@@ -2553,23 +2553,33 @@ def nuclei_scan(self, urls=[], ctx={}, description=None):
2553
2553
return
2554
2554
2555
2555
if intensity == 'normal' : # reduce number of endpoints to scan
2556
+ if not os .path .exists (input_path ):
2557
+ with open (input_path , 'w' ) as f :
2558
+ f .write ('\n ' .join (urls ))
2559
+
2556
2560
unfurl_filter = str (Path (self .results_dir ) / 'urls_unfurled.txt' )
2561
+
2557
2562
run_command (
2558
2563
f"cat { input_path } | unfurl -u format %s://%d%p |uro > { unfurl_filter } " ,
2559
2564
shell = True ,
2560
2565
history_file = self .history_file ,
2561
2566
scan_id = self .scan_id ,
2562
2567
activity_id = self .activity_id )
2563
2568
run_command (
2564
- f'sort -u { unfurl_filter } -o { unfurl_filter } ' ,
2569
+ f'sort -u { unfurl_filter } -o { unfurl_filter } ' ,
2565
2570
shell = True ,
2566
2571
history_file = self .history_file ,
2567
2572
scan_id = self .scan_id ,
2568
2573
activity_id = self .activity_id )
2574
+
2575
+ if not os .path .exists (unfurl_filter ) or os .path .getsize (unfurl_filter ) == 0 :
2576
+ logger .error (f"Failed to create or empty unfurled URLs file at { unfurl_filter } " )
2577
+ unfurl_filter = input_path
2578
+
2569
2579
input_path = unfurl_filter
2570
2580
2571
2581
# Build templates
2572
- # logger.info('Updating Nuclei templates ...')
2582
+ logger .info ('Updating Nuclei templates ...' )
2573
2583
run_command (
2574
2584
'nuclei -update-templates' ,
2575
2585
shell = True ,
@@ -2588,8 +2598,11 @@ def nuclei_scan(self, urls=[], ctx={}, description=None):
2588
2598
templates .extend (nuclei_templates )
2589
2599
2590
2600
if custom_nuclei_templates :
2591
- custom_nuclei_template_paths = [f'{ str (elem )} .yaml' for elem in custom_nuclei_templates ]
2592
- template = templates .extend (custom_nuclei_template_paths )
2601
+ custom_nuclei_template_paths = [
2602
+ str (Path (NUCLEI_DEFAULT_TEMPLATES_PATH ) / f'{ str (elem )} .yaml' )
2603
+ for elem in custom_nuclei_templates
2604
+ ]
2605
+ templates .extend (custom_nuclei_template_paths )
2593
2606
2594
2607
# Build CMD
2595
2608
cmd = 'nuclei -j'
@@ -2633,7 +2646,6 @@ def nuclei_scan(self, urls=[], ctx={}, description=None):
2633
2646
logger .info ('Vulnerability scan with all severities completed...' )
2634
2647
2635
2648
return None
2636
-
2637
2649
@app .task (name = 'dalfox_xss_scan' , queue = 'main_scan_queue' , base = RengineTask , bind = True )
2638
2650
def dalfox_xss_scan (self , urls = [], ctx = {}, description = None ):
2639
2651
"""XSS Scan using dalfox
@@ -3843,12 +3855,51 @@ def record_exists(model, data, exclude_keys=[]):
3843
3855
Returns:
3844
3856
bool: True if the record exists, False otherwise.
3845
3857
"""
3858
+ def clean_request (request_str ):
3859
+ if not request_str :
3860
+ return request_str
3861
+ request_lines = request_str .split ('\r \n ' )
3862
+ cleaned_lines = [line for line in request_lines if not line .startswith ('User-Agent:' )]
3863
+ return '\r \n ' .join (cleaned_lines )
3846
3864
3847
3865
# Extract the keys that will be used for the lookup
3848
- lookup_fields = {key : data [key ] for key in data if key not in exclude_keys }
3866
+ lookup_fields = data .copy ()
3867
+
3868
+ # Clean the request field if it contains a User-Agent line
3869
+ if 'request' in lookup_fields :
3870
+ lookup_fields ['request' ] = clean_request (lookup_fields ['request' ])
3849
3871
3850
- # Return True if a record exists based on the lookup fields, False otherwise
3851
- return model .objects .filter (** lookup_fields ).exists ()
3872
+ # Remove the fields to exclude
3873
+ lookup_fields = {key : lookup_fields [key ] for key in lookup_fields if key not in exclude_keys }
3874
+
3875
+ # Get all existing records that might match
3876
+ base_query = {key : value for key , value in lookup_fields .items () if key != 'request' }
3877
+ existing_records = model .objects .filter (** base_query )
3878
+
3879
+ if not existing_records .exists ():
3880
+ logger .debug (f"No existing records found with lookup fields: { lookup_fields } " )
3881
+ return False
3882
+
3883
+ # For each existing record, log the differences
3884
+ for record in existing_records :
3885
+ differences = {}
3886
+ for key , value in lookup_fields .items ():
3887
+ existing_value = getattr (record , key )
3888
+ if key == 'request' :
3889
+ existing_value = clean_request (existing_value )
3890
+ if existing_value != value :
3891
+ differences [key ] = {
3892
+ 'existing' : existing_value ,
3893
+ 'new' : value
3894
+ }
3895
+
3896
+ if differences :
3897
+ logger .debug (f"Record { record .id } has differences: { differences } " )
3898
+ else :
3899
+ logger .debug (f"Record { record .id } matches exactly with lookup fields: { lookup_fields } " )
3900
+ return True
3901
+
3902
+ return False
3852
3903
3853
3904
@app .task (name = 'geo_localize' , bind = False , queue = 'geo_localize_queue' )
3854
3905
def geo_localize (host , ip_id = None ):
@@ -4406,31 +4457,32 @@ def run_command(cmd, cwd=None, shell=False, history_file=None, scan_id=None, act
4406
4457
Returns:
4407
4458
tuple: A tuple containing the return code and output of the command.
4408
4459
"""
4409
- logger .info (f"Executing command: { cmd } " )
4460
+ logger .info (f"Starting execution of command: { cmd } " )
4410
4461
command_obj = create_command_object (cmd , scan_id , activity_id )
4411
4462
command = prepare_command (cmd , shell )
4412
4463
logger .debug (f"Prepared run command: { command } " )
4413
-
4414
- process = execute_command (command , shell , cwd )
4415
- output = ''
4416
- for stdout_line in iter (process .stdout .readline , "" ):
4417
- item = stdout_line .strip ()
4418
- output += '\n ' + item
4419
- logger .debug (item )
4420
4464
4421
- process . stdout . close ( )
4422
- process .wait ()
4465
+ process = execute_command ( command , shell , cwd )
4466
+ output , error_output = process .communicate ()
4423
4467
return_code = process .returncode
4424
- command_obj .output = output
4468
+
4469
+ if output :
4470
+ output = re .sub (r'\x1b\[[0-9;]*[mGKH]' , '' , output ) if remove_ansi_sequence else output
4471
+
4472
+ if return_code != 0 :
4473
+ error_msg = f"Command failed with exit code { return_code } "
4474
+ if error_output :
4475
+ error_msg += f"\n Error output:\n { error_output } "
4476
+ logger .error (error_msg )
4477
+
4478
+ command_obj .output = output or None
4479
+ command_obj .error_output = error_output or None
4425
4480
command_obj .return_code = return_code
4426
4481
command_obj .save ()
4427
-
4482
+
4428
4483
if history_file :
4429
4484
write_history (history_file , cmd , return_code , output )
4430
4485
4431
- if remove_ansi_sequence :
4432
- output = remove_ansi_escape_sequences (output )
4433
-
4434
4486
return return_code , output
4435
4487
4436
4488
def stream_command (cmd , cwd = None , shell = False , history_file = None , encoding = 'utf-8' , scan_id = None , activity_id = None , trunc_char = None ):
@@ -4457,20 +4509,41 @@ def stream_command(cmd, cwd=None, shell=False, history_file=None, encoding='utf-
4457
4509
4458
4510
process = execute_command (command , shell , cwd )
4459
4511
output = ""
4512
+ error_output = ""
4460
4513
4461
- for line in iter (process .stdout .readline , b'' ):
4462
- if not line :
4514
+ while True :
4515
+ stdout_data = process .stdout .readline ()
4516
+ stderr_data = process .stderr .readline ()
4517
+
4518
+ if not stdout_data and not stderr_data and process .poll () is not None :
4463
4519
break
4464
- item = process_line (line , trunc_char )
4465
- yield item
4466
- output += line
4467
- command_obj .output = output
4468
- command_obj .save ()
4520
+
4521
+ if stdout_data :
4522
+ output += stdout_data
4523
+ try :
4524
+ item = process_line (stdout_data , trunc_char )
4525
+ if item :
4526
+ yield item
4527
+ except Exception as e :
4528
+ logger .error (f"Error processing output line: { e } " )
4529
+
4530
+ if stderr_data :
4531
+ error_output += stderr_data
4469
4532
4470
4533
process .wait ()
4471
4534
return_code = process .returncode
4535
+
4536
+ if return_code != 0 :
4537
+ error_msg = f"Command failed with exit code { return_code } "
4538
+ if error_output :
4539
+ error_msg += f"\n Error output:\n { error_output } "
4540
+ logger .error (error_msg )
4541
+
4542
+ command_obj .output = output or None
4543
+ command_obj .error_output = error_output or None
4472
4544
command_obj .return_code = return_code
4473
4545
command_obj .save ()
4546
+
4474
4547
logger .debug (f'Command returned exit code: { return_code } ' )
4475
4548
4476
4549
if history_file :
0 commit comments