secator 0.10.1a12__py3-none-any.whl → 0.15.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of secator might be problematic. Click here for more details.
- secator/celery.py +10 -5
- secator/celery_signals.py +2 -11
- secator/cli.py +309 -69
- secator/config.py +3 -2
- secator/configs/profiles/aggressive.yaml +6 -5
- secator/configs/profiles/default.yaml +6 -7
- secator/configs/profiles/insane.yaml +8 -0
- secator/configs/profiles/paranoid.yaml +8 -0
- secator/configs/profiles/polite.yaml +8 -0
- secator/configs/profiles/sneaky.yaml +8 -0
- secator/configs/profiles/tor.yaml +5 -0
- secator/configs/workflows/host_recon.yaml +11 -2
- secator/configs/workflows/url_dirsearch.yaml +5 -0
- secator/configs/workflows/url_params_fuzz.yaml +25 -0
- secator/configs/workflows/wordpress.yaml +4 -1
- secator/decorators.py +64 -34
- secator/definitions.py +8 -4
- secator/installer.py +84 -49
- secator/output_types/__init__.py +2 -1
- secator/output_types/certificate.py +78 -0
- secator/output_types/stat.py +3 -0
- secator/output_types/user_account.py +1 -1
- secator/report.py +2 -2
- secator/rich.py +1 -1
- secator/runners/_base.py +50 -11
- secator/runners/_helpers.py +15 -3
- secator/runners/command.py +85 -21
- secator/runners/scan.py +6 -3
- secator/runners/task.py +1 -0
- secator/runners/workflow.py +22 -4
- secator/tasks/_categories.py +25 -17
- secator/tasks/arjun.py +92 -0
- secator/tasks/bbot.py +33 -4
- secator/tasks/bup.py +4 -2
- secator/tasks/cariddi.py +17 -4
- secator/tasks/dalfox.py +4 -2
- secator/tasks/dirsearch.py +4 -2
- secator/tasks/dnsx.py +5 -2
- secator/tasks/dnsxbrute.py +4 -1
- secator/tasks/feroxbuster.py +5 -2
- secator/tasks/ffuf.py +7 -3
- secator/tasks/fping.py +4 -1
- secator/tasks/gau.py +5 -2
- secator/tasks/gf.py +4 -2
- secator/tasks/gitleaks.py +79 -0
- secator/tasks/gospider.py +5 -2
- secator/tasks/grype.py +5 -2
- secator/tasks/h8mail.py +4 -2
- secator/tasks/httpx.py +6 -3
- secator/tasks/katana.py +6 -3
- secator/tasks/maigret.py +4 -2
- secator/tasks/mapcidr.py +5 -3
- secator/tasks/msfconsole.py +8 -6
- secator/tasks/naabu.py +16 -5
- secator/tasks/nmap.py +31 -29
- secator/tasks/nuclei.py +18 -10
- secator/tasks/searchsploit.py +8 -3
- secator/tasks/subfinder.py +6 -3
- secator/tasks/testssl.py +276 -0
- secator/tasks/trivy.py +98 -0
- secator/tasks/wafw00f.py +85 -0
- secator/tasks/wpprobe.py +96 -0
- secator/tasks/wpscan.py +8 -4
- secator/template.py +61 -67
- secator/utils.py +31 -18
- secator/utils_test.py +34 -10
- {secator-0.10.1a12.dist-info → secator-0.15.1.dist-info}/METADATA +11 -3
- secator-0.15.1.dist-info/RECORD +128 -0
- secator/configs/profiles/stealth.yaml +0 -7
- secator-0.10.1a12.dist-info/RECORD +0 -116
- {secator-0.10.1a12.dist-info → secator-0.15.1.dist-info}/WHEEL +0 -0
- {secator-0.10.1a12.dist-info → secator-0.15.1.dist-info}/entry_points.txt +0 -0
- {secator-0.10.1a12.dist-info → secator-0.15.1.dist-info}/licenses/LICENSE +0 -0
secator/tasks/naabu.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from secator.decorators import task
|
|
2
|
-
from secator.definitions import (DELAY, HOST, OPT_NOT_SUPPORTED, PORT, PORTS,
|
|
2
|
+
from secator.definitions import (DELAY, HOST, IP, OPT_NOT_SUPPORTED, PORT, PORTS,
|
|
3
3
|
PROXY, RATE_LIMIT, RETRIES, STATE, THREADS,
|
|
4
4
|
TIMEOUT, TOP_PORTS)
|
|
5
5
|
from secator.output_types import Port
|
|
@@ -10,14 +10,17 @@ from secator.tasks._categories import ReconPort
|
|
|
10
10
|
@task()
|
|
11
11
|
class naabu(ReconPort):
|
|
12
12
|
"""Port scanning tool written in Go."""
|
|
13
|
-
cmd = 'naabu
|
|
13
|
+
cmd = 'naabu'
|
|
14
|
+
tags = ['port', 'scan']
|
|
14
15
|
input_flag = '-host'
|
|
16
|
+
input_types = [HOST, IP]
|
|
15
17
|
file_flag = '-list'
|
|
16
18
|
json_flag = '-json'
|
|
17
19
|
opts = {
|
|
18
20
|
PORTS: {'type': str, 'short': 'p', 'help': 'Ports'},
|
|
19
21
|
TOP_PORTS: {'type': str, 'short': 'tp', 'help': 'Top ports'},
|
|
20
22
|
'scan_type': {'type': str, 'short': 'st', 'help': 'Scan type (SYN (s)/CONNECT(c))'},
|
|
23
|
+
'skip_host_discovery': {'is_flag': True, 'short': 'Pn', 'default': False, 'help': 'Skip host discovery'},
|
|
21
24
|
# 'health_check': {'is_flag': True, 'short': 'hc', 'help': 'Health check'}
|
|
22
25
|
}
|
|
23
26
|
opt_key_map = {
|
|
@@ -47,7 +50,8 @@ class naabu(ReconPort):
|
|
|
47
50
|
}
|
|
48
51
|
}
|
|
49
52
|
output_types = [Port]
|
|
50
|
-
|
|
53
|
+
install_version = 'v2.3.3'
|
|
54
|
+
install_cmd = 'go install -v github.com/projectdiscovery/naabu/v2/cmd/naabu@[install_version]'
|
|
51
55
|
install_github_handle = 'projectdiscovery/naabu'
|
|
52
56
|
install_pre = {'apt': ['libpcap-dev'], 'apk': ['libpcap-dev', 'libc6-compat'], 'pacman|brew': ['libpcap']}
|
|
53
57
|
install_post = {'arch|alpine': 'sudo ln -sf /usr/lib/libpcap.so /usr/lib/libpcap.so.0.8'}
|
|
@@ -62,8 +66,15 @@ class naabu(ReconPort):
|
|
|
62
66
|
if input == 'localhost':
|
|
63
67
|
self.inputs[ix] = '127.0.0.1'
|
|
64
68
|
|
|
69
|
+
@staticmethod
|
|
70
|
+
def on_cmd(self):
|
|
71
|
+
scan_type = self.get_opt_value('scan_type')
|
|
72
|
+
if scan_type == 's':
|
|
73
|
+
self.requires_sudo = True
|
|
74
|
+
|
|
65
75
|
@staticmethod
|
|
66
76
|
def on_item(self, item):
|
|
67
|
-
if item
|
|
68
|
-
item.host
|
|
77
|
+
if isinstance(item, Port):
|
|
78
|
+
if item.host == '127.0.0.1':
|
|
79
|
+
item.host = 'localhost'
|
|
69
80
|
return item
|
secator/tasks/nmap.py
CHANGED
|
@@ -24,7 +24,9 @@ logger = logging.getLogger(__name__)
|
|
|
24
24
|
class nmap(VulnMulti):
|
|
25
25
|
"""Network Mapper is a free and open source utility for network discovery and security auditing."""
|
|
26
26
|
cmd = 'nmap'
|
|
27
|
+
tags = ['port', 'scan']
|
|
27
28
|
input_flag = None
|
|
29
|
+
input_types = [HOST, IP]
|
|
28
30
|
input_chunk_size = 1
|
|
29
31
|
file_flag = '-iL'
|
|
30
32
|
opt_prefix = '--'
|
|
@@ -36,7 +38,7 @@ class nmap(VulnMulti):
|
|
|
36
38
|
|
|
37
39
|
# Script scanning
|
|
38
40
|
SCRIPT: {'type': str, 'default': None, 'help': 'NSE scripts'},
|
|
39
|
-
'script_args': {'type': str, 'default': None, 'help': 'NSE script arguments (n1=v1,n2=v2,...)'},
|
|
41
|
+
'script_args': {'type': str, 'short': 'sargs', 'default': None, 'help': 'NSE script arguments (n1=v1,n2=v2,...)'},
|
|
40
42
|
|
|
41
43
|
# Host discovery
|
|
42
44
|
'skip_host_discovery': {'is_flag': True, 'short': 'Pn', 'default': False, 'help': 'Skip host discovery (no ping)'},
|
|
@@ -44,42 +46,45 @@ class nmap(VulnMulti):
|
|
|
44
46
|
# Service and version detection
|
|
45
47
|
'version_detection': {'is_flag': True, 'short': 'sV', 'default': False, 'help': 'Enable version detection (slow)'},
|
|
46
48
|
'detect_all': {'is_flag': True, 'short': 'A', 'default': False, 'help': 'Enable OS detection, version detection, script scanning, and traceroute on open ports'}, # noqa: E501
|
|
47
|
-
'detect_os': {'is_flag': True, 'short': 'O', 'default': False, 'help': 'Enable OS detection'},
|
|
49
|
+
'detect_os': {'is_flag': True, 'short': 'O', 'default': False, 'help': 'Enable OS detection', 'requires_sudo': True},
|
|
48
50
|
|
|
49
51
|
# Scan techniques
|
|
50
|
-
'tcp_syn_stealth': {'is_flag': True, 'short': 'sS', 'default': False, 'help': 'TCP SYN Stealth'},
|
|
52
|
+
'tcp_syn_stealth': {'is_flag': True, 'short': 'sS', 'default': False, 'help': 'TCP SYN Stealth', 'requires_sudo': True}, # noqa: E501
|
|
51
53
|
'tcp_connect': {'is_flag': True, 'short': 'sT', 'default': False, 'help': 'TCP Connect scan'},
|
|
52
|
-
'udp_scan': {'is_flag': True, 'short': 'sU', 'default': False, 'help': 'UDP scan'},
|
|
53
|
-
'tcp_null_scan': {'is_flag': True, 'short': 'sN', 'default': False, 'help': 'TCP Null scan'},
|
|
54
|
-
'tcp_fin_scan': {'is_flag': True, 'short': 'sF', 'default': False, 'help': 'TCP FIN scan'},
|
|
55
|
-
'tcp_xmas_scan': {'is_flag': True, 'short': 'sX', 'default': False, 'help': 'TCP Xmas scan'},
|
|
56
|
-
'tcp_ack_scan': {'is_flag': True, 'short': 'sA', 'default': False, 'help': 'TCP ACK scan'},
|
|
57
|
-
'tcp_window_scan': {'is_flag': True, 'short': 'sW', 'default': False, 'help': 'TCP Window scan'},
|
|
58
|
-
'tcp_maimon_scan': {'is_flag': True, 'short': 'sM', 'default': False, 'help': 'TCP Maimon scan'},
|
|
59
|
-
'sctp_init_scan': {'is_flag': True, 'short': 'sY', 'default': False, 'help': 'SCTP Init scan'},
|
|
60
|
-
'sctp_cookie_echo_scan': {'is_flag': True, 'short': 'sZ', 'default': False, 'help': 'SCTP Cookie Echo scan'},
|
|
54
|
+
'udp_scan': {'is_flag': True, 'short': 'sU', 'default': False, 'help': 'UDP scan', 'requires_sudo': True},
|
|
55
|
+
'tcp_null_scan': {'is_flag': True, 'short': 'sN', 'default': False, 'help': 'TCP Null scan', 'requires_sudo': True},
|
|
56
|
+
'tcp_fin_scan': {'is_flag': True, 'short': 'sF', 'default': False, 'help': 'TCP FIN scan', 'requires_sudo': True},
|
|
57
|
+
'tcp_xmas_scan': {'is_flag': True, 'short': 'sX', 'default': False, 'help': 'TCP Xmas scan', 'requires_sudo': True},
|
|
58
|
+
'tcp_ack_scan': {'is_flag': True, 'short': 'sA', 'default': False, 'help': 'TCP ACK scan', 'requires_sudo': True},
|
|
59
|
+
'tcp_window_scan': {'is_flag': True, 'short': 'sW', 'default': False, 'help': 'TCP Window scan', 'requires_sudo': True}, # noqa: E501
|
|
60
|
+
'tcp_maimon_scan': {'is_flag': True, 'short': 'sM', 'default': False, 'help': 'TCP Maimon scan', 'requires_sudo': True}, # noqa: E501
|
|
61
|
+
'sctp_init_scan': {'is_flag': True, 'short': 'sY', 'default': False, 'help': 'SCTP Init scan', 'requires_sudo': True},
|
|
62
|
+
'sctp_cookie_echo_scan': {'is_flag': True, 'short': 'sZ', 'default': False, 'help': 'SCTP Cookie Echo scan', 'requires_sudo': True}, # noqa: E501
|
|
61
63
|
'ping_scan': {'is_flag': True, 'short': 'sn', 'default': False, 'help': 'Ping scan (disable port scan)'},
|
|
62
|
-
'ip_protocol_scan': {'type': str, 'short': 'sO', 'default': None, 'help': 'IP protocol scan'},
|
|
64
|
+
'ip_protocol_scan': {'type': str, 'short': 'sO', 'default': None, 'help': 'IP protocol scan', 'requires_sudo': True},
|
|
63
65
|
'script_scan': {'is_flag': True, 'short': 'sC', 'default': False, 'help': 'Enable default scanning'},
|
|
64
|
-
'zombie_host': {'type': str, 'short': 'sI', 'default': None, 'help': 'Use a zombie host for idle scan'},
|
|
66
|
+
'zombie_host': {'type': str, 'short': 'sI', 'default': None, 'help': 'Use a zombie host for idle scan', 'requires_sudo': True}, # noqa: E501
|
|
65
67
|
'ftp_relay_host': {'type': str, 'short': 'sB', 'default': None, 'help': 'FTP bounce scan relay host'},
|
|
66
68
|
|
|
67
69
|
# Firewall / IDS evasion and spoofing
|
|
68
70
|
'spoof_source_port': {'type': int, 'short': 'g', 'default': None, 'help': 'Send packets from a specific port'},
|
|
69
71
|
'spoof_source_ip': {'type': str, 'short': 'S', 'default': None, 'help': 'Spoof source IP address'},
|
|
70
72
|
'spoof_source_mac': {'type': str, 'short': 'spoofmac', 'default': None, 'help': 'Spoof MAC address'},
|
|
71
|
-
'fragment': {'is_flag': True, 'short': 'fragment', 'default': False, 'help': 'Fragment packets'},
|
|
72
|
-
'mtu': {'type': int, 'short': 'mtu', 'default': None, 'help': 'Fragment packets with given MTU'},
|
|
73
|
-
'ttl': {'type': int, 'short': 'ttl', 'default': None, 'help': 'Set TTL'},
|
|
74
|
-
'badsum': {'is_flag': True, 'short': 'badsum', 'default': False, 'help': 'Create a bad checksum in the TCP header'},
|
|
73
|
+
'fragment': {'is_flag': True, 'short': 'fragment', 'default': False, 'help': 'Fragment packets', 'requires_sudo': True}, # noqa: E501
|
|
74
|
+
'mtu': {'type': int, 'short': 'mtu', 'default': None, 'help': 'Fragment packets with given MTU', 'requires_sudo': True}, # noqa: E501
|
|
75
|
+
'ttl': {'type': int, 'short': 'ttl', 'default': None, 'help': 'Set TTL', 'requires_sudo': True},
|
|
76
|
+
'badsum': {'is_flag': True, 'short': 'badsum', 'default': False, 'help': 'Create a bad checksum in the TCP header', 'requires_sudo': True}, # noqa: E501
|
|
75
77
|
'ipv6': {'is_flag': True, 'short': 'ipv6', 'default': False, 'help': 'Enable IPv6 scanning'},
|
|
76
78
|
|
|
77
79
|
# Host discovery
|
|
78
|
-
'traceroute': {'is_flag': True, 'short': 'traceroute', 'default': False, 'help': 'Traceroute'},
|
|
79
|
-
'disable_arp_ping': {'is_flag': True, 'short': '
|
|
80
|
+
'traceroute': {'is_flag': True, 'short': 'traceroute', 'default': False, 'help': 'Traceroute', 'requires_sudo': True},
|
|
81
|
+
'disable_arp_ping': {'is_flag': True, 'short': 'dap', 'default': False, 'help': 'Disable ARP ping'},
|
|
80
82
|
|
|
81
83
|
# Misc
|
|
82
|
-
'output_path': {'type': str, 'short': 'oX', 'default': None, 'help': 'Output XML file path'},
|
|
84
|
+
'output_path': {'type': str, 'short': 'oX', 'default': None, 'help': 'Output XML file path', 'internal': True, 'display': False}, # noqa: E501
|
|
85
|
+
'debug': {'is_flag': True, 'short': 'd', 'default': False, 'help': 'Enable debug mode'},
|
|
86
|
+
'verbose': {'is_flag': True, 'short': 'v', 'default': False, 'help': 'Enable verbose mode'},
|
|
87
|
+
'timing': {'type': int, 'short': 'T', 'default': None, 'help': 'Timing template (0: paranoid, 1: sneaky, 2: polite, 3: normal, 4: aggressive, 5: insane)'}, # noqa: E501
|
|
83
88
|
}
|
|
84
89
|
opt_key_map = {
|
|
85
90
|
HEADER: OPT_NOT_SUPPORTED,
|
|
@@ -117,7 +122,7 @@ class nmap(VulnMulti):
|
|
|
117
122
|
'spoof_source_port': '-g',
|
|
118
123
|
'spoof_source_ip': '-S',
|
|
119
124
|
'spoof_source_mac': '--spoof-mac',
|
|
120
|
-
'
|
|
125
|
+
'fragment': '-f',
|
|
121
126
|
'mtu': '--mtu',
|
|
122
127
|
'ttl': '--ttl',
|
|
123
128
|
'badsum': '--badsum',
|
|
@@ -144,20 +149,17 @@ class nmap(VulnMulti):
|
|
|
144
149
|
profile = 'io'
|
|
145
150
|
|
|
146
151
|
@staticmethod
|
|
147
|
-
def
|
|
152
|
+
def on_cmd(self):
|
|
148
153
|
output_path = self.get_opt_value(OUTPUT_PATH)
|
|
149
154
|
if not output_path:
|
|
150
155
|
output_path = f'{self.reports_folder}/.outputs/{self.unique_name}.xml'
|
|
151
156
|
self.output_path = output_path
|
|
152
157
|
self.cmd += f' -oX {self.output_path}'
|
|
153
|
-
tcp_syn_stealth = self.
|
|
154
|
-
tcp_connect = self.
|
|
155
|
-
udp_scan = self.get_opt_value('udp_scan')
|
|
156
|
-
if tcp_syn_stealth or udp_scan:
|
|
157
|
-
self.cmd = f'sudo {self.cmd}'
|
|
158
|
+
tcp_syn_stealth = self.cmd_options.get('tcp_syn_stealth')
|
|
159
|
+
tcp_connect = self.cmd_options.get('tcp_connect')
|
|
158
160
|
if tcp_connect and tcp_syn_stealth:
|
|
159
161
|
self._print(
|
|
160
|
-
'Options -sT (SYN stealth scan) and -sS (CONNECT scan) are conflicting. Keeping only -
|
|
162
|
+
'Options -sT (SYN stealth scan) and -sS (CONNECT scan) are conflicting. Keeping only -sS.',
|
|
161
163
|
'bold gold3')
|
|
162
164
|
self.cmd = self.cmd.replace('-sT ', '')
|
|
163
165
|
|
secator/tasks/nuclei.py
CHANGED
|
@@ -4,7 +4,7 @@ from secator.definitions import (CONFIDENCE, CVSS_SCORE, DELAY, DESCRIPTION,
|
|
|
4
4
|
MATCHED_AT, NAME, OPT_NOT_SUPPORTED, PERCENT,
|
|
5
5
|
PROVIDER, PROXY, RATE_LIMIT, REFERENCES,
|
|
6
6
|
RETRIES, SEVERITY, TAGS, THREADS, TIMEOUT,
|
|
7
|
-
USER_AGENT)
|
|
7
|
+
USER_AGENT, HOST, URL)
|
|
8
8
|
from secator.output_types import Progress, Vulnerability
|
|
9
9
|
from secator.serializers import JSONSerializer
|
|
10
10
|
from secator.tasks._categories import VulnMulti
|
|
@@ -14,21 +14,28 @@ from secator.tasks._categories import VulnMulti
|
|
|
14
14
|
class nuclei(VulnMulti):
|
|
15
15
|
"""Fast and customisable vulnerability scanner based on simple YAML based DSL."""
|
|
16
16
|
cmd = 'nuclei'
|
|
17
|
+
tags = ['vuln', 'scan']
|
|
18
|
+
input_types = [HOST, IP, URL]
|
|
17
19
|
file_flag = '-l'
|
|
18
20
|
input_flag = '-u'
|
|
19
21
|
json_flag = '-jsonl'
|
|
20
22
|
opts = {
|
|
21
|
-
'
|
|
22
|
-
'tags': {'type': str, 'help': 'Tags'},
|
|
23
|
-
'exclude_tags': {'type': str, 'short': 'etags', 'help': 'Exclude tags'},
|
|
24
|
-
'exclude_severity': {'type': str, 'short': 'es', 'help': 'Exclude severity'},
|
|
25
|
-
'template_id': {'type': str, 'short': 'tid', 'help': 'Template id'},
|
|
23
|
+
'bulk_size': {'type': int, 'short': 'bs', 'help': 'Maximum number of hosts to be analyzed in parallel per template'}, # noqa: E501
|
|
26
24
|
'debug': {'type': str, 'help': 'Debug mode'},
|
|
25
|
+
'exclude_severity': {'type': str, 'short': 'es', 'help': 'Exclude severity'},
|
|
26
|
+
'exclude_tags': {'type': str, 'short': 'etags', 'help': 'Exclude tags'},
|
|
27
|
+
'input_mode': {'type': str, 'short': 'im', 'help': 'Mode of input file (list, burp, jsonl, yaml, openapi, swagger)'},
|
|
28
|
+
'hang_monitor': {'is_flag': True, 'short': 'hm', 'default': True, 'help': 'Enable nuclei hang monitoring'},
|
|
29
|
+
'headless_bulk_size': {'type': int, 'short': 'hbs', 'help': 'Maximum number of headless hosts to be analzyed in parallel per template'}, # noqa: E501
|
|
30
|
+
'new_templates': {'type': str, 'short': 'nt', 'help': 'Run only new templates added in latest nuclei-templates release'}, # noqa: E501
|
|
31
|
+
'automatic_scan': {'is_flag': True, 'short': 'as', 'help': 'Automatic web scan using wappalyzer technology detection to tags mapping'}, # noqa: E501
|
|
32
|
+
'omit_raw': {'is_flag': True, 'short': 'or', 'default': True, 'help': 'Omit requests/response pairs in the JSON, JSONL, and Markdown outputs (for findings only)'}, # noqa: E501
|
|
27
33
|
'stats': {'is_flag': True, 'short': 'stats', 'default': True, 'help': 'Display statistics about the running scan'},
|
|
28
34
|
'stats_json': {'is_flag': True, 'short': 'sj', 'default': True, 'help': 'Display statistics in JSONL(ines) format'},
|
|
29
|
-
'stats_interval': {'type': str, 'short': 'si', '
|
|
30
|
-
'
|
|
31
|
-
'
|
|
35
|
+
'stats_interval': {'type': str, 'short': 'si', 'help': 'Number of seconds to wait between showing a statistics update'}, # noqa: E501
|
|
36
|
+
'tags': {'type': str, 'help': 'Tags'},
|
|
37
|
+
'templates': {'type': str, 'short': 't', 'help': 'Templates'},
|
|
38
|
+
'template_id': {'type': str, 'short': 'tid', 'help': 'Template id'},
|
|
32
39
|
}
|
|
33
40
|
opt_key_map = {
|
|
34
41
|
HEADER: 'header',
|
|
@@ -76,7 +83,8 @@ class nuclei(VulnMulti):
|
|
|
76
83
|
install_pre = {
|
|
77
84
|
'*': ['git']
|
|
78
85
|
}
|
|
79
|
-
|
|
86
|
+
install_version = 'v3.4.2'
|
|
87
|
+
install_cmd = 'go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@[install_version]'
|
|
80
88
|
install_github_handle = 'projectdiscovery/nuclei'
|
|
81
89
|
install_post = {
|
|
82
90
|
'*': 'nuclei -ut'
|
secator/tasks/searchsploit.py
CHANGED
|
@@ -3,7 +3,7 @@ import re
|
|
|
3
3
|
from secator.config import CONFIG
|
|
4
4
|
from secator.decorators import task
|
|
5
5
|
from secator.definitions import (CVES, EXTRA_DATA, ID, MATCHED_AT, NAME,
|
|
6
|
-
PROVIDER, REFERENCE, TAGS, OPT_NOT_SUPPORTED)
|
|
6
|
+
PROVIDER, REFERENCE, TAGS, TECHNOLOGY, OPT_NOT_SUPPORTED)
|
|
7
7
|
from secator.output_types import Exploit
|
|
8
8
|
from secator.runners import Command
|
|
9
9
|
from secator.serializers import JSONSerializer
|
|
@@ -16,7 +16,9 @@ SEARCHSPLOIT_TITLE_REGEX = re.compile(r'^((?:[a-zA-Z\-_!\.()]+\d?\s?)+)\.?\s*(.*
|
|
|
16
16
|
class searchsploit(Command):
|
|
17
17
|
"""Exploit searcher based on ExploitDB."""
|
|
18
18
|
cmd = 'searchsploit'
|
|
19
|
+
tags = ['exploit', 'recon']
|
|
19
20
|
input_flag = None
|
|
21
|
+
input_types = [TECHNOLOGY]
|
|
20
22
|
json_flag = '--json'
|
|
21
23
|
version_flag = OPT_NOT_SUPPORTED
|
|
22
24
|
opts = {
|
|
@@ -41,9 +43,10 @@ class searchsploit(Command):
|
|
|
41
43
|
install_pre = {
|
|
42
44
|
'apk': ['ncurses']
|
|
43
45
|
}
|
|
46
|
+
install_version = '2025-04-23'
|
|
44
47
|
install_cmd = (
|
|
45
|
-
f'git clone --depth 1 --single-branch https://gitlab.com/exploit-database/exploitdb.git {CONFIG.dirs.share}/
|
|
46
|
-
f'ln -sf $HOME/.local/share/
|
|
48
|
+
f'git clone --depth 1 --single-branch -b [install_version] https://gitlab.com/exploit-database/exploitdb.git {CONFIG.dirs.share}/exploitdb_[install_version] || true && ' # noqa: E501
|
|
49
|
+
f'ln -sf $HOME/.local/share/exploitdb_[install_version]/searchsploit {CONFIG.dirs.bin}/searchsploit'
|
|
47
50
|
)
|
|
48
51
|
proxychains = False
|
|
49
52
|
proxy_socks5 = False
|
|
@@ -83,6 +86,8 @@ class searchsploit(Command):
|
|
|
83
86
|
|
|
84
87
|
@staticmethod
|
|
85
88
|
def on_item(self, item):
|
|
89
|
+
if not isinstance(item, Exploit):
|
|
90
|
+
return item
|
|
86
91
|
match = SEARCHSPLOIT_TITLE_REGEX.match(item.name)
|
|
87
92
|
# if not match:
|
|
88
93
|
# self._print(f'[bold red]{item.name} ({item.reference}) did not match SEARCHSPLOIT_TITLE_REGEX. Please report this issue.[/]') # noqa: E501
|
secator/tasks/subfinder.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from secator.decorators import task
|
|
2
|
-
from secator.definitions import (DELAY, DOMAIN, OPT_NOT_SUPPORTED, PROXY,
|
|
2
|
+
from secator.definitions import (DELAY, DOMAIN, HOST, OPT_NOT_SUPPORTED, PROXY,
|
|
3
3
|
RATE_LIMIT, RETRIES, THREADS, TIMEOUT)
|
|
4
4
|
from secator.output_types import Subdomain
|
|
5
5
|
from secator.serializers import JSONSerializer
|
|
@@ -9,7 +9,9 @@ from secator.tasks._categories import ReconDns
|
|
|
9
9
|
@task()
|
|
10
10
|
class subfinder(ReconDns):
|
|
11
11
|
"""Fast passive subdomain enumeration tool."""
|
|
12
|
-
cmd = 'subfinder -
|
|
12
|
+
cmd = 'subfinder -cs'
|
|
13
|
+
tags = ['dns', 'recon']
|
|
14
|
+
input_types = [HOST]
|
|
13
15
|
file_flag = '-dL'
|
|
14
16
|
input_flag = '-d'
|
|
15
17
|
json_flag = '-json'
|
|
@@ -31,7 +33,8 @@ class subfinder(ReconDns):
|
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
35
|
output_types = [Subdomain]
|
|
34
|
-
|
|
36
|
+
install_version = 'v2.7.0'
|
|
37
|
+
install_cmd = 'go install -v github.com/projectdiscovery/subfinder/v2/cmd/subfinder@[install_version]'
|
|
35
38
|
install_github_handle = 'projectdiscovery/subfinder'
|
|
36
39
|
proxychains = False
|
|
37
40
|
proxy_http = True
|
secator/tasks/testssl.py
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
|
|
5
|
+
from secator.config import CONFIG
|
|
6
|
+
from secator.decorators import task
|
|
7
|
+
from secator.output_types import Vulnerability, Certificate, Error, Info, Ip, Tag
|
|
8
|
+
from secator.definitions import (PROXY, HOST, USER_AGENT, HEADER, OUTPUT_PATH,
|
|
9
|
+
CERTIFICATE_STATUS_UNKNOWN, CERTIFICATE_STATUS_TRUSTED, CERTIFICATE_STATUS_REVOKED,
|
|
10
|
+
TIMEOUT)
|
|
11
|
+
from secator.tasks._categories import Command, OPTS
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@task()
|
|
15
|
+
class testssl(Command):
|
|
16
|
+
"""SSL/TLS security scanner, including ciphers, protocols and cryptographic flaws."""
|
|
17
|
+
cmd = 'testssl.sh'
|
|
18
|
+
tags = ['dns', 'recon', 'tls']
|
|
19
|
+
input_types = [HOST]
|
|
20
|
+
input_flag = None
|
|
21
|
+
file_flag = '-iL'
|
|
22
|
+
file_eof_newline = True
|
|
23
|
+
version_flag = ''
|
|
24
|
+
opt_prefix = '--'
|
|
25
|
+
opts = {
|
|
26
|
+
'verbose': {'is_flag': True, 'default': False, 'internal': True, 'display': True, 'help': 'Record all SSL/TLS info, not only critical info'}, # noqa: E501
|
|
27
|
+
'parallel': {'is_flag': True, 'default': False, 'help': 'Test multiple hosts in parallel'},
|
|
28
|
+
'warnings': {'type': str, 'default': None, 'help': 'Set to "batch" to stop on errors, and "off" to skip errors and continue'}, # noqa: E501
|
|
29
|
+
'ids_friendly': {'is_flag': True, 'default': False, 'help': 'Avoid IDS blocking by skipping a few vulnerability checks'}, # noqa: E501
|
|
30
|
+
'hints': {'is_flag': True, 'default': False, 'help': 'Additional hints to findings'},
|
|
31
|
+
'server_defaults': {'is_flag': True, 'default': False, 'help': 'Displays the server default picks and certificate info'}, # noqa: E501
|
|
32
|
+
}
|
|
33
|
+
meta_opts = {
|
|
34
|
+
PROXY: OPTS[PROXY],
|
|
35
|
+
USER_AGENT: OPTS[USER_AGENT],
|
|
36
|
+
HEADER: OPTS[HEADER],
|
|
37
|
+
TIMEOUT: OPTS[TIMEOUT],
|
|
38
|
+
}
|
|
39
|
+
opt_key_map = {
|
|
40
|
+
PROXY: 'proxy',
|
|
41
|
+
USER_AGENT: 'user-agent',
|
|
42
|
+
HEADER: 'reqheader',
|
|
43
|
+
TIMEOUT: 'connect-timeout',
|
|
44
|
+
'ipv6': '-6',
|
|
45
|
+
}
|
|
46
|
+
output_types = [Certificate, Vulnerability, Ip, Tag]
|
|
47
|
+
proxy_http = True
|
|
48
|
+
proxychains = False
|
|
49
|
+
proxy_socks5 = False
|
|
50
|
+
profile = 'io'
|
|
51
|
+
install_pre = {
|
|
52
|
+
'apk': ['hexdump', 'coreutils', 'procps'],
|
|
53
|
+
'pacman': ['util-linux'],
|
|
54
|
+
'*': ['bsdmainutils']
|
|
55
|
+
}
|
|
56
|
+
install_version = 'v3.2.0'
|
|
57
|
+
install_cmd = (
|
|
58
|
+
f'git clone --depth 1 --single-branch -b [install_version] https://github.com/drwetter/testssl.sh.git {CONFIG.dirs.share}/testssl.sh_[install_version] || true && ' # noqa: E501
|
|
59
|
+
f'ln -sf {CONFIG.dirs.share}/testssl.sh_[install_version]/testssl.sh {CONFIG.dirs.bin}'
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
@staticmethod
|
|
63
|
+
def on_cmd(self):
|
|
64
|
+
output_path = self.get_opt_value(OUTPUT_PATH)
|
|
65
|
+
if not output_path:
|
|
66
|
+
output_path = f'{self.reports_folder}/.outputs/{self.unique_name}.json'
|
|
67
|
+
self.output_path = output_path
|
|
68
|
+
self.cmd += f' --jsonfile {self.output_path}'
|
|
69
|
+
|
|
70
|
+
# Hack because target needs to be the last argument in testssl.sh
|
|
71
|
+
if len(self.inputs) == 1:
|
|
72
|
+
target = self.inputs[0]
|
|
73
|
+
self.cmd = self.cmd.replace(f' {target}', '')
|
|
74
|
+
self.cmd += f' {target}'
|
|
75
|
+
|
|
76
|
+
@staticmethod
|
|
77
|
+
def on_cmd_done(self):
|
|
78
|
+
if not os.path.exists(self.output_path):
|
|
79
|
+
yield Error(message=f'Could not find JSON results in {self.output_path}')
|
|
80
|
+
return
|
|
81
|
+
yield Info(message=f'JSON results saved to {self.output_path}')
|
|
82
|
+
|
|
83
|
+
verbose = self.get_opt_value('verbose')
|
|
84
|
+
with open(self.output_path, 'r') as f:
|
|
85
|
+
data = json.load(f)
|
|
86
|
+
bad_cyphers = {}
|
|
87
|
+
retrieved_certificates = {}
|
|
88
|
+
ignored_item_ids = ["scanTime", "overall_grade", "DNS_CAArecord"]
|
|
89
|
+
ip_addresses = []
|
|
90
|
+
host_to_ips = {}
|
|
91
|
+
|
|
92
|
+
for item in data:
|
|
93
|
+
host, ip = tuple(item['ip'].split('/'))
|
|
94
|
+
id = item['id']
|
|
95
|
+
# port = item['port']
|
|
96
|
+
finding = item['finding']
|
|
97
|
+
severity = item['severity'].lower()
|
|
98
|
+
cwe = item.get('cwe')
|
|
99
|
+
vuln_tags = ['ssl', 'tls']
|
|
100
|
+
if cwe:
|
|
101
|
+
vuln_tags.append(cwe)
|
|
102
|
+
|
|
103
|
+
# Skip ignored items
|
|
104
|
+
if id.startswith(tuple(ignored_item_ids)):
|
|
105
|
+
continue
|
|
106
|
+
|
|
107
|
+
# Add IP to address pool
|
|
108
|
+
host_to_ips.setdefault(host, []).append(ip)
|
|
109
|
+
if ip not in ip_addresses:
|
|
110
|
+
ip_addresses.append(ip)
|
|
111
|
+
yield Ip(
|
|
112
|
+
host=host,
|
|
113
|
+
ip=ip,
|
|
114
|
+
alive=True
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# Process errors
|
|
118
|
+
if id.startswith("scanProblem"):
|
|
119
|
+
yield Error(message=finding)
|
|
120
|
+
|
|
121
|
+
# Process bad ciphers
|
|
122
|
+
elif id.startswith('cipher-'):
|
|
123
|
+
splited_item = item["finding"].split(" ")
|
|
124
|
+
concerned_protocol = splited_item[0]
|
|
125
|
+
bad_cypher = splited_item[-1]
|
|
126
|
+
bad_cyphers.setdefault(ip, {}).setdefault(concerned_protocol, []).append(bad_cypher) # noqa: E501
|
|
127
|
+
|
|
128
|
+
# Process certificates
|
|
129
|
+
elif id.startswith('cert_') or id.startswith('cert '):
|
|
130
|
+
retrieved_certificates.setdefault(ip, []).append(item)
|
|
131
|
+
|
|
132
|
+
# Process intermediate certificates
|
|
133
|
+
elif id.startswith('intermediate_cert_'):
|
|
134
|
+
# TODO: implement this
|
|
135
|
+
pass
|
|
136
|
+
|
|
137
|
+
# If info or ok, create a tag only if 'verbose' option is set
|
|
138
|
+
elif severity in ['info', 'ok']:
|
|
139
|
+
if not verbose:
|
|
140
|
+
continue
|
|
141
|
+
yield Tag(
|
|
142
|
+
name=f'SSL/TLS [{id}]',
|
|
143
|
+
match=host,
|
|
144
|
+
extra_data={
|
|
145
|
+
'type': id,
|
|
146
|
+
'finding': finding,
|
|
147
|
+
}
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
# Create vulnerability
|
|
151
|
+
else:
|
|
152
|
+
if id in ['TLS1', 'TLS1_1']:
|
|
153
|
+
human_name = f'SSL/TLS deprecated protocol offered: {id}'
|
|
154
|
+
else:
|
|
155
|
+
human_name = f'SSL/TLS {id}: {finding}'
|
|
156
|
+
yield Vulnerability(
|
|
157
|
+
name=human_name,
|
|
158
|
+
matched_at=host,
|
|
159
|
+
ip=ip,
|
|
160
|
+
tags=vuln_tags,
|
|
161
|
+
severity=severity,
|
|
162
|
+
confidence='high',
|
|
163
|
+
extra_data={
|
|
164
|
+
'id': id,
|
|
165
|
+
'finding': finding
|
|
166
|
+
}
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
# Creating vulnerability for the deprecated ciphers
|
|
170
|
+
for ip, protocols in bad_cyphers.items():
|
|
171
|
+
for protocol, cyphers in protocols.items():
|
|
172
|
+
yield Vulnerability(
|
|
173
|
+
name=f'SSL/TLS vulnerability ciphers for {protocol} deprecated',
|
|
174
|
+
matched_at=ip,
|
|
175
|
+
ip=ip,
|
|
176
|
+
confidence='high',
|
|
177
|
+
severity='low',
|
|
178
|
+
extra_data={
|
|
179
|
+
'cyphers': cyphers
|
|
180
|
+
}
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
# Creating certificates for each founded target
|
|
184
|
+
host_to_ips = {k: set(v) for k, v in host_to_ips.items()}
|
|
185
|
+
for ip, certs in retrieved_certificates.items():
|
|
186
|
+
host = [k for k, v in host_to_ips.items() if ip in v][0]
|
|
187
|
+
cert_data = {
|
|
188
|
+
'host': host,
|
|
189
|
+
'ip': ip,
|
|
190
|
+
'fingerprint_sha256': None,
|
|
191
|
+
'subject_cn': None,
|
|
192
|
+
'subject_an': None,
|
|
193
|
+
'not_before': None,
|
|
194
|
+
'not_after': None,
|
|
195
|
+
'issuer_cn': None,
|
|
196
|
+
'self_signed': None,
|
|
197
|
+
'trusted': None,
|
|
198
|
+
'status': None,
|
|
199
|
+
'keysize': None,
|
|
200
|
+
'serial_number': None,
|
|
201
|
+
}
|
|
202
|
+
for cert in certs:
|
|
203
|
+
host = [k for k, v in host_to_ips.items() if ip in v][0]
|
|
204
|
+
id = cert['id']
|
|
205
|
+
finding = cert['finding']
|
|
206
|
+
|
|
207
|
+
if id.startswith('cert_crlDistributionPoints') and finding != '--':
|
|
208
|
+
# TODO not implemented, need to find a certificate that is revoked by CRL
|
|
209
|
+
cert_data['status'] = CERTIFICATE_STATUS_UNKNOWN
|
|
210
|
+
|
|
211
|
+
if id.startswith('cert_ocspRevoked'):
|
|
212
|
+
if finding.startswith('not revoked'):
|
|
213
|
+
cert_data['status'] = CERTIFICATE_STATUS_TRUSTED
|
|
214
|
+
else:
|
|
215
|
+
cert_data['status'] = CERTIFICATE_STATUS_REVOKED
|
|
216
|
+
|
|
217
|
+
if id.startswith('cert_fingerprintSHA256'):
|
|
218
|
+
cert_data['fingerprint_sha256'] = finding
|
|
219
|
+
|
|
220
|
+
if id.startswith('cert_commonName'):
|
|
221
|
+
cert_data['subject_cn'] = finding
|
|
222
|
+
|
|
223
|
+
if id.startswith('cert_subjectAltName'):
|
|
224
|
+
cert_data['subject_an'] = finding.split(" ")
|
|
225
|
+
|
|
226
|
+
if id.startswith('cert_notBefore'):
|
|
227
|
+
cert_data['not_before'] = datetime.strptime(finding, "%Y-%m-%d %H:%M")
|
|
228
|
+
|
|
229
|
+
if id.startswith('cert_notAfter'):
|
|
230
|
+
cert_data['not_after'] = datetime.strptime(finding, "%Y-%m-%d %H:%M")
|
|
231
|
+
|
|
232
|
+
if id.startswith('cert_caIssuers'):
|
|
233
|
+
cert_data['issuer_cn'] = finding
|
|
234
|
+
|
|
235
|
+
if id.startswith('cert_chain_of_trust'):
|
|
236
|
+
cert_data['self_signed'] = 'self signed' in finding
|
|
237
|
+
|
|
238
|
+
if id.startswith('cert_chain_of_trust'):
|
|
239
|
+
cert_data['trusted'] = finding.startswith('passed')
|
|
240
|
+
|
|
241
|
+
if id.startswith('cert_keySize'):
|
|
242
|
+
cert_data['keysize'] = int(finding.split(" ")[1])
|
|
243
|
+
|
|
244
|
+
if id.startswith('cert_serialNumber'):
|
|
245
|
+
cert_data['serial_number'] = finding
|
|
246
|
+
|
|
247
|
+
if id.startswith('cert ') and finding.startswith('-----BEGIN CERTIFICATE-----'):
|
|
248
|
+
cert_data['raw_value'] = finding
|
|
249
|
+
|
|
250
|
+
# For the following attributes commented, it's because at the time of writting it
|
|
251
|
+
# I did not found the value inside the result of testssl
|
|
252
|
+
cert = Certificate(
|
|
253
|
+
**cert_data
|
|
254
|
+
# issuer_dn='',
|
|
255
|
+
# issuer='',
|
|
256
|
+
# TODO: delete the ciphers attribute from certificate outputType
|
|
257
|
+
# ciphers=None,
|
|
258
|
+
# TODO: need to find a way to retrieve the parent certificate,
|
|
259
|
+
# parent_certificate=None,
|
|
260
|
+
)
|
|
261
|
+
yield cert
|
|
262
|
+
if cert.is_expired():
|
|
263
|
+
yield Vulnerability(
|
|
264
|
+
name='SSL certificate expired',
|
|
265
|
+
provider='testssl',
|
|
266
|
+
description='The SSL certificate is expired. This can easily lead to domain takeovers',
|
|
267
|
+
matched_at=host,
|
|
268
|
+
ip=ip,
|
|
269
|
+
tags=['ssl', 'tls'],
|
|
270
|
+
severity='medium',
|
|
271
|
+
confidence='high',
|
|
272
|
+
extra_data={
|
|
273
|
+
'id': id,
|
|
274
|
+
'expiration_date': Certificate.format_date(cert.not_after)
|
|
275
|
+
}
|
|
276
|
+
)
|