secator 0.13.0__py3-none-any.whl → 0.14.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.

secator/cli.py CHANGED
@@ -36,6 +36,7 @@ click.rich_click.USE_RICH_MARKUP = True
36
36
  ALL_TASKS = discover_tasks()
37
37
  ALL_WORKFLOWS = [t for t in TEMPLATES if t.type == 'workflow']
38
38
  ALL_SCANS = [t for t in TEMPLATES if t.type == 'scan']
39
+ ALL_PROFILES = [t for t in TEMPLATES if t.type == 'profile']
39
40
  FINDING_TYPES_LOWER = [c.__name__.lower() for c in FINDING_TYPES]
40
41
  CONTEXT_SETTINGS = dict(help_option_names=['-h', '-help', '--help'])
41
42
 
@@ -125,6 +126,25 @@ for config in sorted(ALL_SCANS, key=lambda x: x['name']):
125
126
  register_runner(scan, config)
126
127
 
127
128
 
129
+ @cli.group(aliases=['p'])
130
+ @click.pass_context
131
+ def profile(ctx):
132
+ """Show profiles"""
133
+ pass
134
+
135
+
136
+ @profile.command('list')
137
+ def profile_list():
138
+ table = Table()
139
+ table.add_column("Profile name", style="bold gold3")
140
+ table.add_column("Description", overflow='fold')
141
+ table.add_column("Options", overflow='fold')
142
+ for profile in ALL_PROFILES:
143
+ opts_str = ','.join(f'{k}={v}' for k, v in profile.opts.items())
144
+ table.add_row(profile.name, profile.description, opts_str)
145
+ console.print(table)
146
+
147
+
128
148
  #--------#
129
149
  # WORKER #
130
150
  #--------#
@@ -685,7 +705,7 @@ def report_show(report_query, output, runner_type, time_delta, type, query, work
685
705
  all_results.extend(runner.results)
686
706
  continue
687
707
  report = Report(runner, title=f"Consolidated report - {current}", exporters=exporters)
688
- report.build(extractors=extractors if not unified else [])
708
+ report.build(extractors=extractors if not unified else [], dedupe=unified)
689
709
  file_date = get_file_date(path)
690
710
  runner_name = data['info']['name']
691
711
  console.print(
@@ -1423,6 +1443,16 @@ def task(name, verbose, check):
1423
1443
  task = task[0]
1424
1444
  task_name = task.__name__
1425
1445
 
1446
+ # Check task command is set
1447
+ check_test(
1448
+ task.cmd,
1449
+ 'Check task command is set (cls.cmd)',
1450
+ 'Task has no cmd attribute.',
1451
+ errors
1452
+ )
1453
+ if errors:
1454
+ sys.exit(0)
1455
+
1426
1456
  # Run install
1427
1457
  cmd = f'secator install tools {task_name}'
1428
1458
  ret_code = Command.execute(cmd, name='install', quiet=not verbose, cwd=ROOT_FOLDER)
@@ -1437,7 +1467,7 @@ def task(name, verbose, check):
1437
1467
  errors
1438
1468
  )
1439
1469
  check_test(
1440
- any(cmd for cmd in [task.install_cmd, task.install_github_handle]),
1470
+ any(cmd for cmd in [task.install_pre, task.install_cmd, task.install_github_handle]),
1441
1471
  'Check task installation command is defined',
1442
1472
  'Task has no installation command. Please define one or more of the following class attributes: `install_pre`, `install_cmd`, `install_post`, `install_github_handle`.', # noqa: E501
1443
1473
  errors
@@ -1471,12 +1501,6 @@ def task(name, verbose, check):
1471
1501
  'Task has no description (class docstring).',
1472
1502
  errors
1473
1503
  )
1474
- check_test(
1475
- task.cmd,
1476
- 'Check task command is set (cls.cmd)',
1477
- 'Task has no cmd attribute.',
1478
- errors
1479
- )
1480
1504
  check_test(
1481
1505
  task.input_type,
1482
1506
  'Check task input type is set (cls.input_type)',
@@ -1,7 +1,8 @@
1
1
  type: profile
2
2
  name: aggressive
3
- options:
4
- rate_limit: 100000
5
- delay: 0
6
- proxy: random
7
- user_agent: random
3
+ description: "Internal networks or time-sensitive scans"
4
+ opts:
5
+ rate_limit: 10000
6
+ delay: 0
7
+ timeout: 1
8
+ retries: 1
@@ -1,9 +1,8 @@
1
1
  type: profile
2
2
  name: default
3
- options:
4
- rate_limit: 1000
5
- delay: 1
6
- proxy: null
7
- user_agent: 'Mozilla ...'
8
- nuclei.retries: 5
9
- nuclei.timeout: 15
3
+ description: "General scanning"
4
+ opts:
5
+ rate_limit: 1000
6
+ delay: 0
7
+ timeout: 5
8
+ retries: 3
@@ -0,0 +1,8 @@
1
+ type: profile
2
+ name: insane
3
+ description: "Local LAN scanning or stress scanning"
4
+ opts:
5
+ rate_limit: 100000
6
+ delay: 0
7
+ timeout: 1
8
+ retries: 0
@@ -0,0 +1,8 @@
1
+ type: profile
2
+ name: paranoid
3
+ description: "Maximum stealth"
4
+ opts:
5
+ rate_limit: 5
6
+ delay: 5
7
+ timeout: 15
8
+ retries: 5
@@ -0,0 +1,8 @@
1
+ type: profile
2
+ name: polite
3
+ description: "Avoid overloading network"
4
+ opts:
5
+ rate_limit: 100
6
+ delay: 0
7
+ timeout: 10
8
+ retries: 5
@@ -0,0 +1,8 @@
1
+ type: profile
2
+ name: sneaky
3
+ description: "IDS/IPS evasion, sensitive networks"
4
+ opts:
5
+ rate_limit: 10
6
+ delay: 2
7
+ timeout: 15
8
+ retries: 5
@@ -0,0 +1,5 @@
1
+ type: profile
2
+ name: tor
3
+ description: "Anonymous scan using Tor network"
4
+ opts:
5
+ proxy: tor
secator/decorators.py CHANGED
@@ -13,6 +13,7 @@ from secator.utils import (deduplicate, expand_input, get_command_category)
13
13
 
14
14
  RUNNER_OPTS = {
15
15
  'output': {'type': str, 'default': None, 'help': 'Output options (-o table,json,csv,gdrive)', 'short': 'o'},
16
+ 'profiles': {'type': str, 'default': 'default', 'help': 'Profiles', 'short': 'pf'},
16
17
  'workspace': {'type': str, 'default': 'default', 'help': 'Workspace', 'short': 'ws'},
17
18
  'print_json': {'is_flag': True, 'short': 'json', 'default': False, 'help': 'Print items as JSON lines'},
18
19
  'print_raw': {'is_flag': True, 'short': 'raw', 'default': False, 'help': 'Print items in raw format'},
secator/report.py CHANGED
@@ -55,7 +55,7 @@ class Report:
55
55
  f'{str(e)}[/]\n[dim]{traceback_as_string(e)}[/]',
56
56
  )
57
57
 
58
- def build(self, extractors=[], dedupe=False):
58
+ def build(self, extractors=[], dedupe=CONFIG.runners.remove_duplicates):
59
59
  # Trim options
60
60
  from secator.decorators import DEFAULT_CLI_OPTIONS
61
61
  opts = merge_opts(self.runner.config.options, self.runner.run_opts)
@@ -97,7 +97,7 @@ class Report:
97
97
  if items:
98
98
  if sort_by and all(sort_by):
99
99
  items = sorted(items, key=operator.attrgetter(*sort_by))
100
- if dedupe and CONFIG.runners.remove_duplicates:
100
+ if dedupe:
101
101
  items = remove_duplicates(items)
102
102
  # items = [item for item in items if not item._duplicate and item not in dedupe_from]
103
103
  for extractor in extractors:
secator/runners/_base.py CHANGED
@@ -138,6 +138,10 @@ class Runner:
138
138
  self.debug('Run opts', obj={k: v for k, v in self.run_opts.items() if v is not None}, sub='init')
139
139
  self.debug('Print opts', obj={k: v for k, v in self.print_opts.items() if v is not None}, sub='init')
140
140
 
141
+ # Load profiles
142
+ profiles_str = run_opts.get('profiles', [])
143
+ self.load_profiles(profiles_str)
144
+
141
145
  # Determine exporters
142
146
  exporters_str = self.run_opts.get('output') or self.default_exporters
143
147
  self.exporters = self.resolve_exporters(exporters_str)
@@ -953,6 +957,32 @@ class Runner:
953
957
  ]
954
958
  return [cls for cls in classes if cls]
955
959
 
960
+ def load_profiles(self, profiles):
961
+ """Load profiles and update run options.
962
+
963
+ Args:
964
+ profiles (list[str]): List of profile names to resolve.
965
+
966
+ Returns:
967
+ list: List of profiles.
968
+ """
969
+ from secator.cli import ALL_PROFILES
970
+ if isinstance(profiles, str):
971
+ profiles = profiles.split(',')
972
+ templates = []
973
+ for pname in profiles:
974
+ matches = [p for p in ALL_PROFILES if p.name == pname]
975
+ if not matches:
976
+ self._print(Warning(message=f'Profile "{pname}" was not found'), rich=True)
977
+ else:
978
+ templates.append(matches[0])
979
+ opts = {}
980
+ for profile in templates:
981
+ self._print(Info(message=f'Loaded profile {profile.name} ({profile.description})'), rich=True)
982
+ opts.update(profile.opts)
983
+ opts = {k: v for k, v in opts.items() if k not in self.run_opts}
984
+ self.run_opts.update(opts)
985
+
956
986
  @classmethod
957
987
  def get_func_path(cls, func):
958
988
  """Get the full symbolic path of a function or method, including staticmethods, using function and method
secator/runners/scan.py CHANGED
@@ -33,6 +33,7 @@ class Scan(Runner):
33
33
  sigs = []
34
34
  for name, workflow_opts in self.config.workflows.items():
35
35
  run_opts = self.run_opts.copy()
36
+ run_opts.pop('profiles', None)
36
37
  run_opts['no_poll'] = True
37
38
  run_opts['caller'] = 'Scan'
38
39
  opts = merge_opts(scan_opts, workflow_opts, run_opts)
secator/runners/task.py CHANGED
@@ -32,6 +32,7 @@ class Task(Runner):
32
32
  # Run opts
33
33
  opts = self.run_opts.copy()
34
34
  opts.pop('output', None)
35
+ opts.pop('profiles', None)
35
36
  opts.pop('no_poll', False)
36
37
 
37
38
  # Set output types
secator/template.py CHANGED
@@ -64,7 +64,7 @@ class TemplateLoader(DotMap):
64
64
  _path = config.pop('_path', None)
65
65
  if _path:
66
66
  console.print(f'[italic green]{_path}[/]\n')
67
- yaml_str = yaml.dump(config, indent=4)
67
+ yaml_str = yaml.dump(config, indent=4, sort_keys=False)
68
68
  from rich.syntax import Syntax
69
69
  yaml_highlight = Syntax(yaml_str, 'yaml', line_numbers=True)
70
70
  console.print(yaml_highlight)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: secator
3
- Version: 0.13.0
3
+ Version: 0.14.0
4
4
  Summary: The pentester's swiss knife.
5
5
  Project-URL: Homepage, https://github.com/freelabz/secator
6
6
  Project-URL: Issues, https://github.com/freelabz/secator/issues
@@ -3,22 +3,26 @@ secator/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  secator/celery.py,sha256=Xg8e0zpQu4_-jlsZeC65NZtkopHGsGIyQ3SiW5fyH4E,9771
4
4
  secator/celery_signals.py,sha256=hG62Gr34xKJYZTgZFn_wZcsAlMgKuTazQhx55FC5cDA,4259
5
5
  secator/celery_utils.py,sha256=_wcUC42VPUotPhh9YYqbuq0dkARI8_RoCklDlhQL9Jg,8903
6
- secator/cli.py,sha256=AuAsrI2asH359Jnkzo9iek_3H2kdN_L0fzr1i9LpMdw,50827
6
+ secator/cli.py,sha256=76DSAyg0wZ4AraKwiEr7beoPNvQZjPgtz4IMEEP8UPs,51465
7
7
  secator/config.py,sha256=t3RJhfVKIoEcfDWBsYlFzz29BM3dsvJtGFzwTYL0Cfc,19727
8
- secator/decorators.py,sha256=sI1bbWm5g2SOb3EfHlvG37aY0SRK7EUzIiHLK0deACw,14583
8
+ secator/decorators.py,sha256=tTDXNNkEQrOF4jx1UgiOD_pxMnk0LX0R41ALALOx3jk,14668
9
9
  secator/definitions.py,sha256=qE_ZjzGcfrdASL7wjrc_0zoszUovL00KP--kGjDr93w,2986
10
10
  secator/installer.py,sha256=UBlQdcTvYXjmCiTui_fk9DOOxJ4Vs8i70m0ZCVFV78Q,19633
11
- secator/report.py,sha256=55xKvYY0MKNPaEgTrx66mj-Siohx3drLbTX2LpEx6zs,3627
11
+ secator/report.py,sha256=eWD8KgkXXZY_2cpu3xJY-ZuIkU60_UB62C79S69nDJM,3617
12
12
  secator/rich.py,sha256=0P6TECNePsfivc5h1JsJoAqKmpFnME5m8k29ZJjvbwM,3277
13
- secator/template.py,sha256=tDXpC02h6F9-_5YXlQK_nDkGde9LM6yRf7dEyJzHFps,4550
13
+ secator/template.py,sha256=o2igSFcNRWqptg8Rg00m8tvMmVAvbpnnvooWynk1LVI,4567
14
14
  secator/thread.py,sha256=rgRgEtcMgs2wyfLWVlCTUCLWeg6jsMo5iKpyyrON5rY,655
15
15
  secator/utils.py,sha256=kaBqWgBmUZohlvn6nFY805tG26viIu_LdJysNfZWMY4,22055
16
16
  secator/utils_test.py,sha256=jiCvgL4JMhIC1-ZGe6j9umNRZreSDp6nlkMgEJhf5ho,7996
17
17
  secator/configs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
18
  secator/configs/profiles/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
- secator/configs/profiles/aggressive.yaml,sha256=JilVySABlSCYEFMjH7V0Oc3dAVlkfHOh1odTGhtm7BQ,108
20
- secator/configs/profiles/default.yaml,sha256=kDuOF1Qkpv4oz1GZ-OwDxbi5pptAqShsCqdzkBOxXfw,149
21
- secator/configs/profiles/stealth.yaml,sha256=Ud3EMZ2yRj0AT6w-AfV7fWUBYib9VAFp46GPpof9YaU,107
19
+ secator/configs/profiles/aggressive.yaml,sha256=CXsCD76zrS93Iy47H-SUeEm3Ofl58H12dOr6rhm5sUg,159
20
+ secator/configs/profiles/default.yaml,sha256=QCGvqNyRdFjFjGKXLuz9xc9bvKhgG87HfR3flfaaoFs,130
21
+ secator/configs/profiles/insane.yaml,sha256=t3Z0fSy-tJkasMoPPViqxicTo0So5gnF3kfCBWIsR6Q,152
22
+ secator/configs/profiles/paranoid.yaml,sha256=P3jONEyS9qIU5OPhBpEmlzc1AMJVC6ncIBR3GwJIr8Q,128
23
+ secator/configs/profiles/polite.yaml,sha256=yZ2rtUMpSf-xMD7ZBFd6QS7XfYPEOSZ0Sn65lVF9M54,138
24
+ secator/configs/profiles/sneaky.yaml,sha256=TOouDi-JQ3ZGZW9t7xbax-UvB-r2IsTr9sONwSRGo88,147
25
+ secator/configs/profiles/tor.yaml,sha256=bHkn10KrJ5ct57od0Y8kaH-0IWB8aZWfmKQ68FZzct4,91
22
26
  secator/configs/scans/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
27
  secator/configs/scans/domain.yaml,sha256=Dkm5dU2NdUTInkWD5cmVczvhUH0soaKPtoESeg8BVsQ,265
24
28
  secator/configs/scans/host.yaml,sha256=tobz6yGeYlVnGwLVI9RLJT6MDLnGmQVVj8EOwAdksfw,189
@@ -29,7 +33,6 @@ secator/configs/workflows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
29
33
  secator/configs/workflows/cidr_recon.yaml,sha256=ytmirZxtJ8lKnzdo83mwTHOhy1OpnltuN3HFkk6XwzI,557
30
34
  secator/configs/workflows/code_scan.yaml,sha256=3H8H55NVskiDbBwNueVF8FUYkquEQn2C6evnid9zhB4,207
31
35
  secator/configs/workflows/host_recon.yaml,sha256=6RcH4RwCmTgesWVu8NrVIgW2ifNC4kSKgiRkNwZECdg,1173
32
- secator/configs/workflows/port_scan.yaml,sha256=J6-MPpPPfwFAIKf21gXMLu1wkprvZNAfDA_U90eXKJk,951
33
36
  secator/configs/workflows/subdomain_recon.yaml,sha256=GFhAyatzWRVx3a2kphNWNoTB13wY3GZTSZ2tusFgo8E,722
34
37
  secator/configs/workflows/url_bypass.yaml,sha256=_uBzDhevJ2DOD9UkE25n7ZrmnjjfdU3lV3mnUudgdU0,180
35
38
  secator/configs/workflows/url_crawl.yaml,sha256=h74dvDBNLuY1EHc9FMby3ydr34VH1qFJHQKUaIIYpcw,573
@@ -71,12 +74,12 @@ secator/output_types/user_account.py,sha256=EvF3Ebg9eXS_-iDguU1dSHZ9wAsJimEJznDv
71
74
  secator/output_types/vulnerability.py,sha256=nF7OT9zGez8sZvLrkhjBOORjVi8hCqfCYUFq3eZ_ywo,2870
72
75
  secator/output_types/warning.py,sha256=47GtmG083GqGPb_R5JDFmARJ9Mqrme58UxwJhgdGPuI,853
73
76
  secator/runners/__init__.py,sha256=EBbOk37vkBy9p8Hhrbi-2VtM_rTwQ3b-0ggTyiD22cE,290
74
- secator/runners/_base.py,sha256=XAG84cFw85g5D4fKjKTWW1OeOWJHX48px_vi9MN7QO0,31727
77
+ secator/runners/_base.py,sha256=XeH48AJvBKn3Z5qxbBmnL81jASWvIihBxPojw9Tyk-U,32629
75
78
  secator/runners/_helpers.py,sha256=FoawlexiNl1-QMBfwBx0p4Hi7rGZxHe_RAMahqZuJ0Y,2883
76
79
  secator/runners/celery.py,sha256=bqvDTTdoHiGRCt0FRvlgFHQ_nsjKMP5P0PzGbwfCj_0,425
77
80
  secator/runners/command.py,sha256=aAM_VZB9ZDtSYhg52PUlBJIkiqUcNb895Xuef6lIkF8,26900
78
- secator/runners/scan.py,sha256=n8RL9vXPmNqukdB2a5wcPhSmxsZB4KFaqtZt0wfa8dU,1622
79
- secator/runners/task.py,sha256=LIgcBqORVPG5Kfx6g6RnEni1kgWchMfa3Oo2JEZri1Y,2037
81
+ secator/runners/scan.py,sha256=jDPT9lnb2bGShvTClQ9u9SVRcHzZnXU1v308H7Fc-RE,1656
82
+ secator/runners/task.py,sha256=3wudRz8TdvkonnllaeLYLFztNlyXrMQ3E31t5lCRPkk,2066
80
83
  secator/runners/workflow.py,sha256=sO3B9GcndQLgGPnDz-A6XKnBmYO_ABAU_UXpW-q1K1A,3890
81
84
  secator/scans/__init__.py,sha256=s4Ojsk5CWwyWqHu_A4zaXUL5Hm5L5nCmCHZn7wdD3Io,623
82
85
  secator/serializers/__init__.py,sha256=OP5cmFl77ovgSCW_IDcZ21St2mUt5UK4QHfrsK2KvH8,248
@@ -118,8 +121,8 @@ secator/tasks/wafw00f.py,sha256=XeYl6ppS_YA-SmhBNdNcFmgUWYmiCnzU7TTLfxUTcRo,2747
118
121
  secator/tasks/wpprobe.py,sha256=Dx-HcGYjWyyeIsHwkstlcxPKJ5GR6jP9TMTHeV6SXPo,4025
119
122
  secator/tasks/wpscan.py,sha256=QrEO6ZrkmC3TDtD91Aeqip8qrcsrK7filHKpRdcteJU,5755
120
123
  secator/workflows/__init__.py,sha256=R_TTyjg9f2Ph2_LYiF0lL07IjTrfRE_zqJzy-N7_WCk,675
121
- secator-0.13.0.dist-info/METADATA,sha256=CrLCqEzK08_n09RStVZ0rp1bHNo4j3QVBrdxe9eV6NE,14724
122
- secator-0.13.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
123
- secator-0.13.0.dist-info/entry_points.txt,sha256=lPgsqqUXWgiuGSfKy-se5gHdQlAXIwS_A46NYq7Acic,44
124
- secator-0.13.0.dist-info/licenses/LICENSE,sha256=19W5Jsy4WTctNkqmZIqLRV1gTDOp01S3LDj9iSgWaJ0,2867
125
- secator-0.13.0.dist-info/RECORD,,
124
+ secator-0.14.0.dist-info/METADATA,sha256=_jYPgntzztbYS1ucHWOSSIq9d6J1MfEAikWHGr3DGpg,14724
125
+ secator-0.14.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
126
+ secator-0.14.0.dist-info/entry_points.txt,sha256=lPgsqqUXWgiuGSfKy-se5gHdQlAXIwS_A46NYq7Acic,44
127
+ secator-0.14.0.dist-info/licenses/LICENSE,sha256=19W5Jsy4WTctNkqmZIqLRV1gTDOp01S3LDj9iSgWaJ0,2867
128
+ secator-0.14.0.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- type: profile
2
- name: stealth
3
- options:
4
- rate_limit: 100
5
- delay: 1
6
- proxy: proxychains
7
- user_agent: random
@@ -1,39 +0,0 @@
1
- type: workflow
2
- name: port_scan
3
- alias: pscan
4
- description: Port scan
5
- tags: [recon, network, http, vuln]
6
- input_types:
7
- - host
8
- - cidr_range
9
- tasks:
10
- naabu:
11
- description: Find open ports
12
- skip_host_discovery: True
13
- ports: "-" # scan all ports
14
- nmap:
15
- description: Search for vulnerabilities on open ports
16
- skip_host_discovery: True
17
- version_detection: True
18
- targets_: port.host
19
- ports_: port.port
20
- _group:
21
- searchsploit:
22
- description: Search for related exploits
23
- targets_:
24
- - type: port
25
- field: '{host}~{service_name}'
26
- condition: item._source.startswith('nmap') and len(item.service_name.split('/')) > 1
27
- httpx:
28
- description: Probe HTTP services on open ports
29
- targets_:
30
- - type: port
31
- field: '{host}:{port}'
32
- condition: item._source.startswith('nmap')
33
- results:
34
- - type: port
35
-
36
- - type: url
37
- condition: item.status_code != 0
38
-
39
- - type: vulnerability