6060 "MONITOR_INTERVAL" : 60 , # seconds between passes in continuous mode
6161 "MONITOR_JITTER" : 5 , # random jitter to avoid simultaneous CStore writes
6262
63+ # Dune sand walking - random delays between operations to evade IDS detection
64+ "SCAN_MIN_RND_DELAY" : 0.0 , # minimum delay in seconds (0 = disabled)
65+ "SCAN_MAX_RND_DELAY" : 0.0 , # maximum delay in seconds (0 = disabled)
66+
6367 'VALIDATION_RULES' : {
6468 ** BasePlugin .CONFIG ['VALIDATION_RULES' ],
6569 },
@@ -301,16 +305,18 @@ def _ensure_worker_entry(self, job_id, job_spec):
301305
302306
303307 def _launch_job (
304- self ,
308+ self ,
305309 job_id ,
306310 target ,
307- start_port ,
308- end_port ,
311+ start_port ,
312+ end_port ,
309313 network_worker_address ,
310314 nr_local_workers = 4 ,
311315 exceptions = None ,
312316 port_order = None ,
313317 excluded_features = None ,
318+ scan_min_delay = 0.0 ,
319+ scan_max_delay = 0.0 ,
314320 ):
315321 """
316322 Launch local worker threads for a job by splitting the port range.
@@ -335,6 +341,10 @@ def _launch_job(
335341 Port scanning order: "SHUFFLE" or "SEQUENTIAL".
336342 excluded_features : list[str], optional
337343 List of feature names to exclude from scanning.
344+ scan_min_delay: float, optional
345+ Minimum random delay between scan operations.
346+ scan_max_delay: float, optional
347+ Maximum random delay between scan operations.
338348
339349 Returns
340350 -------
@@ -387,12 +397,14 @@ def _launch_job(
387397 batch_job = PentestLocalWorker (
388398 owner = self ,
389399 local_id_prefix = str (i + 1 ),
390- target = target ,
400+ target = target ,
391401 job_id = job_id ,
392402 initiator = network_worker_address ,
393403 exceptions = exceptions ,
394404 worker_target_ports = batch ,
395405 excluded_features = excluded_features ,
406+ scan_min_delay = scan_min_delay ,
407+ scan_max_delay = scan_max_delay ,
396408 )
397409 batch_job .start ()
398410 local_jobs [batch_job .local_worker_id ] = batch_job
@@ -476,6 +488,8 @@ def _maybe_launch_jobs(self, nr_local_workers=None):
476488 self .P ("No end port specified, defaulting to 65535." )
477489 end_port = 65535
478490 exceptions = job_specs .get ("exceptions" , [])
491+ scan_min_delay = job_specs .get ("scan_min_delay" , self .cfg_scan_min_rnd_delay )
492+ scan_max_delay = job_specs .get ("scan_max_delay" , self .cfg_scan_max_rnd_delay )
479493 workers_requested = nr_local_workers if nr_local_workers is not None else self .cfg_nr_local_workers
480494 self .P ("Using {} local workers for job {}" .format (workers_requested , job_id ))
481495 try :
@@ -489,6 +503,8 @@ def _maybe_launch_jobs(self, nr_local_workers=None):
489503 exceptions = exceptions ,
490504 port_order = port_order ,
491505 excluded_features = excluded_features ,
506+ scan_min_delay = scan_min_delay ,
507+ scan_max_delay = scan_max_delay ,
492508 )
493509 except ValueError as exc :
494510 self .P (f"Skipping job { job_id } : { exc } " , color = 'r' )
@@ -908,6 +924,8 @@ def launch_test(
908924 excluded_features : list [str ] = None ,
909925 run_mode : str = "" ,
910926 monitor_interval : int = 0 ,
927+ scan_min_delay : float = 0.0 ,
928+ scan_max_delay : float = 0.0 ,
911929 ):
912930 """
913931 Start a pentest on the specified target.
@@ -937,6 +955,10 @@ def launch_test(
937955 repeated scans at monitor_interval.
938956 monitor_interval: int, optional
939957 Seconds between passes in CONTINUOUS_MONITORING mode (0 = use config).
958+ scan_min_delay: float, optional
959+ Minimum random delay between scan operations (Dune sand walking).
960+ scan_max_delay: float, optional
961+ Maximum random delay between scan operations (Dune sand walking).
940962
941963 Returns
942964 -------
@@ -996,6 +1018,15 @@ def launch_test(
9961018 if monitor_interval <= 0 :
9971019 monitor_interval = self .cfg_monitor_interval
9981020
1021+ # Validate scan delays (Dune sand walking)
1022+ if scan_min_delay <= 0 :
1023+ scan_min_delay = self .cfg_scan_min_rnd_delay
1024+ if scan_max_delay <= 0 :
1025+ scan_max_delay = self .cfg_scan_max_rnd_delay
1026+ # Ensure min <= max
1027+ if scan_min_delay > scan_max_delay :
1028+ scan_min_delay , scan_max_delay = scan_max_delay , scan_min_delay
1029+
9991030 chainstore_peers = self .cfg_chainstore_peers
10001031 num_workers = len (chainstore_peers )
10011032
@@ -1062,6 +1093,9 @@ def launch_test(
10621093 "job_pass" : 1 ,
10631094 "next_pass_at" : None ,
10641095 "pass_history" : [],
1096+ # Dune sand walking
1097+ "scan_min_delay" : scan_min_delay ,
1098+ "scan_max_delay" : scan_max_delay ,
10651099 }
10661100 self .chainstore_hset (
10671101 hkey = self .cfg_instance_id ,
0 commit comments