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
@@ -1,3 +1,5 @@
1
+ from ipaddress import ip_network
2
+
1
3
  from ..bbot_fixtures import *
2
4
 
3
5
 
@@ -12,6 +14,7 @@ async def test_scan(
12
14
  "1.1.1.0",
13
15
  "1.1.1.1/31",
14
16
  "evilcorp.com",
17
+ "test.evilcorp.com",
15
18
  blacklist=["1.1.1.1/28", "www.evilcorp.com"],
16
19
  modules=["ipneighbor"],
17
20
  )
@@ -31,8 +34,11 @@ async def test_scan(
31
34
  assert not scan0.in_scope("test.www.evilcorp.com")
32
35
  assert not scan0.in_scope("www.evilcorp.co.uk")
33
36
  j = scan0.json
34
- assert set(j["target"]["seeds"]) == {"1.1.1.0", "1.1.1.0/31", "evilcorp.com"}
35
- assert set(j["target"]["whitelist"]) == {"1.1.1.0/31", "evilcorp.com"}
37
+ assert set(j["target"]["seeds"]) == {"1.1.1.0", "1.1.1.0/31", "evilcorp.com", "test.evilcorp.com"}
38
+ # we preserve the original whitelist inputs
39
+ assert set(j["target"]["whitelist"]) == {"1.1.1.0", "1.1.1.0/31", "evilcorp.com", "test.evilcorp.com"}
40
+ # but in the background they are collapsed
41
+ assert scan0.target.whitelist.hosts == {ip_network("1.1.1.0/31"), "evilcorp.com"}
36
42
  assert set(j["target"]["blacklist"]) == {"1.1.1.0/28", "www.evilcorp.com"}
37
43
  assert "ipneighbor" in j["preset"]["modules"]
38
44
 
@@ -78,6 +84,9 @@ async def test_scan(
78
84
  for scan in (scan0, scan1, scan2, scan4, scan5):
79
85
  await scan._cleanup()
80
86
 
87
+ scan6 = bbot_scanner("a.foobar.io", "b.foobar.io", "c.foobar.io", "foobar.io")
88
+ assert len(scan6.dns_strings) == 1
89
+
81
90
 
82
91
  @pytest.mark.asyncio
83
92
  async def test_url_extension_handling(bbot_scanner):
@@ -91,13 +100,13 @@ async def test_url_extension_handling(bbot_scanner):
91
100
  assert "blacklisted" not in bad_event.tags
92
101
  assert "httpx-only" not in httpx_event.tags
93
102
  result = await scan.ingress_module.handle_event(good_event)
94
- assert result == None
103
+ assert result is None
95
104
  result, reason = await scan.ingress_module.handle_event(bad_event)
96
- assert result == False
105
+ assert result is False
97
106
  assert reason == "event is blacklisted"
98
107
  assert "blacklisted" in bad_event.tags
99
108
  result = await scan.ingress_module.handle_event(httpx_event)
100
- assert result == None
109
+ assert result is None
101
110
  assert "httpx-only" in httpx_event.tags
102
111
 
103
112
  await scan._cleanup()
@@ -115,3 +124,28 @@ async def test_speed_counter():
115
124
  await asyncio.sleep(0.2)
116
125
  # only 5 should show
117
126
  assert 4 <= counter.speed <= 5
127
+
128
+
129
+ @pytest.mark.asyncio
130
+ async def test_python_output_matches_json(bbot_scanner):
131
+ import json
132
+
133
+ scan = bbot_scanner(
134
+ "blacklanternsecurity.com",
135
+ config={"speculate": True, "dns": {"minimal": False}, "scope": {"report_distance": 10}},
136
+ )
137
+ await scan.helpers.dns._mock_dns({"blacklanternsecurity.com": {"A": ["127.0.0.1"]}})
138
+ events = [e.json() async for e in scan.async_start()]
139
+ output_json = scan.home / "output.json"
140
+ json_events = []
141
+ for line in open(output_json):
142
+ json_events.append(json.loads(line))
143
+
144
+ assert len(events) == 5
145
+ scan_events = [e for e in events if e["type"] == "SCAN"]
146
+ assert len(scan_events) == 2
147
+ assert all(isinstance(e["data"]["status"], str) for e in scan_events)
148
+ assert len([e for e in events if e["type"] == "DNS_NAME"]) == 1
149
+ assert len([e for e in events if e["type"] == "ORG_STUB"]) == 1
150
+ assert len([e for e in events if e["type"] == "IP_ADDRESS"]) == 1
151
+ assert events == json_events
@@ -12,7 +12,8 @@ class TestScopeBaseline(ModuleTestBase):
12
12
  module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args)
13
13
 
14
14
  def check(self, module_test, events):
15
- assert len(events) == 6
15
+ assert len(events) == 7
16
+ assert 2 == len([e for e in events if e.type == "SCAN"])
16
17
  assert 1 == len(
17
18
  [
18
19
  e
@@ -62,7 +63,7 @@ class TestScopeBlacklist(TestScopeBaseline):
62
63
  module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args)
63
64
 
64
65
  def check(self, module_test, events):
65
- assert len(events) == 1
66
+ assert len(events) == 2
66
67
  assert not any(e.type == "URL" for e in events)
67
68
  assert not any(str(e.host) == "127.0.0.1" for e in events)
68
69
 
@@ -72,7 +73,7 @@ class TestScopeWhitelist(TestScopeBlacklist):
72
73
  whitelist = ["255.255.255.255"]
73
74
 
74
75
  def check(self, module_test, events):
75
- assert len(events) == 3
76
+ assert len(events) == 4
76
77
  assert not any(e.type == "URL" for e in events)
77
78
  assert 1 == len(
78
79
  [
@@ -3,39 +3,31 @@ from ..bbot_fixtures import * # noqa: F401
3
3
 
4
4
  @pytest.mark.asyncio
5
5
  async def test_target(bbot_scanner):
6
- import random
6
+ from radixtarget import RadixTarget
7
7
  from ipaddress import ip_address, ip_network
8
- from bbot.scanner.target import Target, BBOTTarget
8
+ from bbot.scanner.target import BBOTTarget, ScanSeeds
9
9
 
10
10
  scan1 = bbot_scanner("api.publicapis.org", "8.8.8.8/30", "2001:4860:4860::8888/126")
11
11
  scan2 = bbot_scanner("8.8.8.8/29", "publicapis.org", "2001:4860:4860::8888/125")
12
12
  scan3 = bbot_scanner("8.8.8.8/29", "publicapis.org", "2001:4860:4860::8888/125")
13
13
  scan4 = bbot_scanner("8.8.8.8/29")
14
14
  scan5 = bbot_scanner()
15
- assert not scan5.target
16
- assert len(scan1.target) == 9
17
- assert len(scan4.target) == 8
18
- assert "8.8.8.9" in scan1.target
19
- assert "8.8.8.12" not in scan1.target
20
- assert "8.8.8.8/31" in scan1.target
21
- assert "8.8.8.8/30" in scan1.target
22
- assert "8.8.8.8/29" not in scan1.target
23
- assert "2001:4860:4860::8889" in scan1.target
24
- assert "2001:4860:4860::888c" not in scan1.target
25
- assert "www.api.publicapis.org" in scan1.target
26
- assert "api.publicapis.org" in scan1.target
27
- assert "publicapis.org" not in scan1.target
28
- assert "bob@www.api.publicapis.org" in scan1.target
29
- assert "https://www.api.publicapis.org" in scan1.target
30
- assert "www.api.publicapis.org:80" in scan1.target
31
- assert scan1.make_event("https://[2001:4860:4860::8888]:80", dummy=True) in scan1.target
32
- assert scan1.make_event("[2001:4860:4860::8888]:80", "OPEN_TCP_PORT", dummy=True) in scan1.target
33
- assert scan1.make_event("[2001:4860:4860::888c]:80", "OPEN_TCP_PORT", dummy=True) not in scan1.target
34
- assert scan1.target in scan2.target
35
- assert scan2.target not in scan1.target
36
- assert scan3.target in scan2.target
37
- assert scan2.target == scan3.target
38
- assert scan4.target != scan1.target
15
+
16
+ # test different types of inputs
17
+ target = BBOTTarget("evilcorp.com", "1.2.3.4/8")
18
+ assert "www.evilcorp.com" in target.seeds
19
+ assert "www.evilcorp.com:80" in target.seeds
20
+ assert "http://www.evilcorp.com:80" in target.seeds
21
+ assert "1.2.3.4" in target.seeds
22
+ assert "1.2.3.4/24" in target.seeds
23
+ assert ip_address("1.2.3.4") in target.seeds
24
+ assert ip_network("1.2.3.4/24", strict=False) in target.seeds
25
+ event = scan1.make_event("https://www.evilcorp.com:80", dummy=True)
26
+ assert event in target.seeds
27
+ with pytest.raises(ValueError):
28
+ ["asdf"] in target.seeds
29
+ with pytest.raises(ValueError):
30
+ target.seeds.get(["asdf"])
39
31
 
40
32
  assert not scan5.target.seeds
41
33
  assert len(scan1.target.seeds) == 9
@@ -56,6 +48,36 @@ async def test_target(bbot_scanner):
56
48
  assert scan1.make_event("https://[2001:4860:4860::8888]:80", dummy=True) in scan1.target.seeds
57
49
  assert scan1.make_event("[2001:4860:4860::8888]:80", "OPEN_TCP_PORT", dummy=True) in scan1.target.seeds
58
50
  assert scan1.make_event("[2001:4860:4860::888c]:80", "OPEN_TCP_PORT", dummy=True) not in scan1.target.seeds
51
+ assert scan1.target.seeds in scan2.target.seeds
52
+ assert scan2.target.seeds not in scan1.target.seeds
53
+ assert scan3.target.seeds in scan2.target.seeds
54
+ assert scan2.target.seeds == scan3.target.seeds
55
+ assert scan4.target.seeds != scan1.target.seeds
56
+
57
+ assert not scan5.target.whitelist
58
+ assert len(scan1.target.whitelist) == 9
59
+ assert len(scan4.target.whitelist) == 8
60
+ assert "8.8.8.9" in scan1.target.whitelist
61
+ assert "8.8.8.12" not in scan1.target.whitelist
62
+ assert "8.8.8.8/31" in scan1.target.whitelist
63
+ assert "8.8.8.8/30" in scan1.target.whitelist
64
+ assert "8.8.8.8/29" not in scan1.target.whitelist
65
+ assert "2001:4860:4860::8889" in scan1.target.whitelist
66
+ assert "2001:4860:4860::888c" not in scan1.target.whitelist
67
+ assert "www.api.publicapis.org" in scan1.target.whitelist
68
+ assert "api.publicapis.org" in scan1.target.whitelist
69
+ assert "publicapis.org" not in scan1.target.whitelist
70
+ assert "bob@www.api.publicapis.org" in scan1.target.whitelist
71
+ assert "https://www.api.publicapis.org" in scan1.target.whitelist
72
+ assert "www.api.publicapis.org:80" in scan1.target.whitelist
73
+ assert scan1.make_event("https://[2001:4860:4860::8888]:80", dummy=True) in scan1.target.whitelist
74
+ assert scan1.make_event("[2001:4860:4860::8888]:80", "OPEN_TCP_PORT", dummy=True) in scan1.target.whitelist
75
+ assert scan1.make_event("[2001:4860:4860::888c]:80", "OPEN_TCP_PORT", dummy=True) not in scan1.target.whitelist
76
+ assert scan1.target.whitelist in scan2.target.whitelist
77
+ assert scan2.target.whitelist not in scan1.target.whitelist
78
+ assert scan3.target.whitelist in scan2.target.whitelist
79
+ assert scan2.target.whitelist == scan3.target.whitelist
80
+ assert scan4.target.whitelist != scan1.target.whitelist
59
81
 
60
82
  assert scan1.whitelisted("https://[2001:4860:4860::8888]:80")
61
83
  assert scan1.whitelisted("[2001:4860:4860::8888]:80")
@@ -70,45 +92,58 @@ async def test_target(bbot_scanner):
70
92
  assert scan2.target.seeds == scan3.target.seeds
71
93
  assert scan4.target.seeds != scan1.target.seeds
72
94
 
73
- assert str(scan1.target.get("8.8.8.9").host) == "8.8.8.8/30"
74
- assert scan1.target.get("8.8.8.12") is None
75
- assert str(scan1.target.get("2001:4860:4860::8889").host) == "2001:4860:4860::8888/126"
76
- assert scan1.target.get("2001:4860:4860::888c") is None
77
- assert str(scan1.target.get("www.api.publicapis.org").host) == "api.publicapis.org"
78
- assert scan1.target.get("publicapis.org") is None
79
-
80
- target = Target("evilcorp.com")
81
- assert not "com" in target
95
+ assert str(scan1.target.seeds.get("8.8.8.9").host) == "8.8.8.8/30"
96
+ assert str(scan1.target.whitelist.get("8.8.8.9").host) == "8.8.8.8/30"
97
+ assert scan1.target.seeds.get("8.8.8.12") is None
98
+ assert scan1.target.whitelist.get("8.8.8.12") is None
99
+ assert str(scan1.target.seeds.get("2001:4860:4860::8889").host) == "2001:4860:4860::8888/126"
100
+ assert str(scan1.target.whitelist.get("2001:4860:4860::8889").host) == "2001:4860:4860::8888/126"
101
+ assert scan1.target.seeds.get("2001:4860:4860::888c") is None
102
+ assert scan1.target.whitelist.get("2001:4860:4860::888c") is None
103
+ assert str(scan1.target.seeds.get("www.api.publicapis.org").host) == "api.publicapis.org"
104
+ assert str(scan1.target.whitelist.get("www.api.publicapis.org").host) == "api.publicapis.org"
105
+ assert scan1.target.seeds.get("publicapis.org") is None
106
+ assert scan1.target.whitelist.get("publicapis.org") is None
107
+
108
+ target = RadixTarget("evilcorp.com")
109
+ assert "com" not in target
82
110
  assert "evilcorp.com" in target
83
111
  assert "www.evilcorp.com" in target
84
- strict_target = Target("evilcorp.com", strict_scope=True)
85
- assert not "com" in strict_target
112
+ strict_target = RadixTarget("evilcorp.com", strict_dns_scope=True)
113
+ assert "com" not in strict_target
86
114
  assert "evilcorp.com" in strict_target
87
- assert not "www.evilcorp.com" in strict_target
115
+ assert "www.evilcorp.com" not in strict_target
88
116
 
89
- target = Target()
117
+ target = RadixTarget()
90
118
  target.add("evilcorp.com")
91
- assert not "com" in target
119
+ assert "com" not in target
92
120
  assert "evilcorp.com" in target
93
121
  assert "www.evilcorp.com" in target
94
- strict_target = Target(strict_scope=True)
122
+ strict_target = RadixTarget(strict_dns_scope=True)
95
123
  strict_target.add("evilcorp.com")
96
- assert not "com" in strict_target
124
+ assert "com" not in strict_target
97
125
  assert "evilcorp.com" in strict_target
98
- assert not "www.evilcorp.com" in strict_target
126
+ assert "www.evilcorp.com" not in strict_target
99
127
 
100
128
  # test target hashing
101
129
 
102
- target1 = Target()
103
- target1.add("evilcorp.com")
104
- target1.add("1.2.3.4/24")
105
- target1.add("https://evilcorp.net:8080")
106
-
107
- target2 = Target()
108
- target2.add("bob@evilcorp.org")
109
- target2.add("evilcorp.com")
110
- target2.add("1.2.3.4/24")
111
- target2.add("https://evilcorp.net:8080")
130
+ target1 = BBOTTarget()
131
+ target1.whitelist.add("evilcorp.com")
132
+ target1.whitelist.add("1.2.3.4/24")
133
+ target1.whitelist.add("https://evilcorp.net:8080")
134
+ target1.seeds.add("evilcorp.com")
135
+ target1.seeds.add("1.2.3.4/24")
136
+ target1.seeds.add("https://evilcorp.net:8080")
137
+
138
+ target2 = BBOTTarget()
139
+ target2.whitelist.add("bob@evilcorp.org")
140
+ target2.whitelist.add("evilcorp.com")
141
+ target2.whitelist.add("1.2.3.4/24")
142
+ target2.whitelist.add("https://evilcorp.net:8080")
143
+ target2.seeds.add("bob@evilcorp.org")
144
+ target2.seeds.add("evilcorp.com")
145
+ target2.seeds.add("1.2.3.4/24")
146
+ target2.seeds.add("https://evilcorp.net:8080")
112
147
 
113
148
  # make sure it's a sha1 hash
114
149
  assert isinstance(target1.hash, bytes)
@@ -116,11 +151,22 @@ async def test_target(bbot_scanner):
116
151
 
117
152
  # hashes shouldn't match yet
118
153
  assert target1.hash != target2.hash
154
+ assert target1.scope_hash != target2.scope_hash
119
155
  # add missing email
120
- target1.add("bob@evilcorp.org")
156
+ target1.whitelist.add("bob@evilcorp.org")
157
+ assert target1.hash != target2.hash
158
+ assert target1.scope_hash == target2.scope_hash
159
+ target1.seeds.add("bob@evilcorp.org")
121
160
  # now they should match
122
161
  assert target1.hash == target2.hash
123
162
 
163
+ # test default whitelist
164
+ bbottarget = BBOTTarget("http://1.2.3.4:8443", "bob@evilcorp.com")
165
+ assert bbottarget.seeds.hosts == {ip_network("1.2.3.4"), "evilcorp.com"}
166
+ assert bbottarget.whitelist.hosts == {ip_network("1.2.3.4"), "evilcorp.com"}
167
+ assert {e.data for e in bbottarget.seeds.events} == {"http://1.2.3.4:8443/", "bob@evilcorp.com"}
168
+ assert {e.data for e in bbottarget.whitelist.events} == {"1.2.3.4", "evilcorp.com"}
169
+
124
170
  bbottarget1 = BBOTTarget("evilcorp.com", "evilcorp.net", whitelist=["1.2.3.4/24"], blacklist=["1.2.3.4"])
125
171
  bbottarget2 = BBOTTarget("evilcorp.com", "evilcorp.net", whitelist=["1.2.3.0/24"], blacklist=["1.2.3.4"])
126
172
  bbottarget3 = BBOTTarget("evilcorp.com", whitelist=["1.2.3.4/24"], blacklist=["1.2.3.4"])
@@ -137,14 +183,23 @@ async def test_target(bbot_scanner):
137
183
 
138
184
  assert bbottarget1 == bbottarget2
139
185
  assert bbottarget2 == bbottarget1
186
+ # 1 and 3 have different seeds
140
187
  assert bbottarget1 != bbottarget3
141
188
  assert bbottarget3 != bbottarget1
142
- bbottarget3.add("evilcorp.net")
189
+ # until we make them the same
190
+ bbottarget3.seeds.add("evilcorp.net")
143
191
  assert bbottarget1 == bbottarget3
144
192
  assert bbottarget3 == bbottarget1
145
193
 
146
- bbottarget1.add("http://evilcorp.co.nz")
147
- bbottarget2.add("evilcorp.co.nz")
194
+ # adding different events (but with same host) to whitelist should not change hash (since only hosts matter)
195
+ bbottarget1.whitelist.add("http://evilcorp.co.nz")
196
+ bbottarget2.whitelist.add("evilcorp.co.nz")
197
+ assert bbottarget1 == bbottarget2
198
+ assert bbottarget2 == bbottarget1
199
+
200
+ # but seeds should change hash
201
+ bbottarget1.seeds.add("http://evilcorp.co.nz")
202
+ bbottarget2.seeds.add("evilcorp.co.nz")
148
203
  assert bbottarget1 != bbottarget2
149
204
  assert bbottarget2 != bbottarget1
150
205
 
@@ -156,15 +211,11 @@ async def test_target(bbot_scanner):
156
211
  assert bbottarget8 != bbottarget9
157
212
  assert bbottarget9 != bbottarget8
158
213
 
159
- bbottarget10 = bbottarget9.copy()
160
- assert bbottarget10 == bbottarget9
161
- assert bbottarget9 == bbottarget10
162
-
163
214
  # make sure duplicate events don't change hash
164
- target1 = Target("https://evilcorp.com")
165
- target2 = Target("https://evilcorp.com")
215
+ target1 = BBOTTarget("https://evilcorp.com")
216
+ target2 = BBOTTarget("https://evilcorp.com")
166
217
  assert target1 == target2
167
- target1.add("https://evilcorp.com:443")
218
+ target1.seeds.add("https://evilcorp.com:443")
168
219
  assert target1 == target2
169
220
 
170
221
  # make sure hosts are collapsed in whitelist and blacklist
@@ -173,24 +224,26 @@ async def test_target(bbot_scanner):
173
224
  whitelist=["evilcorp.net:443", "http://evilcorp.net:8080"],
174
225
  blacklist=["http://evilcorp.org:8080", "evilcorp.org:443"],
175
226
  )
176
- assert list(bbottarget) == ["http://evilcorp.com:8080"]
227
+ # base class is not iterable
228
+ with pytest.raises(TypeError):
229
+ assert list(bbottarget) == ["http://evilcorp.com:8080"]
177
230
  assert list(bbottarget.seeds) == ["http://evilcorp.com:8080"]
178
- assert list(bbottarget.whitelist) == ["evilcorp.net"]
179
- assert list(bbottarget.blacklist) == ["evilcorp.org"]
231
+ assert {e.data for e in bbottarget.whitelist} == {"evilcorp.net:443", "http://evilcorp.net:8080/"}
232
+ assert {e.data for e in bbottarget.blacklist} == {"http://evilcorp.org:8080/", "evilcorp.org:443"}
180
233
 
181
234
  # test org stub as target
182
235
  for org_target in ("ORG:evilcorp", "ORG_STUB:evilcorp"):
183
236
  scan = bbot_scanner(org_target)
184
237
  events = [e async for e in scan.async_start()]
185
- assert len(events) == 2
186
- assert set([e.type for e in events]) == {"SCAN", "ORG_STUB"}
238
+ assert len(events) == 3
239
+ assert {e.type for e in events} == {"SCAN", "ORG_STUB"}
187
240
 
188
241
  # test username as target
189
242
  for user_target in ("USER:vancerefrigeration", "USERNAME:vancerefrigeration"):
190
243
  scan = bbot_scanner(user_target)
191
244
  events = [e async for e in scan.async_start()]
192
- assert len(events) == 2
193
- assert set([e.type for e in events]) == {"SCAN", "USERNAME"}
245
+ assert len(events) == 3
246
+ assert {e.type for e in events} == {"SCAN", "USERNAME"}
194
247
 
195
248
  # verify hash values
196
249
  bbottarget = BBOTTarget(
@@ -200,21 +253,30 @@ async def test_target(bbot_scanner):
200
253
  whitelist=["evilcorp.com", "bob@www.evilcorp.com", "evilcorp.net"],
201
254
  blacklist=["1.2.3.4", "4.3.2.1/24", "http://1.2.3.4", "bob@asdf.evilcorp.net"],
202
255
  )
203
- assert set([e.data for e in bbottarget.seeds.events]) == {
256
+ assert {e.data for e in bbottarget.seeds.events} == {
204
257
  "1.2.3.0/24",
205
258
  "http://www.evilcorp.net/",
206
259
  "bob@fdsa.evilcorp.net",
207
260
  }
208
- assert set([e.data for e in bbottarget.whitelist.events]) == {"evilcorp.com", "evilcorp.net"}
209
- assert set([e.data for e in bbottarget.blacklist.events]) == {"1.2.3.4", "4.3.2.0/24", "asdf.evilcorp.net"}
261
+ assert {e.data for e in bbottarget.whitelist.events} == {
262
+ "evilcorp.com",
263
+ "evilcorp.net",
264
+ "bob@www.evilcorp.com",
265
+ }
266
+ assert {e.data for e in bbottarget.blacklist.events} == {
267
+ "1.2.3.4",
268
+ "4.3.2.0/24",
269
+ "http://1.2.3.4/",
270
+ "bob@asdf.evilcorp.net",
271
+ }
210
272
  assert set(bbottarget.seeds.hosts) == {ip_network("1.2.3.0/24"), "www.evilcorp.net", "fdsa.evilcorp.net"}
211
273
  assert set(bbottarget.whitelist.hosts) == {"evilcorp.com", "evilcorp.net"}
212
- assert set(bbottarget.blacklist.hosts) == {ip_address("1.2.3.4"), ip_network("4.3.2.0/24"), "asdf.evilcorp.net"}
213
- assert bbottarget.hash == b"\x0b\x908\xe3\xef\n=\x13d\xdf\x00;\xack\x0c\xbc\xd2\xcc'\xba"
214
- assert bbottarget.scope_hash == b"\x00\xf5V\xfb.\xeb#\xcb\xf0q\xf9\xe9e\xb7\x1f\xe2T+\xdbw"
215
- assert bbottarget.seeds.hash == b"\xaf.\x86\x83\xa1C\xad\xb4\xe7`X\x94\xe2\xa0\x01\xc2\xe3:J\xc5"
216
- assert bbottarget.whitelist.hash == b"\xa0Af\x07n\x10\xd9\xb6\n\xa7TO\xb07\xcdW\xc4vLC"
217
- assert bbottarget.blacklist.hash == b"\xaf\x0e\x8a\xe9JZ\x86\xbe\xee\xa9\xa9\xdb0\xaf'#\x84 U/"
274
+ assert set(bbottarget.blacklist.hosts) == {ip_network("1.2.3.4/32"), ip_network("4.3.2.0/24"), "asdf.evilcorp.net"}
275
+ assert bbottarget.hash == b"\xb3iU\xa8#\x8aq\x84/\xc5\xf2;\x11\x11\x0c&\xea\x07\xd4Q"
276
+ assert bbottarget.scope_hash == b"f\xe1\x01c^3\xf5\xd24B\x87P\xa0Glq0p3J"
277
+ assert bbottarget.seeds.hash == b"V\n\xf5\x1d\x1f=i\xbc\\\x15o\xc2p\xb2\x84\x97\xfeR\xde\xc1"
278
+ assert bbottarget.whitelist.hash == b"\x8e\xd0\xa76\x8em4c\x0e\x1c\xfdA\x9d*sv}\xeb\xc4\xc4"
279
+ assert bbottarget.blacklist.hash == b'\xf7\xaf\xa1\xda4"C:\x13\xf42\xc3,\xc3\xa9\x9f\x15\x15n\\'
218
280
 
219
281
  scan = bbot_scanner(
220
282
  "http://www.evilcorp.net",
@@ -225,85 +287,120 @@ async def test_target(bbot_scanner):
225
287
  )
226
288
  events = [e async for e in scan.async_start()]
227
289
  scan_events = [e for e in events if e.type == "SCAN"]
228
- assert len(scan_events) == 1
290
+ assert len(scan_events) == 2
229
291
  target_dict = scan_events[0].data["target"]
230
- assert target_dict["strict_scope"] == False
231
- assert target_dict["hash"] == b"\x0b\x908\xe3\xef\n=\x13d\xdf\x00;\xack\x0c\xbc\xd2\xcc'\xba".hex()
232
- assert target_dict["scope_hash"] == b"\x00\xf5V\xfb.\xeb#\xcb\xf0q\xf9\xe9e\xb7\x1f\xe2T+\xdbw".hex()
233
- assert target_dict["seed_hash"] == b"\xaf.\x86\x83\xa1C\xad\xb4\xe7`X\x94\xe2\xa0\x01\xc2\xe3:J\xc5".hex()
234
- assert target_dict["whitelist_hash"] == b"\xa0Af\x07n\x10\xd9\xb6\n\xa7TO\xb07\xcdW\xc4vLC".hex()
235
- assert target_dict["blacklist_hash"] == b"\xaf\x0e\x8a\xe9JZ\x86\xbe\xee\xa9\xa9\xdb0\xaf'#\x84 U/".hex()
236
- assert target_dict["hash"] == "0b9038e3ef0a3d1364df003bac6b0cbcd2cc27ba"
237
- assert target_dict["scope_hash"] == "00f556fb2eeb23cbf071f9e965b71fe2542bdb77"
238
- assert target_dict["seed_hash"] == "af2e8683a143adb4e7605894e2a001c2e33a4ac5"
239
- assert target_dict["whitelist_hash"] == "a04166076e10d9b60aa7544fb037cd57c4764c43"
240
- assert target_dict["blacklist_hash"] == "af0e8ae94a5a86beeea9a9db30af27238420552f"
241
-
242
- # test target sorting
243
- big_subnet = scan.make_event("1.2.3.4/24", dummy=True)
244
- medium_subnet = scan.make_event("1.2.3.4/28", dummy=True)
245
- small_subnet = scan.make_event("1.2.3.4/30", dummy=True)
246
- ip_event = scan.make_event("1.2.3.4", dummy=True)
247
- parent_domain = scan.make_event("evilcorp.com", dummy=True)
248
- grandparent_domain = scan.make_event("www.evilcorp.com", dummy=True)
249
- greatgrandparent_domain = scan.make_event("api.www.evilcorp.com", dummy=True)
250
- target = Target()
251
- assert big_subnet._host_size == -256
252
- assert medium_subnet._host_size == -16
253
- assert small_subnet._host_size == -4
254
- assert ip_event._host_size == 1
255
- assert parent_domain._host_size == 12
256
- assert grandparent_domain._host_size == 16
257
- assert greatgrandparent_domain._host_size == 20
258
- events = [
259
- big_subnet,
260
- medium_subnet,
261
- small_subnet,
262
- ip_event,
263
- parent_domain,
264
- grandparent_domain,
265
- greatgrandparent_domain,
266
- ]
267
- random.shuffle(events)
268
- assert target._sort_events(events) == [
269
- big_subnet,
270
- medium_subnet,
271
- small_subnet,
272
- ip_event,
273
- parent_domain,
274
- grandparent_domain,
275
- greatgrandparent_domain,
276
- ]
292
+
293
+ assert target_dict["seeds"] == ["1.2.3.0/24", "bob@fdsa.evilcorp.net", "http://www.evilcorp.net/"]
294
+ assert target_dict["whitelist"] == ["bob@www.evilcorp.com", "evilcorp.com", "evilcorp.net"]
295
+ assert target_dict["blacklist"] == ["1.2.3.4", "4.3.2.0/24", "bob@asdf.evilcorp.net", "http://1.2.3.4/"]
296
+ assert target_dict["strict_scope"] is False
297
+ assert target_dict["hash"] == "b36955a8238a71842fc5f23b11110c26ea07d451"
298
+ assert target_dict["seed_hash"] == "560af51d1f3d69bc5c156fc270b28497fe52dec1"
299
+ assert target_dict["whitelist_hash"] == "8ed0a7368e6d34630e1cfd419d2a73767debc4c4"
300
+ assert target_dict["blacklist_hash"] == "f7afa1da3422433a13f432c32cc3a99f15156e5c"
301
+ assert target_dict["scope_hash"] == "66e101635e33f5d234428750a0476c713070334a"
277
302
 
278
303
  # make sure child subnets/IPs don't get added to whitelist/blacklist
279
- target = Target("1.2.3.4/24", "1.2.3.4/28", acl_mode=True)
280
- assert set(e.data for e in target) == {"1.2.3.0/24"}
281
- target = Target("1.2.3.4/28", "1.2.3.4/24", acl_mode=True)
282
- assert set(e.data for e in target) == {"1.2.3.0/24"}
283
- target = Target("1.2.3.4/28", "1.2.3.4", acl_mode=True)
284
- assert set(e.data for e in target) == {"1.2.3.0/28"}
285
- target = Target("1.2.3.4", "1.2.3.4/28", acl_mode=True)
286
- assert set(e.data for e in target) == {"1.2.3.0/28"}
304
+ target = RadixTarget("1.2.3.4/24", "1.2.3.4/28", acl_mode=True)
305
+ assert set(target) == {ip_network("1.2.3.0/24")}
306
+ target = RadixTarget("1.2.3.4/28", "1.2.3.4/24", acl_mode=True)
307
+ assert set(target) == {ip_network("1.2.3.0/24")}
308
+ target = RadixTarget("1.2.3.4/28", "1.2.3.4", acl_mode=True)
309
+ assert set(target) == {ip_network("1.2.3.0/28")}
310
+ target = RadixTarget("1.2.3.4", "1.2.3.4/28", acl_mode=True)
311
+ assert set(target) == {ip_network("1.2.3.0/28")}
287
312
 
288
313
  # same but for domains
289
- target = Target("evilcorp.com", "www.evilcorp.com", acl_mode=True)
290
- assert set(e.data for e in target) == {"evilcorp.com"}
291
- target = Target("www.evilcorp.com", "evilcorp.com", acl_mode=True)
292
- assert set(e.data for e in target) == {"evilcorp.com"}
314
+ target = RadixTarget("evilcorp.com", "www.evilcorp.com", acl_mode=True)
315
+ assert set(target) == {"evilcorp.com"}
316
+ target = RadixTarget("www.evilcorp.com", "evilcorp.com", acl_mode=True)
317
+ assert set(target) == {"evilcorp.com"}
293
318
 
294
319
  # make sure strict_scope doesn't mess us up
295
- target = Target("evilcorp.co.uk", "www.evilcorp.co.uk", acl_mode=True, strict_scope=True)
320
+ target = RadixTarget("evilcorp.co.uk", "www.evilcorp.co.uk", acl_mode=True, strict_dns_scope=True)
296
321
  assert set(target.hosts) == {"evilcorp.co.uk", "www.evilcorp.co.uk"}
297
322
  assert "evilcorp.co.uk" in target
298
323
  assert "www.evilcorp.co.uk" in target
299
- assert not "api.evilcorp.co.uk" in target
300
- assert not "api.www.evilcorp.co.uk" in target
324
+ assert "api.evilcorp.co.uk" not in target
325
+ assert "api.www.evilcorp.co.uk" not in target
301
326
 
302
327
  # test 'single' boolean argument
303
- target = Target("http://evilcorp.com", "evilcorp.com:443")
328
+ target = ScanSeeds("http://evilcorp.com", "evilcorp.com:443")
304
329
  assert "www.evilcorp.com" in target
330
+ assert "bob@evilcorp.com" in target
305
331
  event = target.get("www.evilcorp.com")
306
332
  assert event.host == "evilcorp.com"
307
333
  events = target.get("www.evilcorp.com", single=False)
308
334
  assert len(events) == 2
309
- assert set([e.data for e in events]) == {"http://evilcorp.com/", "evilcorp.com:443"}
335
+ assert {e.data for e in events} == {"http://evilcorp.com/", "evilcorp.com:443"}
336
+
337
+
338
+ @pytest.mark.asyncio
339
+ async def test_blacklist_regex(bbot_scanner, bbot_httpserver):
340
+ from bbot.scanner.target import ScanBlacklist
341
+
342
+ blacklist = ScanBlacklist("evilcorp.com")
343
+ assert blacklist.inputs == {"evilcorp.com"}
344
+ assert "www.evilcorp.com" in blacklist
345
+ assert "http://www.evilcorp.com" in blacklist
346
+ blacklist.add("RE:test")
347
+ assert "RE:test" in blacklist.inputs
348
+ assert set(blacklist.inputs) == {"evilcorp.com", "RE:test"}
349
+ assert blacklist.blacklist_regexes
350
+ assert next(iter(blacklist.blacklist_regexes)).pattern == "test"
351
+ result1 = blacklist.get("test.com")
352
+ assert result1.type == "DNS_NAME"
353
+ assert result1.data == "test.com"
354
+ result2 = blacklist.get("www.evilcorp.com")
355
+ assert result2.type == "DNS_NAME"
356
+ assert result2.data == "evilcorp.com"
357
+ result2 = blacklist.get("www.evil.com")
358
+ assert result2 is None
359
+ with pytest.raises(KeyError):
360
+ blacklist.get("www.evil.com", raise_error=True)
361
+ assert "test.com" in blacklist
362
+ assert "http://evilcorp.com/test.aspx" in blacklist
363
+ assert "http://tes.com" not in blacklist
364
+
365
+ blacklist = ScanBlacklist("evilcorp.com", r"RE:[0-9]{6}\.aspx$")
366
+ assert "http://evilcorp.com" in blacklist
367
+ assert "http://test.com/123456" not in blacklist
368
+ assert "http://test.com/12345.aspx?a=asdf" not in blacklist
369
+ assert "http://test.com/asdf/123456.aspx/asdf" not in blacklist
370
+ assert "http://test.com/asdf/123456.aspx?a=asdf" in blacklist
371
+ assert "http://test.com/asdf/123456.aspx" in blacklist
372
+
373
+ bbot_httpserver.expect_request(uri="/").respond_with_data(
374
+ """
375
+ <a href='http://127.0.0.1:8888/asdfevil333asdf'/>
376
+ <a href='http://127.0.0.1:8888/logout.aspx'/>
377
+ """
378
+ )
379
+ bbot_httpserver.expect_request(uri="/asdfevilasdf").respond_with_data("")
380
+ bbot_httpserver.expect_request(uri="/logout.aspx").respond_with_data("")
381
+
382
+ # make sure URL is detected normally
383
+ scan = bbot_scanner("http://127.0.0.1:8888/", presets=["spider"], config={"excavate": True}, debug=True)
384
+ assert {r.pattern for r in scan.target.blacklist.blacklist_regexes} == {r"/.*(sign|log)[_-]?out"}
385
+ events = [e async for e in scan.async_start()]
386
+ urls = [e.data for e in events if e.type == "URL"]
387
+ assert len(urls) == 2
388
+ assert set(urls) == {"http://127.0.0.1:8888/", "http://127.0.0.1:8888/asdfevil333asdf"}
389
+
390
+ # same scan again but with blacklist regex
391
+ scan = bbot_scanner(
392
+ "http://127.0.0.1:8888/",
393
+ blacklist=[r"RE:evil[0-9]{3}"],
394
+ presets=["spider"],
395
+ config={"excavate": True},
396
+ debug=True,
397
+ )
398
+ assert scan.target.blacklist.blacklist_regexes
399
+ assert {r.pattern for r in scan.target.blacklist.blacklist_regexes} == {
400
+ r"evil[0-9]{3}",
401
+ r"/.*(sign|log)[_-]?out",
402
+ }
403
+ events = [e async for e in scan.async_start()]
404
+ urls = [e.data for e in events if e.type == "URL"]
405
+ assert len(urls) == 1
406
+ assert set(urls) == {"http://127.0.0.1:8888/"}