1414import copy
1515import requests
1616import time
17+ from concurrent_executor import ConcurrentExecutor , ExecutionInput
1718logger = logging .getLogger (__name__ )
1819
1920
@@ -423,7 +424,7 @@ def run(self) -> None:
423424 """
424425 Main execution method that orchestrates the workflow.
425426
426- Reads scan configuration, generates payloads, sends requests,
427+ Reads scan configuration, generates payloads, sends requests concurrently ,
427428 and saves results for each test and iteration.
428429 """
429430 logger .info ("Starting vulnerability automation execution" )
@@ -433,38 +434,39 @@ def run(self) -> None:
433434
434435 logger .info (f"Found { len (tests )} test(s) with { iterations } iteration(s) each" )
435436
436- # Process each test
437+ # Phase 1: Collect all payloads for all test/iteration combinations
438+ execution_payloads = []
437439 for test_idx , test in enumerate (tests , 1 ):
438- logger .info (f"Processing test { test_idx } /{ len (tests )} : "
440+ logger .info (f"Preparing test { test_idx } /{ len (tests )} : "
439441 f"language={ test .get ('language' )} , "
440442 f"vuln_id={ test .get ('vuln_id' )} " )
441443
442- # Run iterations for this test
444+ # Generate payloads for all iterations of this test
443445 for iteration in range (1 , iterations + 1 ):
444- logger .info (f"Running iteration { iteration } /{ iterations } " )
445-
446446 try :
447447 # Generate payload
448448 payload , scan_id = self .generate_payload (test , iteration )
449449
450- # Send request
451- result = self .send_request (payload )
452-
453- # Save successful result
454- self .save_result (result , scan_id , iteration , failed = False )
455-
456- logger .info (f"Successfully completed iteration { iteration } "
457- f"for test { test_idx } " )
450+ # Create unique number encoding test_idx and iteration
451+ unique_number = test_idx * 1000 + iteration
458452
453+ execution_payloads .append (
454+ ExecutionInput (
455+ number = unique_number ,
456+ test = test ,
457+ payload = payload ,
458+ request_id = scan_id
459+ )
460+ )
461+ logger .debug (f"Prepared payload for test { test_idx } , iteration { iteration } " )
459462
460463 except Exception as e :
461- logger .error (f"Failed iteration { iteration } for test { test_idx } : { e } " )
464+ logger .error (f"Failed generating payload for test { test_idx } , "
465+ f"iteration { iteration } : { e } " )
462466
463- # Save failed result if we have a scan_id
467+ # Save failed result for payload generation error
464468 try :
465- # Generate scan_id if not already generated
466- if 'scan_id' not in locals ():
467- scan_id = self .generate_scan_id ()
469+ scan_id = self .generate_scan_id ()
468470
469471 # Create error result
470472 error_result = {
@@ -479,6 +481,43 @@ def run(self) -> None:
479481 except Exception as save_error :
480482 logger .error (f"Failed to save error result: { save_error } " )
481483
484+ # Phase 2: Execute all requests concurrently
485+ if execution_payloads :
486+ logger .info (f"Executing { len (execution_payloads )} request(s) concurrently" )
487+ concurrent_executor = ConcurrentExecutor (execution = self , num_of_processes = 2 )
488+ responses = concurrent_executor .run_requests (execution_payloads )
489+
490+ # Phase 3: Process results and save them
491+ for result in responses :
492+ # Extract test_idx and iteration from unique number
493+ test_idx = result .number // 1000
494+ iteration = result .number % 1000
495+
496+ if result .intercepted_error and result .intercepted_error .strip () != "" :
497+ # Request execution failed
498+ logger .error (f"Failed iteration { iteration } for test { test_idx } : "
499+ f"{ result .intercepted_error } " )
500+
501+ # Create error result
502+ error_result = {
503+ 'error' : result .intercepted_error ,
504+ 'scan_id' : result .request_id ,
505+ 'iteration' : iteration ,
506+ 'test' : result .test
507+ }
508+ self .save_result (
509+ error_result , result .request_id , iteration , failed = True
510+ )
511+ else :
512+ # Request succeeded
513+ self .save_result (
514+ result .response , result .request_id , iteration , failed = False
515+ )
516+ logger .info (f"Successfully completed iteration { iteration } "
517+ f"for test { test_idx } " )
518+ else :
519+ logger .warning ("No payloads to execute" )
520+
482521 logger .info ("Vulnerability automation execution completed" )
483522
484523 except FileNotFoundError as e :
0 commit comments