From cf35a1c68b95ccf012aad79309d51946b4359b1a Mon Sep 17 00:00:00 2001 From: Olivier Cervello Date: Tue, 13 May 2025 13:21:03 -0400 Subject: [PATCH 1/2] feat: improve format string for dynamic template opts --- .../configs/workflows/subdomain_recon.yaml | 40 ++++++++++++------- secator/runners/_helpers.py | 20 ++++++---- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/secator/configs/workflows/subdomain_recon.yaml b/secator/configs/workflows/subdomain_recon.yaml index a8e5d8ea1..42356afb4 100644 --- a/secator/configs/workflows/subdomain_recon.yaml +++ b/secator/configs/workflows/subdomain_recon.yaml @@ -6,20 +6,30 @@ tags: [recon, dns, takeovers] input_types: - host tasks: - subfinder: - description: List subdomains (passive) - # TODO: add subdomain bruteforcers - # gobuster: - # input: vhost - # domain_: - # - target.name - # wordlist: combined_subdomains - # gobuster: - # input: dns - # domain_: - # - target.name - # wordlist: combined_subdomains - _group: + _group/1: + subfinder: + description: List subdomains (passive) + # dnsx: + # description: Bruteforce subdomains (DNS) + # subdomains_only: True + # wordlist: combined_subdomains + ffuf: + description: Bruteforce subdomains (Host header) + header: "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36" + fuzz_host_header: True + auto_calibration: True + wordlist: combined_subdomains + targets_: + - type: target + field: 'http://{name}' + - type: target + field: 'https://{name}' + _group/2: + dnsx: + description: Check if subdomains are alive (DNS) + subdomains_only: True + targets_: + - subdomain.host nuclei: description: Check for subdomain takeovers targets_: @@ -30,4 +40,4 @@ tasks: description: Run HTTP probes on subdomains targets_: - target.name - - subdomain.host \ No newline at end of file + - subdomain.host diff --git a/secator/runners/_helpers.py b/secator/runners/_helpers.py index 7b14e1ed4..527155504 100644 --- a/secator/runners/_helpers.py +++ b/secator/runners/_helpers.py @@ -79,16 +79,22 @@ def process_extractor(results, extractor, ctx={}): _field = extractor.get('field') _condition = extractor.get('condition', 'True') else: - _type, _field = tuple(extractor.split('.')) - _condition = 'True' - items = [ + parts = tuple(extractor.split('.')) + if len(parts) == 2: + _type = parts[0] + _field = parts[1] + _condition = 'True' + else: + return results + results = [ item for item in results if item._type == _type and eval(_condition) ] if _field: - _field = '{' + _field + '}' if not _field.startswith('{') else _field - items = [_field.format(**item.toDict()) for item in items] - debug('after extract', obj={'items': items}, sub='extractor') - return items + already_formatted = '{' in _field and '}' in _field + _field = '{' + _field + '}' if not already_formatted else _field + results = [_field.format(**item.toDict()) for item in results] + debug('after extract', obj={'results': results}, sub='extractor') + return results def get_task_folder_id(path): From 63024746e4b296f9d165bdc633a5a5b527f71b52 Mon Sep 17 00:00:00 2001 From: Olivier Cervello Date: Tue, 13 May 2025 13:27:12 -0400 Subject: [PATCH 2/2] update --- secator/runners/command.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/secator/runners/command.py b/secator/runners/command.py index edfaabc33..55678fb5a 100644 --- a/secator/runners/command.py +++ b/secator/runners/command.py @@ -105,6 +105,9 @@ class Command(Runner): # Return code return_code = -1 + # Exit ok + exit_ok = False + # Output output = '' @@ -553,12 +556,14 @@ def handle_file_not_found(self, exc): error._uuid = str(uuid.uuid4()) yield error - def stop_process(self): + def stop_process(self, exit_ok=False): """Sends SIGINT to running process, if any.""" if not self.process: return self.debug(f'Sending SIGINT to process {self.process.pid}.', sub='error') self.process.send_signal(signal.SIGINT) + if exit_ok: + self.exit_ok = True def stats(self): """Gather stats about the current running process, if any.""" @@ -674,7 +679,7 @@ def _wait_for_end(self): for line in self.process.stdout.readlines(): yield from self.process_line(line) self.process.wait() - self.return_code = self.process.returncode + self.return_code = 0 if self.exit_ok else self.process.returncode self.process.stdout.close() self.return_code = 0 if self.ignore_return_code else self.return_code self.output = self.output.strip() @@ -875,6 +880,8 @@ def _build_cmd(self): if conf.get('requires_sudo', False): self.requires_sudo = True opts_str += ' ' + Command._build_opt_str(opt_conf) + if '{target}' in opts_str: + opts_str = opts_str.replace('{target}', self.inputs[0]) self.cmd_options = opts self.cmd += opts_str