bbot 2.0.1.4720rc0__py3-none-any.whl → 2.3.0.5397rc0__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 bbot might be problematic. Click here for more details.

Files changed (267) hide show
  1. bbot/__init__.py +1 -1
  2. bbot/cli.py +3 -7
  3. bbot/core/config/files.py +0 -1
  4. bbot/core/config/logger.py +34 -4
  5. bbot/core/core.py +21 -4
  6. bbot/core/engine.py +9 -8
  7. bbot/core/event/base.py +131 -52
  8. bbot/core/helpers/bloom.py +10 -3
  9. bbot/core/helpers/command.py +8 -7
  10. bbot/core/helpers/depsinstaller/installer.py +31 -13
  11. bbot/core/helpers/diff.py +10 -10
  12. bbot/core/helpers/dns/brute.py +7 -4
  13. bbot/core/helpers/dns/dns.py +1 -2
  14. bbot/core/helpers/dns/engine.py +4 -6
  15. bbot/core/helpers/dns/helpers.py +2 -2
  16. bbot/core/helpers/dns/mock.py +0 -1
  17. bbot/core/helpers/files.py +1 -1
  18. bbot/core/helpers/helper.py +7 -4
  19. bbot/core/helpers/interactsh.py +3 -3
  20. bbot/core/helpers/libmagic.py +65 -0
  21. bbot/core/helpers/misc.py +65 -22
  22. bbot/core/helpers/names_generator.py +17 -3
  23. bbot/core/helpers/process.py +0 -20
  24. bbot/core/helpers/regex.py +1 -1
  25. bbot/core/helpers/regexes.py +12 -6
  26. bbot/core/helpers/validators.py +1 -2
  27. bbot/core/helpers/web/client.py +1 -1
  28. bbot/core/helpers/web/engine.py +1 -2
  29. bbot/core/helpers/web/web.py +4 -114
  30. bbot/core/helpers/wordcloud.py +5 -5
  31. bbot/core/modules.py +36 -27
  32. bbot/core/multiprocess.py +58 -0
  33. bbot/core/shared_deps.py +46 -3
  34. bbot/db/sql/models.py +147 -0
  35. bbot/defaults.yml +11 -9
  36. bbot/modules/anubisdb.py +2 -2
  37. bbot/modules/apkpure.py +63 -0
  38. bbot/modules/azure_tenant.py +2 -2
  39. bbot/modules/baddns.py +35 -19
  40. bbot/modules/baddns_direct.py +92 -0
  41. bbot/modules/baddns_zone.py +3 -8
  42. bbot/modules/badsecrets.py +4 -3
  43. bbot/modules/base.py +195 -51
  44. bbot/modules/bevigil.py +7 -7
  45. bbot/modules/binaryedge.py +7 -4
  46. bbot/modules/bufferoverrun.py +47 -0
  47. bbot/modules/builtwith.py +6 -10
  48. bbot/modules/bypass403.py +5 -5
  49. bbot/modules/c99.py +10 -7
  50. bbot/modules/censys.py +9 -13
  51. bbot/modules/certspotter.py +5 -3
  52. bbot/modules/chaos.py +9 -7
  53. bbot/modules/code_repository.py +1 -0
  54. bbot/modules/columbus.py +3 -3
  55. bbot/modules/crt.py +5 -3
  56. bbot/modules/deadly/dastardly.py +1 -1
  57. bbot/modules/deadly/ffuf.py +9 -9
  58. bbot/modules/deadly/nuclei.py +3 -3
  59. bbot/modules/deadly/vhost.py +4 -3
  60. bbot/modules/dehashed.py +1 -1
  61. bbot/modules/digitorus.py +1 -1
  62. bbot/modules/dnsbimi.py +145 -0
  63. bbot/modules/dnscaa.py +3 -3
  64. bbot/modules/dnsdumpster.py +4 -4
  65. bbot/modules/dnstlsrpt.py +144 -0
  66. bbot/modules/docker_pull.py +7 -5
  67. bbot/modules/dockerhub.py +2 -2
  68. bbot/modules/dotnetnuke.py +18 -19
  69. bbot/modules/emailformat.py +1 -1
  70. bbot/modules/extractous.py +122 -0
  71. bbot/modules/filedownload.py +9 -7
  72. bbot/modules/fullhunt.py +7 -4
  73. bbot/modules/generic_ssrf.py +5 -5
  74. bbot/modules/github_codesearch.py +3 -2
  75. bbot/modules/github_org.py +4 -4
  76. bbot/modules/github_workflows.py +4 -4
  77. bbot/modules/gitlab.py +2 -5
  78. bbot/modules/google_playstore.py +93 -0
  79. bbot/modules/gowitness.py +48 -50
  80. bbot/modules/hackertarget.py +5 -3
  81. bbot/modules/host_header.py +5 -5
  82. bbot/modules/httpx.py +1 -4
  83. bbot/modules/hunterio.py +3 -9
  84. bbot/modules/iis_shortnames.py +19 -30
  85. bbot/modules/internal/cloudcheck.py +27 -12
  86. bbot/modules/internal/dnsresolve.py +22 -20
  87. bbot/modules/internal/excavate.py +85 -48
  88. bbot/modules/internal/speculate.py +41 -32
  89. bbot/modules/internetdb.py +4 -2
  90. bbot/modules/ip2location.py +3 -5
  91. bbot/modules/ipneighbor.py +1 -1
  92. bbot/modules/ipstack.py +3 -8
  93. bbot/modules/jadx.py +87 -0
  94. bbot/modules/leakix.py +11 -10
  95. bbot/modules/myssl.py +2 -2
  96. bbot/modules/newsletters.py +2 -2
  97. bbot/modules/otx.py +5 -3
  98. bbot/modules/output/asset_inventory.py +7 -7
  99. bbot/modules/output/base.py +1 -1
  100. bbot/modules/output/csv.py +1 -1
  101. bbot/modules/output/http.py +20 -14
  102. bbot/modules/output/mysql.py +51 -0
  103. bbot/modules/output/neo4j.py +7 -2
  104. bbot/modules/output/postgres.py +49 -0
  105. bbot/modules/output/slack.py +0 -1
  106. bbot/modules/output/sqlite.py +29 -0
  107. bbot/modules/output/stdout.py +2 -2
  108. bbot/modules/output/teams.py +107 -6
  109. bbot/modules/paramminer_headers.py +5 -8
  110. bbot/modules/passivetotal.py +13 -13
  111. bbot/modules/portscan.py +32 -6
  112. bbot/modules/postman.py +50 -126
  113. bbot/modules/postman_download.py +220 -0
  114. bbot/modules/rapiddns.py +3 -8
  115. bbot/modules/report/asn.py +11 -11
  116. bbot/modules/robots.py +3 -3
  117. bbot/modules/securitytrails.py +7 -10
  118. bbot/modules/securitytxt.py +1 -1
  119. bbot/modules/shodan_dns.py +7 -9
  120. bbot/modules/sitedossier.py +1 -1
  121. bbot/modules/skymem.py +2 -2
  122. bbot/modules/social.py +2 -1
  123. bbot/modules/subdomaincenter.py +1 -1
  124. bbot/modules/subdomainradar.py +160 -0
  125. bbot/modules/telerik.py +8 -8
  126. bbot/modules/templates/bucket.py +1 -1
  127. bbot/modules/templates/github.py +22 -14
  128. bbot/modules/templates/postman.py +21 -0
  129. bbot/modules/templates/shodan.py +14 -13
  130. bbot/modules/templates/sql.py +95 -0
  131. bbot/modules/templates/subdomain_enum.py +51 -16
  132. bbot/modules/templates/webhook.py +2 -4
  133. bbot/modules/trickest.py +8 -37
  134. bbot/modules/trufflehog.py +10 -12
  135. bbot/modules/url_manipulation.py +3 -3
  136. bbot/modules/urlscan.py +1 -1
  137. bbot/modules/viewdns.py +1 -1
  138. bbot/modules/virustotal.py +8 -30
  139. bbot/modules/wafw00f.py +1 -1
  140. bbot/modules/wayback.py +1 -1
  141. bbot/modules/wpscan.py +17 -11
  142. bbot/modules/zoomeye.py +11 -6
  143. bbot/presets/baddns-thorough.yml +12 -0
  144. bbot/presets/fast.yml +16 -0
  145. bbot/presets/kitchen-sink.yml +1 -0
  146. bbot/presets/spider.yml +4 -0
  147. bbot/presets/subdomain-enum.yml +7 -7
  148. bbot/scanner/manager.py +5 -16
  149. bbot/scanner/preset/args.py +44 -26
  150. bbot/scanner/preset/environ.py +7 -2
  151. bbot/scanner/preset/path.py +7 -4
  152. bbot/scanner/preset/preset.py +36 -23
  153. bbot/scanner/scanner.py +172 -62
  154. bbot/scanner/target.py +236 -434
  155. bbot/scripts/docs.py +1 -1
  156. bbot/test/bbot_fixtures.py +13 -3
  157. bbot/test/conftest.py +132 -100
  158. bbot/test/fastapi_test.py +17 -0
  159. bbot/test/owasp_mastg.apk +0 -0
  160. bbot/test/run_tests.sh +4 -4
  161. bbot/test/test.conf +2 -0
  162. bbot/test/test_step_1/test_bbot_fastapi.py +82 -0
  163. bbot/test/test_step_1/test_bloom_filter.py +2 -0
  164. bbot/test/test_step_1/test_cli.py +138 -64
  165. bbot/test/test_step_1/test_dns.py +62 -25
  166. bbot/test/test_step_1/test_engine.py +17 -17
  167. bbot/test/test_step_1/test_events.py +183 -28
  168. bbot/test/test_step_1/test_helpers.py +64 -28
  169. bbot/test/test_step_1/test_manager_deduplication.py +1 -1
  170. bbot/test/test_step_1/test_manager_scope_accuracy.py +333 -330
  171. bbot/test/test_step_1/test_modules_basic.py +68 -70
  172. bbot/test/test_step_1/test_presets.py +184 -96
  173. bbot/test/test_step_1/test_python_api.py +7 -2
  174. bbot/test/test_step_1/test_regexes.py +35 -5
  175. bbot/test/test_step_1/test_scan.py +39 -5
  176. bbot/test/test_step_1/test_scope.py +4 -3
  177. bbot/test/test_step_1/test_target.py +243 -145
  178. bbot/test/test_step_1/test_web.py +14 -8
  179. bbot/test/test_step_2/module_tests/base.py +15 -7
  180. bbot/test/test_step_2/module_tests/test_module_anubisdb.py +1 -1
  181. bbot/test/test_step_2/module_tests/test_module_apkpure.py +71 -0
  182. bbot/test/test_step_2/module_tests/test_module_asset_inventory.py +0 -1
  183. bbot/test/test_step_2/module_tests/test_module_azure_realm.py +1 -1
  184. bbot/test/test_step_2/module_tests/test_module_baddns.py +6 -6
  185. bbot/test/test_step_2/module_tests/test_module_baddns_direct.py +62 -0
  186. bbot/test/test_step_2/module_tests/test_module_bevigil.py +29 -2
  187. bbot/test/test_step_2/module_tests/test_module_binaryedge.py +4 -2
  188. bbot/test/test_step_2/module_tests/test_module_bucket_amazon.py +2 -2
  189. bbot/test/test_step_2/module_tests/test_module_bucket_azure.py +1 -1
  190. bbot/test/test_step_2/module_tests/test_module_bufferoverrun.py +35 -0
  191. bbot/test/test_step_2/module_tests/test_module_builtwith.py +2 -2
  192. bbot/test/test_step_2/module_tests/test_module_bypass403.py +1 -1
  193. bbot/test/test_step_2/module_tests/test_module_c99.py +126 -0
  194. bbot/test/test_step_2/module_tests/test_module_censys.py +4 -1
  195. bbot/test/test_step_2/module_tests/test_module_cloudcheck.py +4 -0
  196. bbot/test/test_step_2/module_tests/test_module_code_repository.py +11 -1
  197. bbot/test/test_step_2/module_tests/test_module_columbus.py +1 -1
  198. bbot/test/test_step_2/module_tests/test_module_credshed.py +3 -3
  199. bbot/test/test_step_2/module_tests/test_module_dastardly.py +2 -1
  200. bbot/test/test_step_2/module_tests/test_module_dehashed.py +2 -2
  201. bbot/test/test_step_2/module_tests/test_module_digitorus.py +1 -1
  202. bbot/test/test_step_2/module_tests/test_module_discord.py +1 -1
  203. bbot/test/test_step_2/module_tests/test_module_dnsbimi.py +103 -0
  204. bbot/test/test_step_2/module_tests/test_module_dnsbrute.py +9 -10
  205. bbot/test/test_step_2/module_tests/test_module_dnsbrute_mutations.py +1 -2
  206. bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py +1 -2
  207. bbot/test/test_step_2/module_tests/test_module_dnsdumpster.py +4 -4
  208. bbot/test/test_step_2/module_tests/test_module_dnstlsrpt.py +64 -0
  209. bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py +0 -8
  210. bbot/test/test_step_2/module_tests/test_module_excavate.py +17 -37
  211. bbot/test/test_step_2/module_tests/test_module_extractous.py +54 -0
  212. bbot/test/test_step_2/module_tests/test_module_ffuf_shortnames.py +1 -1
  213. bbot/test/test_step_2/module_tests/test_module_filedownload.py +14 -14
  214. bbot/test/test_step_2/module_tests/test_module_git_clone.py +2 -2
  215. bbot/test/test_step_2/module_tests/test_module_github_org.py +19 -8
  216. bbot/test/test_step_2/module_tests/test_module_github_workflows.py +1 -1
  217. bbot/test/test_step_2/module_tests/test_module_gitlab.py +9 -4
  218. bbot/test/test_step_2/module_tests/test_module_google_playstore.py +83 -0
  219. bbot/test/test_step_2/module_tests/test_module_gowitness.py +4 -4
  220. bbot/test/test_step_2/module_tests/test_module_host_header.py +1 -1
  221. bbot/test/test_step_2/module_tests/test_module_http.py +4 -4
  222. bbot/test/test_step_2/module_tests/test_module_httpx.py +10 -8
  223. bbot/test/test_step_2/module_tests/test_module_hunterio.py +68 -4
  224. bbot/test/test_step_2/module_tests/test_module_jadx.py +55 -0
  225. bbot/test/test_step_2/module_tests/test_module_json.py +22 -9
  226. bbot/test/test_step_2/module_tests/test_module_leakix.py +7 -3
  227. bbot/test/test_step_2/module_tests/test_module_mysql.py +76 -0
  228. bbot/test/test_step_2/module_tests/test_module_myssl.py +1 -1
  229. bbot/test/test_step_2/module_tests/test_module_neo4j.py +1 -1
  230. bbot/test/test_step_2/module_tests/test_module_newsletters.py +6 -6
  231. bbot/test/test_step_2/module_tests/test_module_ntlm.py +7 -7
  232. bbot/test/test_step_2/module_tests/test_module_oauth.py +1 -1
  233. bbot/test/test_step_2/module_tests/test_module_otx.py +1 -1
  234. bbot/test/test_step_2/module_tests/test_module_paramminer_cookies.py +1 -2
  235. bbot/test/test_step_2/module_tests/test_module_paramminer_getparams.py +0 -6
  236. bbot/test/test_step_2/module_tests/test_module_paramminer_headers.py +2 -9
  237. bbot/test/test_step_2/module_tests/test_module_passivetotal.py +3 -1
  238. bbot/test/test_step_2/module_tests/test_module_portscan.py +9 -8
  239. bbot/test/test_step_2/module_tests/test_module_postgres.py +74 -0
  240. bbot/test/test_step_2/module_tests/test_module_postman.py +84 -253
  241. bbot/test/test_step_2/module_tests/test_module_postman_download.py +439 -0
  242. bbot/test/test_step_2/module_tests/test_module_rapiddns.py +93 -1
  243. bbot/test/test_step_2/module_tests/test_module_shodan_dns.py +20 -1
  244. bbot/test/test_step_2/module_tests/test_module_sitedossier.py +2 -2
  245. bbot/test/test_step_2/module_tests/test_module_smuggler.py +1 -1
  246. bbot/test/test_step_2/module_tests/test_module_social.py +11 -1
  247. bbot/test/test_step_2/module_tests/test_module_speculate.py +2 -6
  248. bbot/test/test_step_2/module_tests/test_module_splunk.py +4 -4
  249. bbot/test/test_step_2/module_tests/test_module_sqlite.py +18 -0
  250. bbot/test/test_step_2/module_tests/test_module_sslcert.py +1 -1
  251. bbot/test/test_step_2/module_tests/test_module_stdout.py +5 -3
  252. bbot/test/test_step_2/module_tests/test_module_subdomaincenter.py +1 -1
  253. bbot/test/test_step_2/module_tests/test_module_subdomainradar.py +208 -0
  254. bbot/test/test_step_2/module_tests/test_module_subdomains.py +1 -1
  255. bbot/test/test_step_2/module_tests/test_module_teams.py +8 -6
  256. bbot/test/test_step_2/module_tests/test_module_telerik.py +1 -1
  257. bbot/test/test_step_2/module_tests/test_module_trufflehog.py +317 -14
  258. bbot/test/test_step_2/module_tests/test_module_wayback.py +1 -1
  259. bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py +2 -2
  260. {bbot-2.0.1.4720rc0.dist-info → bbot-2.3.0.5397rc0.dist-info}/METADATA +48 -18
  261. bbot-2.3.0.5397rc0.dist-info/RECORD +421 -0
  262. {bbot-2.0.1.4720rc0.dist-info → bbot-2.3.0.5397rc0.dist-info}/WHEEL +1 -1
  263. bbot/modules/unstructured.py +0 -163
  264. bbot/test/test_step_2/module_tests/test_module_unstructured.py +0 -102
  265. bbot-2.0.1.4720rc0.dist-info/RECORD +0 -387
  266. {bbot-2.0.1.4720rc0.dist-info → bbot-2.3.0.5397rc0.dist-info}/LICENSE +0 -0
  267. {bbot-2.0.1.4720rc0.dist-info → bbot-2.3.0.5397rc0.dist-info}/entry_points.txt +0 -0
@@ -13,10 +13,10 @@ config:
13
13
  threads: 25
14
14
  brute_threads: 1000
15
15
  # put your API keys here
16
- modules:
17
- github:
18
- api_key: ""
19
- chaos:
20
- api_key: ""
21
- securitytrails:
22
- api_key: ""
16
+ # modules:
17
+ # github:
18
+ # api_key: ""
19
+ # chaos:
20
+ # api_key: ""
21
+ # securitytrails:
22
+ # api_key: ""
bbot/scanner/manager.py CHANGED
@@ -1,10 +1,10 @@
1
1
  import asyncio
2
2
  from contextlib import suppress
3
3
 
4
- from bbot.modules.base import InterceptModule
4
+ from bbot.modules.base import BaseInterceptModule
5
5
 
6
6
 
7
- class ScanIngress(InterceptModule):
7
+ class ScanIngress(BaseInterceptModule):
8
8
  """
9
9
  This is always the first intercept module in the chain, responsible for basic scope checks
10
10
 
@@ -15,9 +15,7 @@ class ScanIngress(InterceptModule):
15
15
  # accept all events regardless of scope distance
16
16
  scope_distance_modifier = None
17
17
  _name = "_scan_ingress"
18
-
19
- # small queue size so we don't drain modules' outgoing queues
20
- _qsize = 10
18
+ _qsize = -1
21
19
 
22
20
  @property
23
21
  def priority(self):
@@ -40,7 +38,7 @@ class ScanIngress(InterceptModule):
40
38
  - It also marks the Scan object as finished with initialization by setting `_finished_init` to True.
41
39
  """
42
40
  if events is None:
43
- events = self.scan.target.events
41
+ events = self.scan.target.seeds.events
44
42
  async with self.scan._acatch(self.init_events), self._task_counter.count(self.init_events):
45
43
  sorted_events = sorted(events, key=lambda e: len(e.data))
46
44
  for event in [self.scan.root_event] + sorted_events:
@@ -51,7 +49,6 @@ class ScanIngress(InterceptModule):
51
49
  event.parent = self.scan.root_event
52
50
  if event.module is None:
53
51
  event.module = self.scan._make_dummy_module(name="TARGET", _type="TARGET")
54
- event.add_tag("target")
55
52
  if event != self.scan.root_event:
56
53
  event.discovery_context = f"Scan {self.scan.name} seeded with " + "{event.type}: {event.data}"
57
54
  self.verbose(f"Target: {event}")
@@ -115,14 +112,6 @@ class ScanIngress(InterceptModule):
115
112
  # nerf event's priority if it's not in scope
116
113
  event.module_priority += event.scope_distance
117
114
 
118
- async def forward_event(self, event, kwargs):
119
- # if a module qualifies for "quick-emit", we skip all the intermediate modules like dns and cloud
120
- # and forward it straight to the egress module
121
- if event.quick_emit:
122
- await self.scan.egress_module.queue_event(event, kwargs)
123
- else:
124
- await super().forward_event(event, kwargs)
125
-
126
115
  @property
127
116
  def non_intercept_modules(self):
128
117
  if self._non_intercept_modules is None:
@@ -169,7 +158,7 @@ class ScanIngress(InterceptModule):
169
158
  return False
170
159
 
171
160
 
172
- class ScanEgress(InterceptModule):
161
+ class ScanEgress(BaseInterceptModule):
173
162
  """
174
163
  This is always the last intercept module in the chain, responsible for executing and acting on the
175
164
  `abort_if` and `on_success_callback` functions.
@@ -10,7 +10,6 @@ log = logging.getLogger("bbot.presets.args")
10
10
 
11
11
 
12
12
  class BBOTArgs:
13
-
14
13
  # module config options to exclude from validation
15
14
  exclude_from_validation = re.compile(r".*modules\.[a-z0-9_]+\.(?:batch_size|module_threads)$")
16
15
 
@@ -91,18 +90,9 @@ class BBOTArgs:
91
90
  *self.parsed.targets,
92
91
  whitelist=self.parsed.whitelist,
93
92
  blacklist=self.parsed.blacklist,
94
- strict_scope=self.parsed.strict_scope,
95
93
  name="args_preset",
96
94
  )
97
95
 
98
- # then we set verbosity levels (so if the user enables -d they can see debug output)
99
- if self.parsed.silent:
100
- args_preset.silent = True
101
- if self.parsed.verbose:
102
- args_preset.verbose = True
103
- if self.parsed.debug:
104
- args_preset.debug = True
105
-
106
96
  # then we load requested preset
107
97
  # this is important so we can load custom module directories, pull in custom flags, module config options, etc.
108
98
  for preset_arg in self.parsed.preset:
@@ -113,6 +103,14 @@ class BBOTArgs:
113
103
  except Exception as e:
114
104
  raise BBOTArgumentError(f'Error parsing preset "{preset_arg}": {e}')
115
105
 
106
+ # then we set verbosity levels (so if the user enables -d they can see debug output)
107
+ if self.parsed.silent:
108
+ args_preset.silent = True
109
+ if self.parsed.verbose:
110
+ args_preset.verbose = True
111
+ if self.parsed.debug:
112
+ args_preset.debug = True
113
+
116
114
  # modules + flags
117
115
  args_preset.exclude_modules.update(set(self.parsed.exclude_modules))
118
116
  args_preset.exclude_flags.update(set(self.parsed.exclude_flags))
@@ -142,9 +140,15 @@ class BBOTArgs:
142
140
  args_preset.core.custom_config["deps_behavior"] = "ignore_failed"
143
141
 
144
142
  # other scan options
145
- args_preset.scan_name = self.parsed.name
146
- args_preset.output_dir = self.parsed.output_dir
147
- args_preset.force_start = self.parsed.force
143
+ if self.parsed.name is not None:
144
+ args_preset.scan_name = self.parsed.name
145
+ if self.parsed.output_dir is not None:
146
+ args_preset.output_dir = self.parsed.output_dir
147
+ if self.parsed.force:
148
+ args_preset.force_start = self.parsed.force
149
+
150
+ if self.parsed.proxy:
151
+ args_preset.core.merge_custom({"web": {"http_proxy": self.parsed.proxy}})
148
152
 
149
153
  if self.parsed.custom_headers:
150
154
  args_preset.core.merge_custom({"web": {"http_headers": self.parsed.custom_headers}})
@@ -162,13 +166,17 @@ class BBOTArgs:
162
166
  except Exception as e:
163
167
  raise BBOTArgumentError(f'Error parsing command-line config option: "{config_arg}": {e}')
164
168
 
169
+ # strict scope
170
+ if self.parsed.strict_scope:
171
+ args_preset.core.merge_custom({"scope": {"strict": True}})
172
+
165
173
  return args_preset
166
174
 
167
175
  def create_parser(self, *args, **kwargs):
168
176
  kwargs.update(
169
- dict(
170
- description="Bighuge BLS OSINT Tool", formatter_class=argparse.RawTextHelpFormatter, epilog=self.epilog
171
- )
177
+ {
178
+ "description": "Bighuge BLS OSINT Tool", "formatter_class": argparse.RawTextHelpFormatter, "epilog": self.epilog
179
+ }
172
180
  )
173
181
  p = argparse.ArgumentParser(*args, **kwargs)
174
182
 
@@ -206,7 +214,7 @@ class BBOTArgs:
206
214
  metavar="CONFIG",
207
215
  default=[],
208
216
  )
209
- presets.add_argument("-lp", "--list-presets", action="store_true", help=f"List available presets.")
217
+ presets.add_argument("-lp", "--list-presets", action="store_true", help="List available presets.")
210
218
 
211
219
  modules = p.add_argument_group(title="Modules")
212
220
  modules.add_argument(
@@ -214,31 +222,31 @@ class BBOTArgs:
214
222
  "--modules",
215
223
  nargs="+",
216
224
  default=[],
217
- help=f'Modules to enable. Choices: {",".join(self.preset.module_loader.scan_module_choices)}',
225
+ help=f'Modules to enable. Choices: {",".join(sorted(self.preset.module_loader.scan_module_choices))}',
218
226
  metavar="MODULE",
219
227
  )
220
- modules.add_argument("-l", "--list-modules", action="store_true", help=f"List available modules.")
228
+ modules.add_argument("-l", "--list-modules", action="store_true", help="List available modules.")
221
229
  modules.add_argument(
222
230
  "-lmo", "--list-module-options", action="store_true", help="Show all module config options"
223
231
  )
224
232
  modules.add_argument(
225
- "-em", "--exclude-modules", nargs="+", default=[], help=f"Exclude these modules.", metavar="MODULE"
233
+ "-em", "--exclude-modules", nargs="+", default=[], help="Exclude these modules.", metavar="MODULE"
226
234
  )
227
235
  modules.add_argument(
228
236
  "-f",
229
237
  "--flags",
230
238
  nargs="+",
231
239
  default=[],
232
- help=f'Enable modules by flag. Choices: {",".join(self.preset.module_loader.flag_choices)}',
240
+ help=f'Enable modules by flag. Choices: {",".join(sorted(self.preset.module_loader.flag_choices))}',
233
241
  metavar="FLAG",
234
242
  )
235
- modules.add_argument("-lf", "--list-flags", action="store_true", help=f"List available flags.")
243
+ modules.add_argument("-lf", "--list-flags", action="store_true", help="List available flags.")
236
244
  modules.add_argument(
237
245
  "-rf",
238
246
  "--require-flags",
239
247
  nargs="+",
240
248
  default=[],
241
- help=f"Only enable modules with these flags (e.g. -rf passive)",
249
+ help="Only enable modules with these flags (e.g. -rf passive)",
242
250
  metavar="FLAG",
243
251
  )
244
252
  modules.add_argument(
@@ -246,7 +254,7 @@ class BBOTArgs:
246
254
  "--exclude-flags",
247
255
  nargs="+",
248
256
  default=[],
249
- help=f"Disable modules with these flags. (e.g. -ef aggressive)",
257
+ help="Disable modules with these flags. (e.g. -ef aggressive)",
250
258
  metavar="FLAG",
251
259
  )
252
260
  modules.add_argument("--allow-deadly", action="store_true", help="Enable the use of highly aggressive modules")
@@ -262,7 +270,12 @@ class BBOTArgs:
262
270
  help="Run scan even in the case of condition violations or failed module setups",
263
271
  )
264
272
  scan.add_argument("-y", "--yes", action="store_true", help="Skip scan confirmation prompt")
265
- scan.add_argument("--dry-run", action="store_true", help=f"Abort before executing scan")
273
+ scan.add_argument(
274
+ "--fast-mode",
275
+ action="store_true",
276
+ help="Scan only the provided targets as fast as possible, with no extra discovery",
277
+ )
278
+ scan.add_argument("--dry-run", action="store_true", help="Abort before executing scan")
266
279
  scan.add_argument(
267
280
  "--current-preset",
268
281
  action="store_true",
@@ -286,7 +299,7 @@ class BBOTArgs:
286
299
  "--output-modules",
287
300
  nargs="+",
288
301
  default=[],
289
- help=f'Output module(s). Choices: {",".join(self.preset.module_loader.output_module_choices)}',
302
+ help=f'Output module(s). Choices: {",".join(sorted(self.preset.module_loader.output_module_choices))}',
290
303
  metavar="MODULE",
291
304
  )
292
305
  output.add_argument("--json", "-j", action="store_true", help="Output scan data in JSON format")
@@ -307,6 +320,7 @@ class BBOTArgs:
307
320
 
308
321
  misc = p.add_argument_group(title="Misc")
309
322
  misc.add_argument("--version", action="store_true", help="show BBOT version and exit")
323
+ misc.add_argument("--proxy", help="Use this proxy for all HTTP requests", metavar="HTTP_PROXY")
310
324
  misc.add_argument(
311
325
  "-H",
312
326
  "--custom-headers",
@@ -356,6 +370,10 @@ class BBOTArgs:
356
370
  custom_headers_dict[k] = v
357
371
  self.parsed.custom_headers = custom_headers_dict
358
372
 
373
+ # --fast-mode
374
+ if self.parsed.fast_mode:
375
+ self.parsed.preset += ["fast"]
376
+
359
377
  def validate(self):
360
378
  # validate config options
361
379
  sentinel = object()
@@ -6,6 +6,9 @@ from pathlib import Path
6
6
  from bbot.core.helpers.misc import cpu_architecture, os_platform, os_platform_friendly
7
7
 
8
8
 
9
+ REQUESTS_PATCHED = False
10
+
11
+
9
12
  def increase_limit(new_limit):
10
13
  try:
11
14
  import resource
@@ -62,7 +65,6 @@ omegaconf.OmegaConf.register_new_resolver("env", env_resolver)
62
65
 
63
66
 
64
67
  class BBOTEnviron:
65
-
66
68
  def __init__(self, preset):
67
69
  self.preset = preset
68
70
 
@@ -120,7 +122,10 @@ class BBOTEnviron:
120
122
 
121
123
  urllib3.disable_warnings()
122
124
  ssl_verify = self.preset.config.get("ssl_verify", False)
123
- if not ssl_verify:
125
+
126
+ global REQUESTS_PATCHED
127
+ if not ssl_verify and not REQUESTS_PATCHED:
128
+ REQUESTS_PATCHED = True
124
129
  import requests
125
130
  import functools
126
131
 
@@ -33,13 +33,16 @@ class PresetPath:
33
33
  if "/" in str(filename):
34
34
  if filename_path.parent not in paths_to_search:
35
35
  paths_to_search.append(filename_path.parent)
36
- log.debug(f"Searching for preset in {paths_to_search}, file candidates: {file_candidates_str}")
36
+ log.debug(
37
+ f"Searching for preset in {[str(p) for p in paths_to_search]}, file candidates: {file_candidates_str}"
38
+ )
37
39
  for path in paths_to_search:
38
40
  for candidate in file_candidates:
39
41
  for file in path.rglob(candidate):
40
- log.verbose(f'Found preset matching "{filename}" at {file}')
41
- self.add_path(file.parent)
42
- return file.resolve()
42
+ if file.is_file():
43
+ log.verbose(f'Found preset matching "{filename}" at {file}')
44
+ self.add_path(file.parent)
45
+ return file.resolve()
43
46
  raise ValidationError(
44
47
  f'Could not find preset at "{filename}" - file does not exist. Use -lp to list available presets'
45
48
  )
@@ -17,7 +17,7 @@ from bbot.core.helpers.misc import make_table, mkdir, get_closest_match
17
17
  log = logging.getLogger("bbot.presets")
18
18
 
19
19
 
20
- _preset_cache = dict()
20
+ _preset_cache = {}
21
21
 
22
22
 
23
23
  # cache default presets to prevent having to reload from disk
@@ -47,7 +47,6 @@ class Preset:
47
47
  target (Target): Target(s) of scan.
48
48
  whitelist (Target): Scan whitelist (by default this is the same as `target`).
49
49
  blacklist (Target): Scan blacklist (this takes ultimate precedence).
50
- strict_scope (bool): If True, subdomains of targets are not considered to be in-scope.
51
50
  helpers (ConfigAwareHelper): Helper containing various reusable functions, regexes, etc.
52
51
  output_dir (pathlib.Path): Output directory for scan.
53
52
  scan_name (str): Name of scan. Defaults to random value, e.g. "demonic_jimmy".
@@ -87,7 +86,6 @@ class Preset:
87
86
  *targets,
88
87
  whitelist=None,
89
88
  blacklist=None,
90
- strict_scope=False,
91
89
  modules=None,
92
90
  output_modules=None,
93
91
  exclude_modules=None,
@@ -117,7 +115,6 @@ class Preset:
117
115
  *targets (str): Target(s) to scan. Types supported: hostnames, IPs, CIDRs, emails, open ports.
118
116
  whitelist (list, optional): Whitelisted target(s) to scan. Defaults to the same as `targets`.
119
117
  blacklist (list, optional): Blacklisted target(s). Takes ultimate precedence. Defaults to empty.
120
- strict_scope (bool, optional): If True, subdomains of targets are not in-scope.
121
118
  modules (list[str], optional): List of scan modules to enable for the scan. Defaults to empty list.
122
119
  output_modules (list[str], optional): List of output modules to use. Defaults to csv, human, and json.
123
120
  exclude_modules (list[str], optional): List of modules to exclude from the scan.
@@ -234,7 +231,6 @@ class Preset:
234
231
  self.module_dirs = module_dirs
235
232
 
236
233
  # target / whitelist / blacklist
237
- self.strict_scope = strict_scope
238
234
  # these are temporary receptacles until they all get .baked() together
239
235
  self._seeds = set(targets if targets else [])
240
236
  self._whitelist = set(whitelist) if whitelist else whitelist
@@ -245,7 +241,7 @@ class Preset:
245
241
  # "presets" is alias to "include"
246
242
  if presets and include:
247
243
  raise ValueError(
248
- 'Cannot use both "presets" and "include" args at the same time (presets is only an alias to include). Please pick only one :)'
244
+ 'Cannot use both "presets" and "include" args at the same time (presets is an alias to include). Please pick one or the other :)'
249
245
  )
250
246
  if presets and not include:
251
247
  include = presets
@@ -274,6 +270,12 @@ class Preset:
274
270
  raise ValueError("Cannot access target before preset is baked (use ._seeds instead)")
275
271
  return self._target
276
272
 
273
+ @property
274
+ def seeds(self):
275
+ if self._seeds is None:
276
+ raise ValueError("Cannot access target before preset is baked (use ._seeds instead)")
277
+ return self.target.seeds
278
+
277
279
  @property
278
280
  def whitelist(self):
279
281
  if self._target is None:
@@ -353,7 +355,9 @@ class Preset:
353
355
  else:
354
356
  self._whitelist.update(other._whitelist)
355
357
  self._blacklist.update(other._blacklist)
356
- self.strict_scope = self.strict_scope or other.strict_scope
358
+
359
+ # module dirs
360
+ self.module_dirs = self.module_dirs.union(other.module_dirs)
357
361
 
358
362
  # log verbosity
359
363
  if other.silent:
@@ -373,6 +377,9 @@ class Preset:
373
377
  # misc
374
378
  self.force_start = self.force_start | other.force_start
375
379
  self._cli = self._cli | other._cli
380
+ # transfer args
381
+ if other._args is not None:
382
+ self._args = other._args
376
383
 
377
384
  def bake(self, scan=None):
378
385
  """
@@ -436,7 +443,7 @@ class Preset:
436
443
 
437
444
  # disable internal modules if requested
438
445
  for internal_module in baked_preset.internal_modules:
439
- if baked_preset.config.get(internal_module, True) == False:
446
+ if baked_preset.config.get(internal_module, True) is False:
440
447
  baked_preset.exclude_modules.add(internal_module)
441
448
 
442
449
  # enable modules by flag
@@ -531,6 +538,14 @@ class Preset:
531
538
  def web_config(self):
532
539
  return self.core.config.get("web", {})
533
540
 
541
+ @property
542
+ def scope_config(self):
543
+ return self.config.get("scope", {})
544
+
545
+ @property
546
+ def strict_scope(self):
547
+ return self.scope_config.get("strict", False)
548
+
534
549
  def apply_log_level(self, apply_core=False):
535
550
  # silent takes precedence
536
551
  if self.silent:
@@ -629,7 +644,6 @@ class Preset:
629
644
  debug=preset_dict.get("debug", False),
630
645
  silent=preset_dict.get("silent", False),
631
646
  config=preset_dict.get("config"),
632
- strict_scope=preset_dict.get("strict_scope", False),
633
647
  module_dirs=preset_dict.get("module_dirs", []),
634
648
  include=list(preset_dict.get("include", [])),
635
649
  scan_name=preset_dict.get("scan_name"),
@@ -731,6 +745,9 @@ class Preset:
731
745
  """
732
746
  preset_dict = {}
733
747
 
748
+ if self.description:
749
+ preset_dict["description"] = self.description
750
+
734
751
  # config
735
752
  if full_config:
736
753
  config = self.core.config
@@ -744,19 +761,17 @@ class Preset:
744
761
 
745
762
  # scope
746
763
  if include_target:
747
- target = sorted(str(t.data) for t in self.target.seeds)
764
+ target = sorted(self.target.seeds.inputs)
748
765
  whitelist = []
749
766
  if self.target.whitelist is not None:
750
- whitelist = sorted(str(t.data) for t in self.target.whitelist)
751
- blacklist = sorted(str(t.data) for t in self.target.blacklist)
767
+ whitelist = sorted(self.target.whitelist.inputs)
768
+ blacklist = sorted(self.target.blacklist.inputs)
752
769
  if target:
753
770
  preset_dict["target"] = target
754
771
  if whitelist and whitelist != target:
755
772
  preset_dict["whitelist"] = whitelist
756
773
  if blacklist:
757
774
  preset_dict["blacklist"] = blacklist
758
- if self.strict_scope:
759
- preset_dict["strict_scope"] = True
760
775
 
761
776
  # flags + modules
762
777
  if self.require_flags:
@@ -825,7 +840,7 @@ class Preset:
825
840
  else:
826
841
  raise ValidationError(f'Unknown module type "{module}"')
827
842
 
828
- if not module in module_choices:
843
+ if module not in module_choices:
829
844
  raise ValidationError(get_closest_match(module, module_choices, msg=f"{module_type} module"))
830
845
 
831
846
  try:
@@ -838,8 +853,6 @@ class Preset:
838
853
 
839
854
  if module in self.exclude_modules:
840
855
  reason = "the module has been excluded"
841
- if raise_error:
842
- raise ValidationError(f'Unable to add {module_type} module "{module}" because {reason}')
843
856
  return False, reason, {}
844
857
 
845
858
  module_flags = preloaded.get("flags", [])
@@ -870,21 +883,21 @@ class Preset:
870
883
 
871
884
  # validate excluded modules
872
885
  for excluded_module in self.exclude_modules:
873
- if not excluded_module in self.module_loader.all_module_choices:
886
+ if excluded_module not in self.module_loader.all_module_choices:
874
887
  raise ValidationError(
875
888
  get_closest_match(excluded_module, self.module_loader.all_module_choices, msg="module")
876
889
  )
877
890
  # validate excluded flags
878
891
  for excluded_flag in self.exclude_flags:
879
- if not excluded_flag in self.module_loader.flag_choices:
892
+ if excluded_flag not in self.module_loader.flag_choices:
880
893
  raise ValidationError(get_closest_match(excluded_flag, self.module_loader.flag_choices, msg="flag"))
881
894
  # validate required flags
882
895
  for required_flag in self.require_flags:
883
- if not required_flag in self.module_loader.flag_choices:
896
+ if required_flag not in self.module_loader.flag_choices:
884
897
  raise ValidationError(get_closest_match(required_flag, self.module_loader.flag_choices, msg="flag"))
885
898
  # validate flags
886
899
  for flag in self.flags:
887
- if not flag in self.module_loader.flag_choices:
900
+ if flag not in self.module_loader.flag_choices:
888
901
  raise ValidationError(get_closest_match(flag, self.module_loader.flag_choices, msg="flag"))
889
902
 
890
903
  @property
@@ -903,7 +916,7 @@ class Preset:
903
916
 
904
917
  global DEFAULT_PRESETS
905
918
  if DEFAULT_PRESETS is None:
906
- presets = dict()
919
+ presets = {}
907
920
  for ext in ("yml", "yaml"):
908
921
  for preset_path in PRESET_PATH:
909
922
  # for every yaml file
@@ -954,7 +967,7 @@ class Preset:
954
967
  header = ["Preset", "Category", "Description", "# Modules"]
955
968
  if include_modules:
956
969
  header.append("Modules")
957
- for yaml_file, (loaded_preset, category, preset_path, original_file) in self.all_presets.items():
970
+ for (loaded_preset, category, preset_path, original_file) in self.all_presets.values():
958
971
  loaded_preset = loaded_preset.bake()
959
972
  num_modules = f"{len(loaded_preset.scan_modules):,}"
960
973
  row = [loaded_preset.name, category, loaded_preset.description, num_modules]