secator 0.15.1__py3-none-any.whl → 0.16.0__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.

Files changed (106) hide show
  1. secator/celery.py +40 -24
  2. secator/celery_signals.py +71 -68
  3. secator/celery_utils.py +43 -27
  4. secator/cli.py +520 -280
  5. secator/cli_helper.py +394 -0
  6. secator/click.py +87 -0
  7. secator/config.py +67 -39
  8. secator/configs/profiles/http_headless.yaml +6 -0
  9. secator/configs/profiles/http_record.yaml +6 -0
  10. secator/configs/profiles/tor.yaml +1 -1
  11. secator/configs/scans/domain.yaml +4 -2
  12. secator/configs/scans/host.yaml +1 -1
  13. secator/configs/scans/network.yaml +1 -4
  14. secator/configs/scans/subdomain.yaml +13 -1
  15. secator/configs/scans/url.yaml +1 -2
  16. secator/configs/workflows/cidr_recon.yaml +6 -4
  17. secator/configs/workflows/code_scan.yaml +1 -1
  18. secator/configs/workflows/host_recon.yaml +29 -3
  19. secator/configs/workflows/subdomain_recon.yaml +67 -16
  20. secator/configs/workflows/url_crawl.yaml +44 -15
  21. secator/configs/workflows/url_dirsearch.yaml +4 -4
  22. secator/configs/workflows/url_fuzz.yaml +25 -17
  23. secator/configs/workflows/url_params_fuzz.yaml +7 -0
  24. secator/configs/workflows/url_vuln.yaml +33 -8
  25. secator/configs/workflows/user_hunt.yaml +2 -1
  26. secator/configs/workflows/wordpress.yaml +5 -3
  27. secator/cve.py +718 -0
  28. secator/decorators.py +0 -454
  29. secator/definitions.py +49 -30
  30. secator/exporters/_base.py +2 -2
  31. secator/exporters/console.py +2 -2
  32. secator/exporters/table.py +4 -3
  33. secator/exporters/txt.py +1 -1
  34. secator/hooks/mongodb.py +2 -4
  35. secator/installer.py +77 -49
  36. secator/loader.py +116 -0
  37. secator/output_types/_base.py +3 -0
  38. secator/output_types/certificate.py +63 -63
  39. secator/output_types/error.py +4 -5
  40. secator/output_types/info.py +2 -2
  41. secator/output_types/ip.py +3 -1
  42. secator/output_types/progress.py +5 -9
  43. secator/output_types/state.py +17 -17
  44. secator/output_types/tag.py +3 -0
  45. secator/output_types/target.py +10 -2
  46. secator/output_types/url.py +19 -7
  47. secator/output_types/vulnerability.py +11 -7
  48. secator/output_types/warning.py +2 -2
  49. secator/report.py +27 -15
  50. secator/rich.py +18 -10
  51. secator/runners/_base.py +446 -233
  52. secator/runners/_helpers.py +133 -24
  53. secator/runners/command.py +182 -102
  54. secator/runners/scan.py +33 -5
  55. secator/runners/task.py +13 -7
  56. secator/runners/workflow.py +105 -72
  57. secator/scans/__init__.py +2 -2
  58. secator/serializers/dataclass.py +20 -20
  59. secator/tasks/__init__.py +4 -4
  60. secator/tasks/_categories.py +39 -27
  61. secator/tasks/arjun.py +9 -5
  62. secator/tasks/bbot.py +53 -21
  63. secator/tasks/bup.py +19 -5
  64. secator/tasks/cariddi.py +24 -3
  65. secator/tasks/dalfox.py +26 -7
  66. secator/tasks/dirsearch.py +10 -4
  67. secator/tasks/dnsx.py +70 -25
  68. secator/tasks/feroxbuster.py +11 -3
  69. secator/tasks/ffuf.py +42 -6
  70. secator/tasks/fping.py +20 -8
  71. secator/tasks/gau.py +3 -1
  72. secator/tasks/gf.py +3 -3
  73. secator/tasks/gitleaks.py +2 -2
  74. secator/tasks/gospider.py +7 -1
  75. secator/tasks/grype.py +5 -4
  76. secator/tasks/h8mail.py +2 -1
  77. secator/tasks/httpx.py +18 -5
  78. secator/tasks/katana.py +35 -15
  79. secator/tasks/maigret.py +4 -4
  80. secator/tasks/mapcidr.py +3 -3
  81. secator/tasks/msfconsole.py +4 -4
  82. secator/tasks/naabu.py +2 -2
  83. secator/tasks/nmap.py +12 -14
  84. secator/tasks/nuclei.py +3 -3
  85. secator/tasks/searchsploit.py +4 -5
  86. secator/tasks/subfinder.py +2 -2
  87. secator/tasks/testssl.py +264 -263
  88. secator/tasks/trivy.py +5 -5
  89. secator/tasks/wafw00f.py +21 -3
  90. secator/tasks/wpprobe.py +90 -83
  91. secator/tasks/wpscan.py +6 -5
  92. secator/template.py +218 -104
  93. secator/thread.py +15 -15
  94. secator/tree.py +196 -0
  95. secator/utils.py +131 -123
  96. secator/utils_test.py +60 -19
  97. secator/workflows/__init__.py +2 -2
  98. {secator-0.15.1.dist-info → secator-0.16.0.dist-info}/METADATA +36 -36
  99. secator-0.16.0.dist-info/RECORD +132 -0
  100. secator/configs/profiles/default.yaml +0 -8
  101. secator/configs/workflows/url_nuclei.yaml +0 -11
  102. secator/tasks/dnsxbrute.py +0 -42
  103. secator-0.15.1.dist-info/RECORD +0 -128
  104. {secator-0.15.1.dist-info → secator-0.16.0.dist-info}/WHEEL +0 -0
  105. {secator-0.15.1.dist-info → secator-0.16.0.dist-info}/entry_points.txt +0 -0
  106. {secator-0.15.1.dist-info → secator-0.16.0.dist-info}/licenses/LICENSE +0 -0
secator/tasks/trivy.py CHANGED
@@ -5,8 +5,7 @@ import yaml
5
5
  from secator.config import CONFIG
6
6
  from secator.decorators import task
7
7
  from secator.definitions import (THREADS, OUTPUT_PATH, OPT_NOT_SUPPORTED, HEADER, DELAY, FOLLOW_REDIRECT,
8
- DOCKER_IMAGE, PATH, GIT_REPOSITORY, PROXY, RATE_LIMIT, RETRIES, TIMEOUT,
9
- USER_AGENT)
8
+ PATH, PROXY, RATE_LIMIT, RETRIES, TIMEOUT, USER_AGENT, STRING, URL)
10
9
  from secator.tasks._categories import Vuln
11
10
  from secator.output_types import Vulnerability, Tag, Info, Error
12
11
 
@@ -15,10 +14,12 @@ from secator.output_types import Vulnerability, Tag, Info, Error
15
14
  class trivy(Vuln):
16
15
  """Comprehensive and versatile security scanner."""
17
16
  cmd = 'trivy'
17
+ input_types = [PATH, URL, STRING]
18
+ output_types = [Tag, Vulnerability]
18
19
  tags = ['vuln', 'scan']
19
- input_flag = None
20
- input_types = [DOCKER_IMAGE, PATH, GIT_REPOSITORY]
20
+ input_chunk_size = 1
21
21
  json_flag = '-f json'
22
+ version_flag = '--version'
22
23
  opts = {
23
24
  "mode": {"type": click.Choice(['image', 'fs', 'repo']), 'default': 'image', 'help': 'Trivy mode', 'required': True} # noqa: E501
24
25
  }
@@ -33,7 +34,6 @@ class trivy(Vuln):
33
34
  TIMEOUT: OPT_NOT_SUPPORTED,
34
35
  USER_AGENT: OPT_NOT_SUPPORTED
35
36
  }
36
- output_types = [Tag, Vulnerability]
37
37
  install_version = 'v0.61.1'
38
38
  install_cmd = (
39
39
  'curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh |'
secator/tasks/wafw00f.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import os
2
+ import tempfile
2
3
  import yaml
3
4
 
4
5
  from secator.decorators import task
@@ -12,8 +13,9 @@ from secator.tasks._categories import OPTS
12
13
  class wafw00f(Command):
13
14
  """Web Application Firewall Fingerprinting tool."""
14
15
  cmd = 'wafw00f'
15
- tags = ['waf', 'scan']
16
16
  input_types = [URL]
17
+ output_types = [Tag]
18
+ tags = ['waf', 'scan']
17
19
  input_flag = None
18
20
  file_flag = '-i'
19
21
  json_flag = '-f json'
@@ -30,6 +32,9 @@ class wafw00f(Command):
30
32
  'find_all': {'is_flag': True, 'short': 'ta', 'default': False, 'help': 'Find all WAFs which match the signatures, do not stop testing on the first one'}, # noqa: E501
31
33
  'no_follow_redirects': {'is_flag': True, 'short': 'nfr', 'default': False, 'help': 'Do not follow redirections given by 3xx responses'}, # noqa: E501
32
34
  }
35
+ opt_value_map = {
36
+ HEADER: lambda x: wafw00f.headers_to_file(x)
37
+ }
33
38
  opt_key_map = {
34
39
  HEADER: 'headers',
35
40
  PROXY: 'proxy',
@@ -37,7 +42,6 @@ class wafw00f(Command):
37
42
  'find_all': 'findall',
38
43
  'no_follow_redirects': 'noredirect',
39
44
  }
40
- output_types = [Tag]
41
45
  install_version = 'v2.3.1'
42
46
  install_cmd = 'pipx install git+https://github.com/EnableSecurity/wafw00f.git@[install_version] --force'
43
47
  install_github_handle = 'EnableSecurity/wafw00f'
@@ -81,5 +85,19 @@ class wafw00f(Command):
81
85
  yield Tag(
82
86
  name=waf_name + ' WAF',
83
87
  match=url,
84
- extra_data={'waf_name': waf_name, 'manufacter': manufacter, 'trigger_url': match}
88
+ extra_data={
89
+ 'waf_name': waf_name,
90
+ 'manufacter': manufacter,
91
+ 'trigger_url': match,
92
+ 'headers': self.get_opt_value('header', preprocess=True)
93
+ }
85
94
  )
95
+
96
+ @staticmethod
97
+ def headers_to_file(headers):
98
+ temp_dir = tempfile.gettempdir()
99
+ header_file = f'{temp_dir}/headers.txt'
100
+ with open(header_file, 'w') as f:
101
+ for header in headers.split(';;'):
102
+ f.write(f'{header}\n')
103
+ return header_file
secator/tasks/wpprobe.py CHANGED
@@ -1,96 +1,103 @@
1
+ import os
2
+ import re
1
3
  import click
2
4
  import yaml
3
5
 
4
6
  from secator.decorators import task
5
7
  from secator.runners import Command
6
8
  from secator.definitions import OUTPUT_PATH, THREADS, URL
7
- from secator.output_types import Vulnerability, Tag, Info, Warning
9
+ from secator.output_types import Vulnerability, Tag, Info, Warning, Error
8
10
  from secator.tasks._categories import OPTS
9
11
 
10
12
 
11
13
  @task()
12
14
  class wpprobe(Command):
13
- """Fast wordpress plugin enumeration tool."""
14
- cmd = 'wpprobe'
15
- tags = ['vuln', 'scan', 'wordpress']
16
- file_flag = '-f'
17
- input_flag = '-u'
18
- input_types = [URL]
19
- opt_prefix = '-'
20
- opts = {
21
- 'mode': {'type': click.Choice(['scan', 'update', 'update-db']), 'default': 'scan', 'help': 'WPProbe mode', 'required': True, 'internal': True}, # noqa: E501
22
- 'output_path': {'type': str, 'default': None, 'help': 'Output JSON file path', 'internal': True, 'display': False}, # noqa: E501
23
- }
24
- meta_opts = {
25
- THREADS: OPTS[THREADS]
26
- }
27
- opt_key_map = {
28
- THREADS: 't'
29
- }
30
- output_types = [Vulnerability, Tag]
31
- install_version = 'v0.5.6'
32
- install_cmd = 'go install github.com/Chocapikk/wpprobe@[install_version]'
33
- install_github_handle = 'Chocapikk/wpprobe'
34
- install_post = {
35
- '*': 'wpprobe update && wpprobe update-db'
36
- }
15
+ """Fast wordpress plugin enumeration tool."""
16
+ cmd = 'wpprobe'
17
+ input_types = [URL]
18
+ output_types = [Vulnerability, Tag]
19
+ tags = ['vuln', 'scan', 'wordpress']
20
+ file_flag = '-f'
21
+ input_flag = '-u'
22
+ opt_prefix = '-'
23
+ opts = {
24
+ 'mode': {'type': click.Choice(['scan', 'update', 'update-db']), 'default': 'scan', 'help': 'WPProbe mode', 'required': True, 'internal': True}, # noqa: E501
25
+ 'output_path': {'type': str, 'default': None, 'help': 'Output JSON file path', 'internal': True, 'display': False}, # noqa: E501
26
+ }
27
+ meta_opts = {
28
+ THREADS: OPTS[THREADS]
29
+ }
30
+ opt_key_map = {
31
+ THREADS: 't'
32
+ }
33
+ install_version = 'v0.5.6'
34
+ install_cmd = 'go install github.com/Chocapikk/wpprobe@[install_version]'
35
+ install_github_handle = 'Chocapikk/wpprobe'
36
+ install_post = {
37
+ '*': 'wpprobe update && wpprobe update-db'
38
+ }
37
39
 
38
- @staticmethod
39
- def on_cmd(self):
40
- mode = self.get_opt_value('mode')
41
- if mode == 'update' or mode == 'update-db':
42
- self.cmd = f'{wpprobe.cmd} {mode}'
43
- return
44
- self.cmd = self.cmd.replace(wpprobe.cmd, f'{wpprobe.cmd} {mode}')
45
- output_path = self.get_opt_value(OUTPUT_PATH)
46
- if not output_path:
47
- output_path = f'{self.reports_folder}/.outputs/{self.unique_name}.json'
48
- self.output_path = output_path
49
- self.cmd += f' -o {self.output_path}'
40
+ @staticmethod
41
+ def on_cmd(self):
42
+ mode = self.get_opt_value('mode')
43
+ if mode == 'update' or mode == 'update-db':
44
+ self.cmd = f'{wpprobe.cmd} {mode}'
45
+ return
46
+ self.cmd = re.sub(wpprobe.cmd, f'{wpprobe.cmd} {mode}', self.cmd, 1)
47
+ output_path = self.get_opt_value(OUTPUT_PATH)
48
+ if not output_path:
49
+ output_path = f'{self.reports_folder}/.outputs/{self.unique_name}.json'
50
+ self.output_path = output_path
51
+ self.cmd += f' -o {self.output_path}'
50
52
 
51
- @staticmethod
52
- def on_cmd_done(self):
53
- if not self.get_opt_value('mode') == 'scan':
54
- return
55
- yield Info(message=f'JSON results saved to {self.output_path}')
56
- with open(self.output_path, 'r') as f:
57
- results = yaml.safe_load(f.read())
58
- if not results or 'url' not in results:
59
- yield Warning(message='No results found !')
60
- return
61
- url = results['url']
62
- for plugin_name, plugin_data in results['plugins'].items():
63
- for plugin_data_version in plugin_data:
64
- plugin_version = plugin_data_version['version']
65
- yield Tag(
66
- name=f'Wordpress plugin - {plugin_name} {plugin_version}',
67
- match=url,
68
- extra_data={
69
- 'name': plugin_name,
70
- 'version': plugin_version
71
- }
72
- )
73
- severities = plugin_data_version.get('severities', {})
74
- for severity, severity_data in severities.items():
75
- if severity == 'None':
76
- severity = 'unknown'
77
- for item in severity_data:
78
- for vuln in item['vulnerabilities']:
79
- auth_type = item.get('auth_type')
80
- extra_data = {
81
- 'plugin_name': plugin_name,
82
- 'plugin_version': plugin_version,
83
- }
84
- if auth_type:
85
- extra_data['auth_type'] = auth_type
86
- yield Vulnerability(
87
- name=vuln['title'],
88
- id=vuln['cve'],
89
- severity=severity,
90
- cvss_score=vuln['cvss_score'],
91
- tags=[plugin_name],
92
- reference=vuln['cve_link'],
93
- extra_data=extra_data,
94
- matched_at=url,
95
- confidence='high'
96
- )
53
+ @staticmethod
54
+ def on_cmd_done(self):
55
+ if not self.get_opt_value('mode') == 'scan':
56
+ return
57
+
58
+ if not os.path.exists(self.output_path):
59
+ yield Error(message=f'Could not find JSON results in {self.output_path}')
60
+ return
61
+
62
+ yield Info(message=f'JSON results saved to {self.output_path}')
63
+ with open(self.output_path, 'r') as f:
64
+ results = yaml.safe_load(f.read())
65
+ if not results or 'url' not in results:
66
+ yield Warning(message='No results found !')
67
+ return
68
+ url = results['url']
69
+ for plugin_name, plugin_data in results['plugins'].items():
70
+ for plugin_data_version in plugin_data:
71
+ plugin_version = plugin_data_version['version']
72
+ yield Tag(
73
+ name=f'Wordpress plugin - {plugin_name} {plugin_version}',
74
+ match=url,
75
+ extra_data={
76
+ 'name': plugin_name,
77
+ 'version': plugin_version
78
+ }
79
+ )
80
+ severities = plugin_data_version.get('severities', {})
81
+ for severity, severity_data in severities.items():
82
+ if severity == 'None':
83
+ severity = 'unknown'
84
+ for item in severity_data:
85
+ for vuln in item['vulnerabilities']:
86
+ auth_type = item.get('auth_type')
87
+ extra_data = {
88
+ 'plugin_name': plugin_name,
89
+ 'plugin_version': plugin_version,
90
+ }
91
+ if auth_type:
92
+ extra_data['auth_type'] = auth_type
93
+ yield Vulnerability(
94
+ name=vuln['title'],
95
+ id=vuln['cve'],
96
+ severity=severity,
97
+ cvss_score=vuln['cvss_score'],
98
+ tags=[plugin_name],
99
+ reference=vuln['cve_link'],
100
+ extra_data=extra_data,
101
+ matched_at=url,
102
+ confidence='high'
103
+ )
secator/tasks/wpscan.py CHANGED
@@ -17,10 +17,11 @@ from secator.tasks._categories import VulnHttp
17
17
  class wpscan(VulnHttp):
18
18
  """Wordpress security scanner."""
19
19
  cmd = 'wpscan --force --verbose'
20
+ input_types = [URL]
21
+ output_types = [Vulnerability, Tag]
20
22
  tags = ['vuln', 'scan', 'wordpress']
21
- file_flag = None
22
23
  input_flag = '--url'
23
- input_types = [URL]
24
+ input_chunk_size = 1
24
25
  json_flag = '-f json'
25
26
  opt_prefix = '--'
26
27
  opts = {
@@ -69,14 +70,14 @@ class wpscan(VulnHttp):
69
70
  PROVIDER: 'wpscan',
70
71
  },
71
72
  }
72
- output_types = [Vulnerability, Tag]
73
73
  install_pre = {
74
74
  'apt': ['make', 'kali:libcurl4t64', 'libffi-dev'],
75
75
  'pacman': ['make', 'ruby-erb'],
76
76
  '*': ['make']
77
77
  }
78
- install_version = '3.8.28'
79
- install_cmd = f'gem install wpscan -v [install_version] --user-install -n {CONFIG.dirs.bin}'
78
+ install_github_handle = 'wpscanteam/wpscan'
79
+ install_version = 'v3.8.28'
80
+ install_cmd = f'gem install wpscan -v [install_version_strip] --user-install -n {CONFIG.dirs.bin}'
80
81
  install_post = {
81
82
  'kali': (
82
83
  f'gem uninstall nokogiri --user-install -n {CONFIG.dirs.bin} --force --executables && '