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
@@ -16,7 +16,7 @@ from bbot.scanner import Scanner, Preset
16
16
  def test_preset_descriptions():
17
17
  # ensure very preset has a description
18
18
  preset = Preset()
19
- for yaml_file, (loaded_preset, category, preset_path, original_filename) in preset.all_presets.items():
19
+ for (loaded_preset, category, preset_path, original_filename) in preset.all_presets.values():
20
20
  assert (
21
21
  loaded_preset.description
22
22
  ), f'Preset "{loaded_preset.name}" at {original_filename} does not have a description.'
@@ -86,12 +86,15 @@ def test_preset_yaml(clean_default_config):
86
86
  debug=False,
87
87
  silent=True,
88
88
  config={"preset_test_asdf": 1},
89
- strict_scope=False,
90
89
  )
91
90
  preset1 = preset1.bake()
92
- assert "evilcorp.com" in preset1.target
91
+ assert "evilcorp.com" in preset1.target.seeds
92
+ assert "evilcorp.ce" not in preset1.target.seeds
93
+ assert "asdf.www.evilcorp.ce" in preset1.target.seeds
93
94
  assert "evilcorp.ce" in preset1.whitelist
95
+ assert "asdf.evilcorp.ce" in preset1.whitelist
94
96
  assert "test.www.evilcorp.ce" in preset1.blacklist
97
+ assert "asdf.test.www.evilcorp.ce" in preset1.blacklist
95
98
  assert "sslcert" in preset1.scan_modules
96
99
  assert preset1.whitelisted("evilcorp.ce")
97
100
  assert preset1.whitelisted("www.evilcorp.ce")
@@ -169,10 +172,17 @@ exclude_flags:
169
172
 
170
173
  def test_preset_scope():
171
174
 
175
+ # test target merging
176
+ scan = Scanner("1.2.3.4", preset=Preset.from_dict({"target": ["evilcorp.com"]}))
177
+ assert {str(h) for h in scan.preset.target.seeds.hosts} == {"1.2.3.4/32", "evilcorp.com"}
178
+ assert {e.data for e in scan.target.seeds} == {"1.2.3.4", "evilcorp.com"}
179
+ assert {e.data for e in scan.target.whitelist} == {"1.2.3.4", "evilcorp.com"}
180
+
172
181
  blank_preset = Preset()
173
182
  blank_preset = blank_preset.bake()
174
- assert not blank_preset.target
175
- assert blank_preset.strict_scope == False
183
+ assert not blank_preset.target.seeds
184
+ assert not blank_preset.target.whitelist
185
+ assert blank_preset.strict_scope is False
176
186
 
177
187
  preset1 = Preset(
178
188
  "evilcorp.com",
@@ -183,13 +193,14 @@ def test_preset_scope():
183
193
  preset1_baked = preset1.bake()
184
194
 
185
195
  # make sure target logic works as expected
186
- assert "evilcorp.com" in preset1_baked.target
187
- assert "asdf.evilcorp.com" in preset1_baked.target
188
- assert "asdf.www.evilcorp.ce" in preset1_baked.target
189
- assert not "evilcorp.ce" in preset1_baked.target
196
+ assert "evilcorp.com" in preset1_baked.target.seeds
197
+ assert "evilcorp.com" not in preset1_baked.target.whitelist
198
+ assert "asdf.evilcorp.com" in preset1_baked.target.seeds
199
+ assert "asdf.evilcorp.com" not in preset1_baked.target.whitelist
200
+ assert "asdf.evilcorp.ce" in preset1_baked.whitelist
190
201
  assert "evilcorp.ce" in preset1_baked.whitelist
191
202
  assert "test.www.evilcorp.ce" in preset1_baked.blacklist
192
- assert not "evilcorp.ce" in preset1_baked.blacklist
203
+ assert "evilcorp.ce" not in preset1_baked.blacklist
193
204
  assert preset1_baked.in_scope("www.evilcorp.ce")
194
205
  assert not preset1_baked.in_scope("evilcorp.com")
195
206
  assert not preset1_baked.in_scope("asdf.test.www.evilcorp.ce")
@@ -205,7 +216,7 @@ def test_preset_scope():
205
216
  "evilcorp.org",
206
217
  whitelist=["evilcorp.de"],
207
218
  blacklist=["test.www.evilcorp.de"],
208
- strict_scope=True,
219
+ config={"scope": {"strict": True}},
209
220
  )
210
221
 
211
222
  preset1.merge(preset3)
@@ -213,20 +224,24 @@ def test_preset_scope():
213
224
  preset1_baked = preset1.bake()
214
225
 
215
226
  # targets should be merged
216
- assert "evilcorp.com" in preset1_baked.target
217
- assert "www.evilcorp.ce" in preset1_baked.target
218
- assert "evilcorp.org" in preset1_baked.target
227
+ assert "evilcorp.com" in preset1_baked.target.seeds
228
+ assert "www.evilcorp.ce" in preset1_baked.target.seeds
229
+ assert "evilcorp.org" in preset1_baked.target.seeds
219
230
  # strict scope is enabled
220
- assert not "asdf.evilcorp.com" in preset1_baked.target
221
- assert not "asdf.www.evilcorp.ce" in preset1_baked.target
231
+ assert "asdf.www.evilcorp.ce" not in preset1_baked.target.seeds
232
+ assert "asdf.evilcorp.org" not in preset1_baked.target.seeds
233
+ assert "asdf.evilcorp.com" not in preset1_baked.target.seeds
234
+ assert "asdf.www.evilcorp.ce" not in preset1_baked.target.seeds
222
235
  assert "evilcorp.ce" in preset1_baked.whitelist
223
236
  assert "evilcorp.de" in preset1_baked.whitelist
224
- assert not "asdf.evilcorp.de" in preset1_baked.whitelist
225
- assert not "asdf.evilcorp.ce" in preset1_baked.whitelist
237
+ assert "asdf.evilcorp.de" not in preset1_baked.whitelist
238
+ assert "asdf.evilcorp.ce" not in preset1_baked.whitelist
226
239
  # blacklist should be merged, strict scope does not apply
240
+ assert "test.www.evilcorp.ce" in preset1_baked.blacklist
241
+ assert "test.www.evilcorp.de" in preset1_baked.blacklist
227
242
  assert "asdf.test.www.evilcorp.ce" in preset1_baked.blacklist
228
243
  assert "asdf.test.www.evilcorp.de" in preset1_baked.blacklist
229
- assert not "asdf.test.www.evilcorp.org" in preset1_baked.blacklist
244
+ assert "asdf.test.www.evilcorp.org" not in preset1_baked.blacklist
230
245
  # only the base domain of evilcorp.de should be in scope
231
246
  assert not preset1_baked.in_scope("evilcorp.com")
232
247
  assert not preset1_baked.in_scope("evilcorp.org")
@@ -259,14 +274,14 @@ def test_preset_scope():
259
274
  }
260
275
  assert preset_whitelist_baked.to_dict(include_target=True) == {
261
276
  "target": ["evilcorp.org"],
262
- "whitelist": ["1.2.3.0/24", "evilcorp.net"],
263
- "blacklist": ["evilcorp.co.uk"],
277
+ "whitelist": ["1.2.3.0/24", "http://evilcorp.net/"],
278
+ "blacklist": ["bob@evilcorp.co.uk", "evilcorp.co.uk:443"],
264
279
  "config": {"modules": {"secretsdb": {"api_key": "deadbeef", "otherthing": "asdf"}}},
265
280
  }
266
281
  assert preset_whitelist_baked.to_dict(include_target=True, redact_secrets=True) == {
267
282
  "target": ["evilcorp.org"],
268
- "whitelist": ["1.2.3.0/24", "evilcorp.net"],
269
- "blacklist": ["evilcorp.co.uk"],
283
+ "whitelist": ["1.2.3.0/24", "http://evilcorp.net/"],
284
+ "blacklist": ["bob@evilcorp.co.uk", "evilcorp.co.uk:443"],
270
285
  "config": {"modules": {"secretsdb": {"otherthing": "asdf"}}},
271
286
  }
272
287
 
@@ -274,7 +289,8 @@ def test_preset_scope():
274
289
  assert not preset_nowhitelist_baked.in_scope("www.evilcorp.de")
275
290
  assert not preset_nowhitelist_baked.in_scope("1.2.3.4/24")
276
291
 
277
- assert "www.evilcorp.org" in preset_whitelist_baked.target
292
+ assert "www.evilcorp.org" in preset_whitelist_baked.target.seeds
293
+ assert "www.evilcorp.org" not in preset_whitelist_baked.target.whitelist
278
294
  assert "1.2.3.4" in preset_whitelist_baked.whitelist
279
295
  assert not preset_whitelist_baked.in_scope("www.evilcorp.org")
280
296
  assert not preset_whitelist_baked.in_scope("www.evilcorp.de")
@@ -287,17 +303,17 @@ def test_preset_scope():
287
303
  assert preset_whitelist_baked.whitelisted("1.2.3.4/28")
288
304
  assert preset_whitelist_baked.whitelisted("1.2.3.4/24")
289
305
 
290
- assert set([e.data for e in preset_nowhitelist_baked.target]) == {"evilcorp.com"}
291
- assert set([e.data for e in preset_whitelist_baked.target]) == {"evilcorp.org"}
292
- assert set([e.data for e in preset_nowhitelist_baked.whitelist]) == {"evilcorp.com"}
293
- assert set([e.data for e in preset_whitelist_baked.whitelist]) == {"1.2.3.0/24", "evilcorp.net"}
306
+ assert {e.data for e in preset_nowhitelist_baked.seeds} == {"evilcorp.com"}
307
+ assert {e.data for e in preset_nowhitelist_baked.whitelist} == {"evilcorp.com"}
308
+ assert {e.data for e in preset_whitelist_baked.seeds} == {"evilcorp.org"}
309
+ assert {e.data for e in preset_whitelist_baked.whitelist} == {"1.2.3.0/24", "http://evilcorp.net/"}
294
310
 
295
311
  preset_nowhitelist.merge(preset_whitelist)
296
312
  preset_nowhitelist_baked = preset_nowhitelist.bake()
297
- assert set([e.data for e in preset_nowhitelist_baked.target]) == {"evilcorp.com", "evilcorp.org"}
298
- assert set([e.data for e in preset_nowhitelist_baked.whitelist]) == {"1.2.3.0/24", "evilcorp.net"}
299
- assert "www.evilcorp.org" in preset_nowhitelist_baked.target
300
- assert "www.evilcorp.com" in preset_nowhitelist_baked.target
313
+ assert {e.data for e in preset_nowhitelist_baked.seeds} == {"evilcorp.com", "evilcorp.org"}
314
+ assert {e.data for e in preset_nowhitelist_baked.whitelist} == {"1.2.3.0/24", "http://evilcorp.net/"}
315
+ assert "www.evilcorp.org" in preset_nowhitelist_baked.seeds
316
+ assert "www.evilcorp.com" in preset_nowhitelist_baked.seeds
301
317
  assert "1.2.3.4" in preset_nowhitelist_baked.whitelist
302
318
  assert not preset_nowhitelist_baked.in_scope("www.evilcorp.org")
303
319
  assert not preset_nowhitelist_baked.in_scope("www.evilcorp.com")
@@ -309,10 +325,12 @@ def test_preset_scope():
309
325
  preset_whitelist = Preset("evilcorp.org", whitelist=["1.2.3.4/24"])
310
326
  preset_whitelist.merge(preset_nowhitelist)
311
327
  preset_whitelist_baked = preset_whitelist.bake()
312
- assert set([e.data for e in preset_whitelist_baked.target]) == {"evilcorp.com", "evilcorp.org"}
313
- assert set([e.data for e in preset_whitelist_baked.whitelist]) == {"1.2.3.0/24"}
314
- assert "www.evilcorp.org" in preset_whitelist_baked.target
315
- assert "www.evilcorp.com" in preset_whitelist_baked.target
328
+ assert {e.data for e in preset_whitelist_baked.seeds} == {"evilcorp.com", "evilcorp.org"}
329
+ assert {e.data for e in preset_whitelist_baked.whitelist} == {"1.2.3.0/24"}
330
+ assert "www.evilcorp.org" in preset_whitelist_baked.seeds
331
+ assert "www.evilcorp.com" in preset_whitelist_baked.seeds
332
+ assert "www.evilcorp.org" not in preset_whitelist_baked.target.whitelist
333
+ assert "www.evilcorp.com" not in preset_whitelist_baked.target.whitelist
316
334
  assert "1.2.3.4" in preset_whitelist_baked.whitelist
317
335
  assert not preset_whitelist_baked.in_scope("www.evilcorp.org")
318
336
  assert not preset_whitelist_baked.in_scope("www.evilcorp.com")
@@ -324,18 +342,18 @@ def test_preset_scope():
324
342
  preset_nowhitelist2 = Preset("evilcorp.de")
325
343
  preset_nowhitelist1_baked = preset_nowhitelist1.bake()
326
344
  preset_nowhitelist2_baked = preset_nowhitelist2.bake()
327
- assert set([e.data for e in preset_nowhitelist1_baked.target]) == {"evilcorp.com"}
328
- assert set([e.data for e in preset_nowhitelist2_baked.target]) == {"evilcorp.de"}
329
- assert set([e.data for e in preset_nowhitelist1_baked.whitelist]) == {"evilcorp.com"}
330
- assert set([e.data for e in preset_nowhitelist2_baked.whitelist]) == {"evilcorp.de"}
345
+ assert {e.data for e in preset_nowhitelist1_baked.seeds} == {"evilcorp.com"}
346
+ assert {e.data for e in preset_nowhitelist2_baked.seeds} == {"evilcorp.de"}
347
+ assert {e.data for e in preset_nowhitelist1_baked.whitelist} == {"evilcorp.com"}
348
+ assert {e.data for e in preset_nowhitelist2_baked.whitelist} == {"evilcorp.de"}
331
349
  preset_nowhitelist1.merge(preset_nowhitelist2)
332
350
  preset_nowhitelist1_baked = preset_nowhitelist1.bake()
333
- assert set([e.data for e in preset_nowhitelist1_baked.target]) == {"evilcorp.com", "evilcorp.de"}
334
- assert set([e.data for e in preset_nowhitelist2_baked.target]) == {"evilcorp.de"}
335
- assert set([e.data for e in preset_nowhitelist1_baked.whitelist]) == {"evilcorp.com", "evilcorp.de"}
336
- assert set([e.data for e in preset_nowhitelist2_baked.whitelist]) == {"evilcorp.de"}
337
- assert "www.evilcorp.com" in preset_nowhitelist1_baked.target
338
- assert "www.evilcorp.de" in preset_nowhitelist1_baked.target
351
+ assert {e.data for e in preset_nowhitelist1_baked.seeds} == {"evilcorp.com", "evilcorp.de"}
352
+ assert {e.data for e in preset_nowhitelist2_baked.seeds} == {"evilcorp.de"}
353
+ assert {e.data for e in preset_nowhitelist1_baked.whitelist} == {"evilcorp.com", "evilcorp.de"}
354
+ assert {e.data for e in preset_nowhitelist2_baked.whitelist} == {"evilcorp.de"}
355
+ assert "www.evilcorp.com" in preset_nowhitelist1_baked.seeds
356
+ assert "www.evilcorp.de" in preset_nowhitelist1_baked.seeds
339
357
  assert "www.evilcorp.com" in preset_nowhitelist1_baked.target.seeds
340
358
  assert "www.evilcorp.de" in preset_nowhitelist1_baked.target.seeds
341
359
  assert "www.evilcorp.com" in preset_nowhitelist1_baked.whitelist
@@ -352,10 +370,10 @@ def test_preset_scope():
352
370
  preset_nowhitelist2.merge(preset_nowhitelist1)
353
371
  preset_nowhitelist1_baked = preset_nowhitelist1.bake()
354
372
  preset_nowhitelist2_baked = preset_nowhitelist2.bake()
355
- assert set([e.data for e in preset_nowhitelist1_baked.target]) == {"evilcorp.com"}
356
- assert set([e.data for e in preset_nowhitelist2_baked.target]) == {"evilcorp.com", "evilcorp.de"}
357
- assert set([e.data for e in preset_nowhitelist1_baked.whitelist]) == {"evilcorp.com"}
358
- assert set([e.data for e in preset_nowhitelist2_baked.whitelist]) == {"evilcorp.com", "evilcorp.de"}
373
+ assert {e.data for e in preset_nowhitelist1_baked.seeds} == {"evilcorp.com"}
374
+ assert {e.data for e in preset_nowhitelist2_baked.seeds} == {"evilcorp.com", "evilcorp.de"}
375
+ assert {e.data for e in preset_nowhitelist1_baked.whitelist} == {"evilcorp.com"}
376
+ assert {e.data for e in preset_nowhitelist2_baked.whitelist} == {"evilcorp.com", "evilcorp.de"}
359
377
 
360
378
 
361
379
  @pytest.mark.asyncio
@@ -369,30 +387,30 @@ async def test_preset_logging():
369
387
 
370
388
  try:
371
389
  silent_preset = Preset(silent=True)
372
- assert silent_preset.silent == True
373
- assert silent_preset.debug == False
374
- assert silent_preset.verbose == False
390
+ assert silent_preset.silent is True
391
+ assert silent_preset.debug is False
392
+ assert silent_preset.verbose is False
375
393
  assert original_log_level == CORE.logger.log_level
376
394
  debug_preset = Preset(debug=True)
377
- assert debug_preset.silent == False
378
- assert debug_preset.debug == True
379
- assert debug_preset.verbose == False
395
+ assert debug_preset.silent is False
396
+ assert debug_preset.debug is True
397
+ assert debug_preset.verbose is False
380
398
  assert original_log_level == CORE.logger.log_level
381
399
  verbose_preset = Preset(verbose=True)
382
- assert verbose_preset.silent == False
383
- assert verbose_preset.debug == False
384
- assert verbose_preset.verbose == True
400
+ assert verbose_preset.silent is False
401
+ assert verbose_preset.debug is False
402
+ assert verbose_preset.verbose is True
385
403
  assert original_log_level == CORE.logger.log_level
386
404
 
387
405
  # test conflicting verbosity levels
388
406
  silent_and_verbose = Preset(silent=True, verbose=True)
389
- assert silent_and_verbose.silent == True
390
- assert silent_and_verbose.debug == False
391
- assert silent_and_verbose.verbose == True
407
+ assert silent_and_verbose.silent is True
408
+ assert silent_and_verbose.debug is False
409
+ assert silent_and_verbose.verbose is True
392
410
  baked = silent_and_verbose.bake()
393
- assert baked.silent == True
394
- assert baked.debug == False
395
- assert baked.verbose == False
411
+ assert baked.silent is True
412
+ assert baked.debug is False
413
+ assert baked.verbose is False
396
414
  assert baked.core.logger.log_level == original_log_level
397
415
  baked = silent_and_verbose.bake(scan=scan)
398
416
  assert baked.core.logger.log_level == logging.CRITICAL
@@ -402,13 +420,13 @@ async def test_preset_logging():
402
420
  assert CORE.logger.log_level == original_log_level
403
421
 
404
422
  silent_and_debug = Preset(silent=True, debug=True)
405
- assert silent_and_debug.silent == True
406
- assert silent_and_debug.debug == True
407
- assert silent_and_debug.verbose == False
423
+ assert silent_and_debug.silent is True
424
+ assert silent_and_debug.debug is True
425
+ assert silent_and_debug.verbose is False
408
426
  baked = silent_and_debug.bake()
409
- assert baked.silent == True
410
- assert baked.debug == False
411
- assert baked.verbose == False
427
+ assert baked.silent is True
428
+ assert baked.debug is False
429
+ assert baked.verbose is False
412
430
  assert baked.core.logger.log_level == original_log_level
413
431
  baked = silent_and_debug.bake(scan=scan)
414
432
  assert baked.core.logger.log_level == logging.CRITICAL
@@ -418,13 +436,13 @@ async def test_preset_logging():
418
436
  assert CORE.logger.log_level == original_log_level
419
437
 
420
438
  debug_and_verbose = Preset(verbose=True, debug=True)
421
- assert debug_and_verbose.silent == False
422
- assert debug_and_verbose.debug == True
423
- assert debug_and_verbose.verbose == True
439
+ assert debug_and_verbose.silent is False
440
+ assert debug_and_verbose.debug is True
441
+ assert debug_and_verbose.verbose is True
424
442
  baked = debug_and_verbose.bake()
425
- assert baked.silent == False
426
- assert baked.debug == True
427
- assert baked.verbose == False
443
+ assert baked.silent is False
444
+ assert baked.debug is True
445
+ assert baked.verbose is False
428
446
  assert baked.core.logger.log_level == original_log_level
429
447
  baked = debug_and_verbose.bake(scan=scan)
430
448
  assert baked.core.logger.log_level == logging.DEBUG
@@ -434,13 +452,13 @@ async def test_preset_logging():
434
452
  assert CORE.logger.log_level == original_log_level
435
453
 
436
454
  all_preset = Preset(verbose=True, debug=True, silent=True)
437
- assert all_preset.silent == True
438
- assert all_preset.debug == True
439
- assert all_preset.verbose == True
455
+ assert all_preset.silent is True
456
+ assert all_preset.debug is True
457
+ assert all_preset.verbose is True
440
458
  baked = all_preset.bake()
441
- assert baked.silent == True
442
- assert baked.debug == False
443
- assert baked.verbose == False
459
+ assert baked.silent is True
460
+ assert baked.debug is False
461
+ assert baked.verbose is False
444
462
  assert baked.core.logger.log_level == original_log_level
445
463
  baked = all_preset.bake(scan=scan)
446
464
  assert baked.core.logger.log_level == logging.CRITICAL
@@ -527,12 +545,26 @@ def test_preset_module_resolution(clean_default_config):
527
545
  assert set(preset.scan_modules) == {"wayback"}
528
546
 
529
547
  # modules + module exclusions
530
- with pytest.raises(ValidationError) as error:
531
- preset = Preset(exclude_modules=["sslcert"], modules=["sslcert", "wappalyzer", "wayback"]).bake()
532
- assert str(error.value) == 'Unable to add scan module "sslcert" because the module has been excluded'
548
+ preset = Preset(exclude_modules=["sslcert"], modules=["sslcert", "wappalyzer", "wayback"]).bake()
549
+ baked_preset = preset.bake()
550
+ assert baked_preset.modules == {
551
+ "wayback",
552
+ "cloudcheck",
553
+ "python",
554
+ "json",
555
+ "speculate",
556
+ "dnsresolve",
557
+ "aggregate",
558
+ "excavate",
559
+ "txt",
560
+ "httpx",
561
+ "csv",
562
+ "wappalyzer",
563
+ }
533
564
 
534
565
 
535
- def test_preset_module_loader():
566
+ @pytest.mark.asyncio
567
+ async def test_preset_module_loader():
536
568
  custom_module_dir = bbot_test_dir / "custom_module_dir"
537
569
  custom_module_dir_2 = custom_module_dir / "asdf"
538
570
  custom_output_module_dir = custom_module_dir / "output"
@@ -640,6 +672,43 @@ class TestModule4(BaseModule):
640
672
  # reset module_loader
641
673
  preset2.module_loader.__init__()
642
674
 
675
+ # custom module dir via preset
676
+ custom_module_dir_3 = bbot_test_dir / "custom_module_dir_3"
677
+ custom_module_dir_3.mkdir(exist_ok=True, parents=True)
678
+ custom_module_5 = custom_module_dir_3 / "testmodule5.py"
679
+ with open(custom_module_5, "w") as f:
680
+ f.write(
681
+ """
682
+ from bbot.modules.base import BaseModule
683
+
684
+ class TestModule5(BaseModule):
685
+ watched_events = ["TECHNOLOGY"]
686
+ produced_events = ["FINDING"]
687
+ """
688
+ )
689
+
690
+ preset = Preset.from_yaml_string(
691
+ """
692
+ modules:
693
+ - testmodule5
694
+ """
695
+ )
696
+ # should fail
697
+ with pytest.raises(ValidationError):
698
+ scan = Scanner(preset=preset)
699
+
700
+ preset = Preset.from_yaml_string(
701
+ f"""
702
+ module_dirs:
703
+ - {custom_module_dir_3}
704
+ modules:
705
+ - testmodule5
706
+ """
707
+ )
708
+ scan = Scanner(preset=preset)
709
+ await scan._prep()
710
+ assert "testmodule5" in scan.modules
711
+
643
712
 
644
713
  def test_preset_include():
645
714
 
@@ -827,9 +896,9 @@ def test_preset_require_exclude():
827
896
  dnsbrute_flags = preset.preloaded_module("dnsbrute").get("flags", [])
828
897
  assert "subdomain-enum" in dnsbrute_flags
829
898
  assert "active" in dnsbrute_flags
830
- assert not "passive" in dnsbrute_flags
899
+ assert "passive" not in dnsbrute_flags
831
900
  assert "aggressive" in dnsbrute_flags
832
- assert not "safe" in dnsbrute_flags
901
+ assert "safe" not in dnsbrute_flags
833
902
  assert "dnsbrute" in [x[0] for x in module_flags]
834
903
  assert "certspotter" in [x[0] for x in module_flags]
835
904
  assert "c99" in [x[0] for x in module_flags]
@@ -843,7 +912,7 @@ def test_preset_require_exclude():
843
912
  assert len(preset.modules) > 25
844
913
  module_flags = list(get_module_flags(preset))
845
914
  assert "chaos" in [x[0] for x in module_flags]
846
- assert not "httpx" in [x[0] for x in module_flags]
915
+ assert "httpx" not in [x[0] for x in module_flags]
847
916
  assert all("passive" in flags for module, flags in module_flags)
848
917
  assert not any("active" in flags for module, flags in module_flags)
849
918
  assert any("safe" in flags for module, flags in module_flags)
@@ -854,7 +923,7 @@ def test_preset_require_exclude():
854
923
  assert len(preset.modules) > 25
855
924
  module_flags = list(get_module_flags(preset))
856
925
  assert "chaos" in [x[0] for x in module_flags]
857
- assert not "httpx" in [x[0] for x in module_flags]
926
+ assert "httpx" not in [x[0] for x in module_flags]
858
927
  assert all("passive" in flags for module, flags in module_flags)
859
928
  assert not any("active" in flags for module, flags in module_flags)
860
929
  assert any("safe" in flags for module, flags in module_flags)
@@ -864,7 +933,7 @@ def test_preset_require_exclude():
864
933
  preset = Preset(flags=["subdomain-enum"], exclude_modules=["dnsbrute"]).bake()
865
934
  assert len(preset.modules) > 25
866
935
  module_flags = list(get_module_flags(preset))
867
- assert not "dnsbrute" in [x[0] for x in module_flags]
936
+ assert "dnsbrute" not in [x[0] for x in module_flags]
868
937
  assert "httpx" in [x[0] for x in module_flags]
869
938
  assert any("passive" in flags for module, flags in module_flags)
870
939
  assert any("active" in flags for module, flags in module_flags)
@@ -875,7 +944,7 @@ def test_preset_require_exclude():
875
944
  preset = Preset(flags=["subdomain-enum"], require_flags=["safe", "passive"]).bake()
876
945
  assert len(preset.modules) > 25
877
946
  module_flags = list(get_module_flags(preset))
878
- assert not "dnsbrute" in [x[0] for x in module_flags]
947
+ assert "dnsbrute" not in [x[0] for x in module_flags]
879
948
  assert all("passive" in flags and "safe" in flags for module, flags in module_flags)
880
949
  assert all("active" not in flags and "aggressive" not in flags for module, flags in module_flags)
881
950
  assert not any("active" in flags for module, flags in module_flags)
@@ -885,7 +954,7 @@ def test_preset_require_exclude():
885
954
  preset = Preset(flags=["subdomain-enum"], exclude_flags=["aggressive", "active"]).bake()
886
955
  assert len(preset.modules) > 25
887
956
  module_flags = list(get_module_flags(preset))
888
- assert not "dnsbrute" in [x[0] for x in module_flags]
957
+ assert "dnsbrute" not in [x[0] for x in module_flags]
889
958
  assert all("passive" in flags and "safe" in flags for module, flags in module_flags)
890
959
  assert all("active" not in flags and "aggressive" not in flags for module, flags in module_flags)
891
960
  assert not any("active" in flags for module, flags in module_flags)
@@ -895,10 +964,29 @@ def test_preset_require_exclude():
895
964
  preset = Preset(flags=["subdomain-enum"], exclude_modules=["dnsbrute", "c99"]).bake()
896
965
  assert len(preset.modules) > 25
897
966
  module_flags = list(get_module_flags(preset))
898
- assert not "dnsbrute" in [x[0] for x in module_flags]
967
+ assert "dnsbrute" not in [x[0] for x in module_flags]
899
968
  assert "certspotter" in [x[0] for x in module_flags]
900
- assert not "c99" in [x[0] for x in module_flags]
969
+ assert "c99" not in [x[0] for x in module_flags]
901
970
  assert any("passive" in flags for module, flags in module_flags)
902
971
  assert any("active" in flags for module, flags in module_flags)
903
972
  assert any("safe" in flags for module, flags in module_flags)
904
973
  assert any("aggressive" in flags for module, flags in module_flags)
974
+
975
+
976
+ @pytest.mark.asyncio
977
+ async def test_preset_output_dir():
978
+ output_dir = bbot_test_dir / "preset_output_dir"
979
+ preset = Preset.from_yaml_string(
980
+ f"""
981
+ output_dir: {output_dir}
982
+ scan_name: bbot_test
983
+ """
984
+ )
985
+ scan = Scanner(preset=preset)
986
+ await scan.async_start_without_generator()
987
+ scan_dir = output_dir / "bbot_test"
988
+ assert scan_dir.is_dir()
989
+ output_file = scan_dir / "output.txt"
990
+ assert output_file.is_file()
991
+
992
+ shutil.rmtree(output_dir, ignore_errors=True)
@@ -84,6 +84,10 @@ def test_python_api_sync():
84
84
  def test_python_api_validation():
85
85
  from bbot.scanner import Scanner, Preset
86
86
 
87
+ # invalid target
88
+ with pytest.raises(ValidationError) as error:
89
+ Scanner("asdf:::asdf")
90
+ assert str(error.value) == 'Unable to autodetect event type from "asdf:::asdf"'
87
91
  # invalid module
88
92
  with pytest.raises(ValidationError) as error:
89
93
  Scanner(modules=["asdf"])
@@ -122,7 +126,8 @@ def test_python_api_validation():
122
126
  assert str(error.value) == 'Preset must be of type Preset, not "str"'
123
127
  # include nonexistent preset
124
128
  with pytest.raises(ValidationError) as error:
125
- Preset(include=["asdf"])
129
+ Preset(include=["nonexistent"])
126
130
  assert (
127
- str(error.value) == 'Could not find preset at "asdf" - file does not exist. Use -lp to list available presets'
131
+ str(error.value)
132
+ == 'Could not find preset at "nonexistent" - file does not exist. Use -lp to list available presets'
128
133
  )
@@ -91,7 +91,7 @@ def test_ip_regexes():
91
91
  ip == "2001:db8::1/128" and event_type == "IP_RANGE"
92
92
  ), f"Event type for IP_ADDRESS {ip} was not properly detected"
93
93
  else:
94
- matches = list(r.match(ip) for r in ip_address_regexes)
94
+ matches = [r.match(ip) for r in ip_address_regexes]
95
95
  assert any(matches), f"Good IP ADDRESS {ip} did not match regexes"
96
96
 
97
97
 
@@ -138,7 +138,7 @@ def test_ip_range_regexes():
138
138
  pytest.fail(f"BAD IP_RANGE: {bad_ip_range} raised unknown error: {e}: {traceback.format_exc()}")
139
139
 
140
140
  for good_ip_range in good_ip_ranges:
141
- matches = list(r.match(good_ip_range) for r in ip_range_regexes)
141
+ matches = [r.match(good_ip_range) for r in ip_range_regexes]
142
142
  assert any(matches), f"Good IP_RANGE {good_ip_range} did not match regexes"
143
143
 
144
144
 
@@ -191,7 +191,7 @@ def test_dns_name_regexes():
191
191
  pytest.fail(f"BAD DNS NAME: {dns} raised unknown error: {e}")
192
192
 
193
193
  for dns in good_dns:
194
- matches = list(r.match(dns) for r in dns_name_regexes)
194
+ matches = [r.match(dns) for r in dns_name_regexes]
195
195
  assert any(matches), f"Good DNS_NAME {dns} did not match regexes"
196
196
  event_type, _ = get_event_type(dns)
197
197
  if not event_type == "DNS_NAME":
@@ -253,7 +253,7 @@ def test_open_port_regexes():
253
253
  pytest.fail(f"BAD OPEN_TCP_PORT: {open_port} raised unknown error: {e}")
254
254
 
255
255
  for open_port in good_ports:
256
- matches = list(r.match(open_port) for r in open_port_regexes)
256
+ matches = [r.match(open_port) for r in open_port_regexes]
257
257
  assert any(matches), f"Good OPEN_TCP_PORT {open_port} did not match regexes"
258
258
  event_type, _ = get_event_type(open_port)
259
259
  assert event_type == "OPEN_TCP_PORT"
@@ -318,7 +318,7 @@ def test_url_regexes():
318
318
  pytest.fail(f"BAD URL: {bad_url} raised unknown error: {e}: {traceback.format_exc()}")
319
319
 
320
320
  for good_url in good_urls:
321
- matches = list(r.match(good_url) for r in url_regexes)
321
+ matches = [r.match(good_url) for r in url_regexes]
322
322
  assert any(matches), f"Good URL {good_url} did not match regexes"
323
323
  assert (
324
324
  get_event_type(good_url)[0] == "URL_UNVERIFIED"
@@ -372,3 +372,33 @@ async def test_regex_helper():
372
372
  assert matches.count(s) == 2
373
373
 
374
374
  await scan._cleanup()
375
+
376
+ # test yara hostname extractor helper
377
+ scan = Scanner("evilcorp.com", "www.evilcorp.net", "evilcorp.co.uk")
378
+ host_blob = """
379
+ https://evilcorp.com/
380
+ https://asdf.evilcorp.com/
381
+ https://asdf.www.evilcorp.net/
382
+ https://asdf.www.evilcorp.co.uk/
383
+ https://asdf.www.evilcorp.com/
384
+ https://asdf.www.evilcorp.com/
385
+ https://test.api.www.evilcorp.net/
386
+ """
387
+ extracted = await scan.extract_in_scope_hostnames(host_blob)
388
+ assert extracted == {
389
+ "evilcorp.co.uk",
390
+ "evilcorp.com",
391
+ "www.evilcorp.com",
392
+ "asdf.evilcorp.com",
393
+ "asdf.www.evilcorp.com",
394
+ "www.evilcorp.net",
395
+ "api.www.evilcorp.net",
396
+ "asdf.www.evilcorp.net",
397
+ "test.api.www.evilcorp.net",
398
+ "asdf.www.evilcorp.co.uk",
399
+ "www.evilcorp.co.uk",
400
+ }
401
+
402
+ scan = Scanner()
403
+ extracted = await scan.extract_in_scope_hostnames(host_blob)
404
+ assert extracted == set()