bbot 2.0.1.4720rc0__py3-none-any.whl → 2.3.0.5401rc0__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 (278) 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 +12 -10
  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 +20 -21
  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 +29 -12
  86. bbot/modules/internal/dnsresolve.py +22 -22
  87. bbot/modules/internal/excavate.py +97 -59
  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 +8 -11
  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 +18 -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 -2
  146. bbot/presets/spider.yml +4 -0
  147. bbot/presets/subdomain-enum.yml +7 -7
  148. bbot/presets/web/dotnet-audit.yml +0 -1
  149. bbot/scanner/manager.py +5 -16
  150. bbot/scanner/preset/args.py +46 -26
  151. bbot/scanner/preset/environ.py +7 -2
  152. bbot/scanner/preset/path.py +7 -4
  153. bbot/scanner/preset/preset.py +36 -23
  154. bbot/scanner/scanner.py +172 -62
  155. bbot/scanner/target.py +236 -434
  156. bbot/scripts/docs.py +1 -1
  157. bbot/test/bbot_fixtures.py +13 -3
  158. bbot/test/conftest.py +132 -100
  159. bbot/test/fastapi_test.py +17 -0
  160. bbot/test/owasp_mastg.apk +0 -0
  161. bbot/test/run_tests.sh +4 -4
  162. bbot/test/test.conf +2 -0
  163. bbot/test/test_step_1/test__module__tests.py +0 -1
  164. bbot/test/test_step_1/test_bbot_fastapi.py +79 -0
  165. bbot/test/test_step_1/test_bloom_filter.py +2 -1
  166. bbot/test/test_step_1/test_cli.py +138 -64
  167. bbot/test/test_step_1/test_dns.py +61 -27
  168. bbot/test/test_step_1/test_engine.py +17 -19
  169. bbot/test/test_step_1/test_events.py +183 -30
  170. bbot/test/test_step_1/test_helpers.py +64 -29
  171. bbot/test/test_step_1/test_manager_deduplication.py +1 -1
  172. bbot/test/test_step_1/test_manager_scope_accuracy.py +333 -330
  173. bbot/test/test_step_1/test_modules_basic.py +68 -70
  174. bbot/test/test_step_1/test_presets.py +183 -100
  175. bbot/test/test_step_1/test_python_api.py +7 -2
  176. bbot/test/test_step_1/test_regexes.py +35 -5
  177. bbot/test/test_step_1/test_scan.py +39 -5
  178. bbot/test/test_step_1/test_scope.py +4 -3
  179. bbot/test/test_step_1/test_target.py +242 -145
  180. bbot/test/test_step_1/test_web.py +14 -10
  181. bbot/test/test_step_2/module_tests/base.py +15 -7
  182. bbot/test/test_step_2/module_tests/test_module_anubisdb.py +1 -1
  183. bbot/test/test_step_2/module_tests/test_module_apkpure.py +71 -0
  184. bbot/test/test_step_2/module_tests/test_module_asset_inventory.py +0 -1
  185. bbot/test/test_step_2/module_tests/test_module_azure_realm.py +1 -1
  186. bbot/test/test_step_2/module_tests/test_module_baddns.py +6 -6
  187. bbot/test/test_step_2/module_tests/test_module_baddns_direct.py +62 -0
  188. bbot/test/test_step_2/module_tests/test_module_bevigil.py +29 -2
  189. bbot/test/test_step_2/module_tests/test_module_binaryedge.py +4 -2
  190. bbot/test/test_step_2/module_tests/test_module_bucket_amazon.py +2 -2
  191. bbot/test/test_step_2/module_tests/test_module_bucket_azure.py +1 -1
  192. bbot/test/test_step_2/module_tests/test_module_bufferoverrun.py +35 -0
  193. bbot/test/test_step_2/module_tests/test_module_builtwith.py +2 -2
  194. bbot/test/test_step_2/module_tests/test_module_bypass403.py +1 -1
  195. bbot/test/test_step_2/module_tests/test_module_c99.py +126 -0
  196. bbot/test/test_step_2/module_tests/test_module_censys.py +4 -1
  197. bbot/test/test_step_2/module_tests/test_module_cloudcheck.py +4 -0
  198. bbot/test/test_step_2/module_tests/test_module_code_repository.py +11 -1
  199. bbot/test/test_step_2/module_tests/test_module_columbus.py +1 -1
  200. bbot/test/test_step_2/module_tests/test_module_credshed.py +3 -3
  201. bbot/test/test_step_2/module_tests/test_module_dastardly.py +2 -1
  202. bbot/test/test_step_2/module_tests/test_module_dehashed.py +2 -2
  203. bbot/test/test_step_2/module_tests/test_module_digitorus.py +1 -1
  204. bbot/test/test_step_2/module_tests/test_module_discord.py +1 -1
  205. bbot/test/test_step_2/module_tests/test_module_dnsbimi.py +103 -0
  206. bbot/test/test_step_2/module_tests/test_module_dnsbrute.py +9 -10
  207. bbot/test/test_step_2/module_tests/test_module_dnsbrute_mutations.py +1 -2
  208. bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py +1 -2
  209. bbot/test/test_step_2/module_tests/test_module_dnsdumpster.py +4 -4
  210. bbot/test/test_step_2/module_tests/test_module_dnstlsrpt.py +64 -0
  211. bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py +0 -8
  212. bbot/test/test_step_2/module_tests/test_module_excavate.py +28 -48
  213. bbot/test/test_step_2/module_tests/test_module_extractous.py +54 -0
  214. bbot/test/test_step_2/module_tests/test_module_ffuf_shortnames.py +1 -1
  215. bbot/test/test_step_2/module_tests/test_module_filedownload.py +14 -14
  216. bbot/test/test_step_2/module_tests/test_module_git_clone.py +2 -2
  217. bbot/test/test_step_2/module_tests/test_module_github_org.py +19 -8
  218. bbot/test/test_step_2/module_tests/test_module_github_workflows.py +1 -1
  219. bbot/test/test_step_2/module_tests/test_module_gitlab.py +9 -4
  220. bbot/test/test_step_2/module_tests/test_module_google_playstore.py +83 -0
  221. bbot/test/test_step_2/module_tests/test_module_gowitness.py +4 -6
  222. bbot/test/test_step_2/module_tests/test_module_host_header.py +1 -1
  223. bbot/test/test_step_2/module_tests/test_module_http.py +4 -4
  224. bbot/test/test_step_2/module_tests/test_module_httpx.py +10 -8
  225. bbot/test/test_step_2/module_tests/test_module_hunterio.py +68 -4
  226. bbot/test/test_step_2/module_tests/test_module_jadx.py +55 -0
  227. bbot/test/test_step_2/module_tests/test_module_json.py +22 -9
  228. bbot/test/test_step_2/module_tests/test_module_leakix.py +7 -3
  229. bbot/test/test_step_2/module_tests/test_module_mysql.py +76 -0
  230. bbot/test/test_step_2/module_tests/test_module_myssl.py +1 -1
  231. bbot/test/test_step_2/module_tests/test_module_neo4j.py +1 -1
  232. bbot/test/test_step_2/module_tests/test_module_newsletters.py +16 -16
  233. bbot/test/test_step_2/module_tests/test_module_ntlm.py +8 -7
  234. bbot/test/test_step_2/module_tests/test_module_oauth.py +1 -1
  235. bbot/test/test_step_2/module_tests/test_module_otx.py +1 -1
  236. bbot/test/test_step_2/module_tests/test_module_paramminer_cookies.py +1 -2
  237. bbot/test/test_step_2/module_tests/test_module_paramminer_getparams.py +0 -6
  238. bbot/test/test_step_2/module_tests/test_module_paramminer_headers.py +2 -9
  239. bbot/test/test_step_2/module_tests/test_module_passivetotal.py +3 -1
  240. bbot/test/test_step_2/module_tests/test_module_pgp.py +2 -2
  241. bbot/test/test_step_2/module_tests/test_module_portscan.py +9 -8
  242. bbot/test/test_step_2/module_tests/test_module_postgres.py +74 -0
  243. bbot/test/test_step_2/module_tests/test_module_postman.py +84 -253
  244. bbot/test/test_step_2/module_tests/test_module_postman_download.py +439 -0
  245. bbot/test/test_step_2/module_tests/test_module_rapiddns.py +93 -1
  246. bbot/test/test_step_2/module_tests/test_module_shodan_dns.py +20 -1
  247. bbot/test/test_step_2/module_tests/test_module_sitedossier.py +2 -2
  248. bbot/test/test_step_2/module_tests/test_module_smuggler.py +14 -14
  249. bbot/test/test_step_2/module_tests/test_module_social.py +11 -1
  250. bbot/test/test_step_2/module_tests/test_module_speculate.py +4 -8
  251. bbot/test/test_step_2/module_tests/test_module_splunk.py +4 -4
  252. bbot/test/test_step_2/module_tests/test_module_sqlite.py +18 -0
  253. bbot/test/test_step_2/module_tests/test_module_sslcert.py +1 -1
  254. bbot/test/test_step_2/module_tests/test_module_stdout.py +5 -3
  255. bbot/test/test_step_2/module_tests/test_module_subdomaincenter.py +1 -1
  256. bbot/test/test_step_2/module_tests/test_module_subdomainradar.py +208 -0
  257. bbot/test/test_step_2/module_tests/test_module_subdomains.py +1 -1
  258. bbot/test/test_step_2/module_tests/test_module_teams.py +8 -6
  259. bbot/test/test_step_2/module_tests/test_module_telerik.py +1 -1
  260. bbot/test/test_step_2/module_tests/test_module_trufflehog.py +317 -14
  261. bbot/test/test_step_2/module_tests/test_module_viewdns.py +1 -1
  262. bbot/test/test_step_2/module_tests/test_module_wayback.py +1 -1
  263. bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py +2 -2
  264. bbot/wordlists/devops_mutations.txt +1 -1
  265. bbot/wordlists/ffuf_shortname_candidates.txt +1 -1
  266. bbot/wordlists/nameservers.txt +1 -1
  267. bbot/wordlists/paramminer_headers.txt +1 -1
  268. bbot/wordlists/paramminer_parameters.txt +1 -1
  269. bbot/wordlists/raft-small-extensions-lowercase_CLEANED.txt +1 -1
  270. bbot/wordlists/valid_url_schemes.txt +1 -1
  271. {bbot-2.0.1.4720rc0.dist-info → bbot-2.3.0.5401rc0.dist-info}/METADATA +48 -18
  272. bbot-2.3.0.5401rc0.dist-info/RECORD +421 -0
  273. {bbot-2.0.1.4720rc0.dist-info → bbot-2.3.0.5401rc0.dist-info}/WHEEL +1 -1
  274. bbot/modules/unstructured.py +0 -163
  275. bbot/test/test_step_2/module_tests/test_module_unstructured.py +0 -102
  276. bbot-2.0.1.4720rc0.dist-info/RECORD +0 -387
  277. {bbot-2.0.1.4720rc0.dist-info → bbot-2.3.0.5401rc0.dist-info}/LICENSE +0 -0
  278. {bbot-2.0.1.4720rc0.dist-info → bbot-2.3.0.5401rc0.dist-info}/entry_points.txt +0 -0
@@ -23,7 +23,7 @@ async def test_dns_engine(bbot_scanner):
23
23
  )
24
24
  result = await scan.helpers.resolve("one.one.one.one")
25
25
  assert "1.1.1.1" in result
26
- assert not "2606:4700:4700::1111" in result
26
+ assert "2606:4700:4700::1111" not in result
27
27
 
28
28
  results = [_ async for _ in scan.helpers.resolve_batch(("one.one.one.one", "1.1.1.1"))]
29
29
  pass_1 = False
@@ -85,12 +85,12 @@ async def test_dns_resolution(bbot_scanner):
85
85
  for answer in answers:
86
86
  responses += list(extract_targets(answer))
87
87
  assert ("A", "1.1.1.1") in responses
88
- assert not ("AAAA", "2606:4700:4700::1111") in responses
88
+ assert ("AAAA", "2606:4700:4700::1111") not in responses
89
89
  answers, errors = await dnsengine.resolve_raw("one.one.one.one", type="AAAA")
90
90
  responses = []
91
91
  for answer in answers:
92
92
  responses += list(extract_targets(answer))
93
- assert not ("A", "1.1.1.1") in responses
93
+ assert ("A", "1.1.1.1") not in responses
94
94
  assert ("AAAA", "2606:4700:4700::1111") in responses
95
95
  answers, errors = await dnsengine.resolve_raw("1.1.1.1")
96
96
  responses = []
@@ -106,13 +106,14 @@ async def test_dns_resolution(bbot_scanner):
106
106
  assert "2606:4700:4700::1111" in await dnsengine.resolve("one.one.one.one", type="AAAA")
107
107
  assert "one.one.one.one" in await dnsengine.resolve("1.1.1.1")
108
108
  for rdtype in ("NS", "SOA", "MX", "TXT"):
109
- assert len(await dnsengine.resolve("google.com", type=rdtype)) > 0
109
+ results = await dnsengine.resolve("google.com", type=rdtype)
110
+ assert len(results) > 0
110
111
 
111
112
  # batch resolution
112
113
  batch_results = [r async for r in dnsengine.resolve_batch(["1.1.1.1", "one.one.one.one"])]
113
114
  assert len(batch_results) == 2
114
115
  batch_results = dict(batch_results)
115
- assert any([x in batch_results["one.one.one.one"] for x in ("1.1.1.1", "1.0.0.1")])
116
+ assert any(x in batch_results["one.one.one.one"] for x in ("1.1.1.1", "1.0.0.1"))
116
117
  assert "one.one.one.one" in batch_results["1.1.1.1"]
117
118
 
118
119
  # custom batch resolution
@@ -140,11 +141,11 @@ async def test_dns_resolution(bbot_scanner):
140
141
  assert hash(("1.1.1.1", "PTR")) in dnsengine._dns_cache
141
142
  await dnsengine.resolve("one.one.one.one", type="A")
142
143
  assert hash(("one.one.one.one", "A")) in dnsengine._dns_cache
143
- assert not hash(("one.one.one.one", "AAAA")) in dnsengine._dns_cache
144
+ assert hash(("one.one.one.one", "AAAA")) not in dnsengine._dns_cache
144
145
  dnsengine._dns_cache.clear()
145
146
  await dnsengine.resolve("one.one.one.one", type="AAAA")
146
147
  assert hash(("one.one.one.one", "AAAA")) in dnsengine._dns_cache
147
- assert not hash(("one.one.one.one", "A")) in dnsengine._dns_cache
148
+ assert hash(("one.one.one.one", "A")) not in dnsengine._dns_cache
148
149
 
149
150
  await dnsengine._shutdown()
150
151
 
@@ -164,7 +165,7 @@ async def test_dns_resolution(bbot_scanner):
164
165
  assert "A" in resolved_hosts_event1.raw_dns_records
165
166
  assert "AAAA" in resolved_hosts_event1.raw_dns_records
166
167
  assert "a-record" in resolved_hosts_event1.tags
167
- assert not "a-record" in resolved_hosts_event2.tags
168
+ assert "a-record" not in resolved_hosts_event2.tags
168
169
 
169
170
  scan2 = bbot_scanner("evilcorp.com", config={"dns": {"minimal": False}})
170
171
  await scan2.helpers.dns._mock_dns(
@@ -184,7 +185,6 @@ async def test_dns_resolution(bbot_scanner):
184
185
 
185
186
  @pytest.mark.asyncio
186
187
  async def test_wildcards(bbot_scanner):
187
-
188
188
  scan = bbot_scanner("1.1.1.1")
189
189
  helpers = scan.helpers
190
190
 
@@ -197,7 +197,7 @@ async def test_wildcards(bbot_scanner):
197
197
  assert len(dnsengine._wildcard_cache) == len(all_rdtypes) + (len(all_rdtypes) - 2)
198
198
  for rdtype in all_rdtypes:
199
199
  assert hash(("github.io", rdtype)) in dnsengine._wildcard_cache
200
- if not rdtype in ("A", "AAAA"):
200
+ if rdtype not in ("A", "AAAA"):
201
201
  assert hash(("asdf.github.io", rdtype)) in dnsengine._wildcard_cache
202
202
  assert "github.io" in wildcard_domains
203
203
  assert "A" in wildcard_domains["github.io"]
@@ -263,7 +263,7 @@ def custom_lookup(query, rdtype):
263
263
  await scan.helpers.dns._mock_dns(mock_data, custom_lookup_fn=custom_lookup)
264
264
 
265
265
  events = [e async for e in scan.async_start()]
266
- assert len(events) == 11
266
+ assert len(events) == 12
267
267
  assert len([e for e in events if e.type == "DNS_NAME"]) == 5
268
268
  assert len([e for e in events if e.type == "RAW_DNS_RECORD"]) == 4
269
269
  assert sorted([e.data for e in events if e.type == "DNS_NAME"]) == [
@@ -320,7 +320,7 @@ def custom_lookup(query, rdtype):
320
320
  await scan.helpers.dns._mock_dns(mock_data, custom_lookup_fn=custom_lookup)
321
321
 
322
322
  events = [e async for e in scan.async_start()]
323
- assert len(events) == 11
323
+ assert len(events) == 12
324
324
  assert len([e for e in events if e.type == "DNS_NAME"]) == 5
325
325
  assert len([e for e in events if e.type == "RAW_DNS_RECORD"]) == 4
326
326
  assert sorted([e.data for e in events if e.type == "DNS_NAME"]) == [
@@ -418,7 +418,7 @@ def custom_lookup(query, rdtype):
418
418
 
419
419
  events = [e async for e in scan.async_start()]
420
420
 
421
- assert len(events) == 10
421
+ assert len(events) == 11
422
422
  assert len([e for e in events if e.type == "DNS_NAME"]) == 5
423
423
  assert len([e for e in events if e.type == "RAW_DNS_RECORD"]) == 4
424
424
  assert sorted([e.data for e in events if e.type == "DNS_NAME"]) == [
@@ -546,8 +546,8 @@ def custom_lookup(query, rdtype):
546
546
  )
547
547
  await scan2.ingress_module.queue_event(other_event, {})
548
548
  events = [e async for e in scan2.async_start()]
549
- assert len(events) == 3
550
- assert 1 == len([e for e in events if e.type == "SCAN"])
549
+ assert len(events) == 4
550
+ assert 2 == len([e for e in events if e.type == "SCAN"])
551
551
  unmodified_wildcard_events = [
552
552
  e for e in events if e.type == "DNS_NAME" and e.data == "asdfl.gashdgkjsadgsdf.github.io"
553
553
  ]
@@ -592,8 +592,8 @@ def custom_lookup(query, rdtype):
592
592
  )
593
593
  await scan2.ingress_module.queue_event(other_event, {})
594
594
  events = [e async for e in scan2.async_start()]
595
- assert len(events) == 3
596
- assert 1 == len([e for e in events if e.type == "SCAN"])
595
+ assert len(events) == 4
596
+ assert 2 == len([e for e in events if e.type == "SCAN"])
597
597
  unmodified_wildcard_events = [e for e in events if e.type == "DNS_NAME" and "_wildcard" not in e.data]
598
598
  assert len(unmodified_wildcard_events) == 2
599
599
  assert 1 == len(
@@ -632,8 +632,42 @@ def custom_lookup(query, rdtype):
632
632
 
633
633
 
634
634
  @pytest.mark.asyncio
635
- async def test_dns_raw_records(bbot_scanner):
635
+ async def test_wildcard_deduplication(bbot_scanner):
636
+ custom_lookup = """
637
+ def custom_lookup(query, rdtype):
638
+ if rdtype == "TXT" and query.strip(".").endswith("evilcorp.com"):
639
+ return {""}
640
+ """
641
+
642
+ mock_data = {
643
+ "evilcorp.com": {"A": ["127.0.0.1"]},
644
+ }
645
+
646
+ from bbot.modules.base import BaseModule
647
+
648
+ class DummyModule(BaseModule):
649
+ watched_events = ["DNS_NAME"]
650
+ per_domain_only = True
651
+
652
+ async def handle_event(self, event):
653
+ for i in range(30):
654
+ await self.emit_event(f"www{i}.evilcorp.com", "DNS_NAME", parent=event)
655
+
656
+ # scan without omitted event type
657
+ scan = bbot_scanner(
658
+ "evilcorp.com", config={"dns": {"minimal": False, "wildcard_ignore": []}, "omit_event_types": []}
659
+ )
660
+ await scan.helpers.dns._mock_dns(mock_data, custom_lookup_fn=custom_lookup)
661
+ dummy_module = DummyModule(scan)
662
+ scan.modules["dummy_module"] = dummy_module
663
+ events = [e async for e in scan.async_start()]
664
+ dns_name_events = [e for e in events if e.type == "DNS_NAME"]
665
+ assert len(dns_name_events) == 2
666
+ assert 1 == len([e for e in dns_name_events if e.data == "_wildcard.evilcorp.com"])
667
+
636
668
 
669
+ @pytest.mark.asyncio
670
+ async def test_dns_raw_records(bbot_scanner):
637
671
  from bbot.modules.base import BaseModule
638
672
 
639
673
  class DummyModule(BaseModule):
@@ -696,7 +730,7 @@ async def test_dns_raw_records(bbot_scanner):
696
730
  dummy_module = DummyModule(scan)
697
731
  scan.modules["dummy_module"] = dummy_module
698
732
  events = [e async for e in scan.async_start()]
699
- # no raw records should be ouptut
733
+ # no raw records should be output
700
734
  assert 0 == len([e for e in events if e.type == "RAW_DNS_RECORD"])
701
735
  # but they should still make it to the module
702
736
  assert 1 == len(
@@ -729,7 +763,7 @@ async def test_dns_graph_structure(bbot_scanner):
729
763
  }
730
764
  )
731
765
  events = [e async for e in scan.async_start()]
732
- assert len(events) == 5
766
+ assert len(events) == 6
733
767
  non_scan_events = [e for e in events if e.type != "SCAN"]
734
768
  assert sorted([e.type for e in non_scan_events]) == ["DNS_NAME", "DNS_NAME", "DNS_NAME", "URL_UNVERIFIED"]
735
769
  events_by_data = {e.data: e for e in non_scan_events}
@@ -744,16 +778,16 @@ async def test_dns_graph_structure(bbot_scanner):
744
778
 
745
779
  @pytest.mark.asyncio
746
780
  async def test_dns_helpers(bbot_scanner):
747
- assert service_record("") == False
748
- assert service_record("localhost") == False
749
- assert service_record("www.example.com") == False
750
- assert service_record("www.example.com", "SRV") == True
751
- assert service_record("_custom._service.example.com", "SRV") == True
752
- assert service_record("_custom._service.example.com", "A") == False
781
+ assert service_record("") is False
782
+ assert service_record("localhost") is False
783
+ assert service_record("www.example.com") is False
784
+ assert service_record("www.example.com", "SRV") is True
785
+ assert service_record("_custom._service.example.com", "SRV") is True
786
+ assert service_record("_custom._service.example.com", "A") is False
753
787
  # top 100 most common SRV records
754
788
  for srv_record in common_srvs[:100]:
755
789
  hostname = f"{srv_record}.example.com"
756
- assert service_record(hostname) == True
790
+ assert service_record(hostname) is True
757
791
 
758
792
  # make sure system nameservers are excluded from use by DNS brute force
759
793
  brute_nameservers = tempwordlist(["1.2.3.4", "8.8.4.4", "4.3.2.1", "8.8.8.8"])
@@ -14,7 +14,6 @@ async def test_engine():
14
14
  return_errored = False
15
15
 
16
16
  class TestEngineServer(EngineServer):
17
-
18
17
  CMDS = {
19
18
  0: "return_thing",
20
19
  1: "yield_stuff",
@@ -54,7 +53,6 @@ async def test_engine():
54
53
  raise
55
54
 
56
55
  class TestEngineClient(EngineClient):
57
-
58
56
  SERVER_CLASS = TestEngineServer
59
57
 
60
58
  async def return_thing(self, n):
@@ -72,7 +70,7 @@ async def test_engine():
72
70
 
73
71
  # test async generator
74
72
  assert counter == 0
75
- assert yield_cancelled == False
73
+ assert yield_cancelled is False
76
74
  yield_res = [r async for r in test_engine.yield_stuff(13)]
77
75
  assert yield_res == [f"thing{i}" for i in range(13)]
78
76
  assert len(yield_res) == 13
@@ -88,8 +86,8 @@ async def test_engine():
88
86
  await agen.aclose()
89
87
  break
90
88
  await asyncio.sleep(5)
91
- assert yield_cancelled == True
92
- assert yield_errored == False
89
+ assert yield_cancelled is True
90
+ assert yield_errored is False
93
91
  assert counter < 15
94
92
 
95
93
  # test async generator with error
@@ -99,8 +97,8 @@ async def test_engine():
99
97
  with pytest.raises(BBOTEngineError):
100
98
  async for _ in agen:
101
99
  pass
102
- assert yield_cancelled == False
103
- assert yield_errored == True
100
+ assert yield_cancelled is False
101
+ assert yield_errored is True
104
102
 
105
103
  # test return with cancellation
106
104
  return_started = False
@@ -113,10 +111,10 @@ async def test_engine():
113
111
  with pytest.raises(asyncio.CancelledError):
114
112
  await task
115
113
  await asyncio.sleep(0.1)
116
- assert return_started == True
117
- assert return_finished == False
118
- assert return_cancelled == True
119
- assert return_errored == False
114
+ assert return_started is True
115
+ assert return_finished is False
116
+ assert return_cancelled is True
117
+ assert return_errored is False
120
118
 
121
119
  # test return with late cancellation
122
120
  return_started = False
@@ -128,10 +126,10 @@ async def test_engine():
128
126
  task.cancel()
129
127
  result = await task
130
128
  assert result == "thing1"
131
- assert return_started == True
132
- assert return_finished == True
133
- assert return_cancelled == False
134
- assert return_errored == False
129
+ assert return_started is True
130
+ assert return_finished is True
131
+ assert return_cancelled is False
132
+ assert return_errored is False
135
133
 
136
134
  # test return with error
137
135
  return_started = False
@@ -140,9 +138,9 @@ async def test_engine():
140
138
  return_errored = False
141
139
  with pytest.raises(BBOTEngineError):
142
140
  result = await test_engine.return_thing(None)
143
- assert return_started == True
144
- assert return_finished == False
145
- assert return_cancelled == False
146
- assert return_errored == True
141
+ assert return_started is True
142
+ assert return_finished is False
143
+ assert return_cancelled is False
144
+ assert return_errored is True
147
145
 
148
146
  await test_engine.shutdown()