bbot 2.0.1.4654rc0__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 (270) 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 -6
  6. bbot/core/engine.py +9 -8
  7. bbot/core/event/base.py +162 -63
  8. bbot/core/helpers/bloom.py +10 -3
  9. bbot/core/helpers/command.py +9 -8
  10. bbot/core/helpers/depsinstaller/installer.py +89 -32
  11. bbot/core/helpers/depsinstaller/sudo_askpass.py +38 -2
  12. bbot/core/helpers/diff.py +10 -10
  13. bbot/core/helpers/dns/brute.py +18 -14
  14. bbot/core/helpers/dns/dns.py +16 -15
  15. bbot/core/helpers/dns/engine.py +159 -132
  16. bbot/core/helpers/dns/helpers.py +2 -2
  17. bbot/core/helpers/dns/mock.py +26 -8
  18. bbot/core/helpers/files.py +1 -1
  19. bbot/core/helpers/helper.py +7 -4
  20. bbot/core/helpers/interactsh.py +3 -3
  21. bbot/core/helpers/libmagic.py +65 -0
  22. bbot/core/helpers/misc.py +65 -22
  23. bbot/core/helpers/names_generator.py +17 -3
  24. bbot/core/helpers/process.py +0 -20
  25. bbot/core/helpers/regex.py +1 -1
  26. bbot/core/helpers/regexes.py +12 -6
  27. bbot/core/helpers/validators.py +1 -2
  28. bbot/core/helpers/web/client.py +1 -1
  29. bbot/core/helpers/web/engine.py +18 -13
  30. bbot/core/helpers/web/web.py +25 -116
  31. bbot/core/helpers/wordcloud.py +5 -5
  32. bbot/core/modules.py +36 -27
  33. bbot/core/multiprocess.py +58 -0
  34. bbot/core/shared_deps.py +46 -3
  35. bbot/db/sql/models.py +147 -0
  36. bbot/defaults.yml +15 -10
  37. bbot/errors.py +0 -8
  38. bbot/modules/anubisdb.py +2 -2
  39. bbot/modules/apkpure.py +63 -0
  40. bbot/modules/azure_tenant.py +2 -2
  41. bbot/modules/baddns.py +35 -19
  42. bbot/modules/baddns_direct.py +92 -0
  43. bbot/modules/baddns_zone.py +3 -8
  44. bbot/modules/badsecrets.py +4 -3
  45. bbot/modules/base.py +195 -51
  46. bbot/modules/bevigil.py +7 -7
  47. bbot/modules/binaryedge.py +7 -4
  48. bbot/modules/bufferoverrun.py +47 -0
  49. bbot/modules/builtwith.py +6 -10
  50. bbot/modules/bypass403.py +5 -5
  51. bbot/modules/c99.py +10 -7
  52. bbot/modules/censys.py +9 -13
  53. bbot/modules/certspotter.py +5 -3
  54. bbot/modules/chaos.py +9 -7
  55. bbot/modules/code_repository.py +1 -0
  56. bbot/modules/columbus.py +3 -3
  57. bbot/modules/crt.py +5 -3
  58. bbot/modules/deadly/dastardly.py +1 -1
  59. bbot/modules/deadly/ffuf.py +9 -9
  60. bbot/modules/deadly/nuclei.py +3 -3
  61. bbot/modules/deadly/vhost.py +4 -3
  62. bbot/modules/dehashed.py +1 -1
  63. bbot/modules/digitorus.py +1 -1
  64. bbot/modules/dnsbimi.py +145 -0
  65. bbot/modules/dnscaa.py +3 -3
  66. bbot/modules/dnsdumpster.py +4 -4
  67. bbot/modules/dnstlsrpt.py +144 -0
  68. bbot/modules/docker_pull.py +7 -5
  69. bbot/modules/dockerhub.py +2 -2
  70. bbot/modules/dotnetnuke.py +18 -19
  71. bbot/modules/emailformat.py +1 -1
  72. bbot/modules/extractous.py +122 -0
  73. bbot/modules/filedownload.py +9 -7
  74. bbot/modules/fullhunt.py +7 -4
  75. bbot/modules/generic_ssrf.py +5 -5
  76. bbot/modules/github_codesearch.py +3 -2
  77. bbot/modules/github_org.py +4 -4
  78. bbot/modules/github_workflows.py +4 -4
  79. bbot/modules/gitlab.py +2 -5
  80. bbot/modules/google_playstore.py +93 -0
  81. bbot/modules/gowitness.py +48 -50
  82. bbot/modules/hackertarget.py +5 -3
  83. bbot/modules/host_header.py +5 -5
  84. bbot/modules/httpx.py +1 -4
  85. bbot/modules/hunterio.py +3 -9
  86. bbot/modules/iis_shortnames.py +19 -30
  87. bbot/modules/internal/cloudcheck.py +27 -12
  88. bbot/modules/internal/dnsresolve.py +250 -276
  89. bbot/modules/internal/excavate.py +100 -64
  90. bbot/modules/internal/speculate.py +42 -33
  91. bbot/modules/internetdb.py +4 -2
  92. bbot/modules/ip2location.py +3 -5
  93. bbot/modules/ipneighbor.py +1 -1
  94. bbot/modules/ipstack.py +3 -8
  95. bbot/modules/jadx.py +87 -0
  96. bbot/modules/leakix.py +11 -10
  97. bbot/modules/myssl.py +2 -2
  98. bbot/modules/newsletters.py +2 -2
  99. bbot/modules/otx.py +5 -3
  100. bbot/modules/output/asset_inventory.py +7 -7
  101. bbot/modules/output/base.py +1 -1
  102. bbot/modules/output/csv.py +1 -2
  103. bbot/modules/output/http.py +20 -14
  104. bbot/modules/output/mysql.py +51 -0
  105. bbot/modules/output/neo4j.py +7 -2
  106. bbot/modules/output/postgres.py +49 -0
  107. bbot/modules/output/slack.py +0 -1
  108. bbot/modules/output/sqlite.py +29 -0
  109. bbot/modules/output/stdout.py +2 -2
  110. bbot/modules/output/teams.py +107 -6
  111. bbot/modules/paramminer_headers.py +5 -8
  112. bbot/modules/passivetotal.py +13 -13
  113. bbot/modules/portscan.py +32 -6
  114. bbot/modules/postman.py +50 -126
  115. bbot/modules/postman_download.py +220 -0
  116. bbot/modules/rapiddns.py +3 -8
  117. bbot/modules/report/asn.py +11 -11
  118. bbot/modules/robots.py +3 -3
  119. bbot/modules/securitytrails.py +7 -10
  120. bbot/modules/securitytxt.py +128 -0
  121. bbot/modules/shodan_dns.py +7 -9
  122. bbot/modules/sitedossier.py +1 -1
  123. bbot/modules/skymem.py +2 -2
  124. bbot/modules/social.py +2 -1
  125. bbot/modules/subdomaincenter.py +1 -1
  126. bbot/modules/subdomainradar.py +160 -0
  127. bbot/modules/telerik.py +8 -8
  128. bbot/modules/templates/bucket.py +1 -1
  129. bbot/modules/templates/github.py +22 -14
  130. bbot/modules/templates/postman.py +21 -0
  131. bbot/modules/templates/shodan.py +14 -13
  132. bbot/modules/templates/sql.py +95 -0
  133. bbot/modules/templates/subdomain_enum.py +53 -17
  134. bbot/modules/templates/webhook.py +2 -4
  135. bbot/modules/trickest.py +8 -37
  136. bbot/modules/trufflehog.py +18 -3
  137. bbot/modules/url_manipulation.py +3 -3
  138. bbot/modules/urlscan.py +1 -1
  139. bbot/modules/viewdns.py +1 -1
  140. bbot/modules/virustotal.py +8 -30
  141. bbot/modules/wafw00f.py +1 -1
  142. bbot/modules/wayback.py +1 -1
  143. bbot/modules/wpscan.py +17 -11
  144. bbot/modules/zoomeye.py +11 -6
  145. bbot/presets/baddns-thorough.yml +12 -0
  146. bbot/presets/fast.yml +16 -0
  147. bbot/presets/kitchen-sink.yml +1 -0
  148. bbot/presets/spider.yml +4 -0
  149. bbot/presets/subdomain-enum.yml +7 -7
  150. bbot/scanner/manager.py +5 -16
  151. bbot/scanner/preset/args.py +44 -26
  152. bbot/scanner/preset/environ.py +7 -2
  153. bbot/scanner/preset/path.py +7 -4
  154. bbot/scanner/preset/preset.py +36 -23
  155. bbot/scanner/scanner.py +176 -63
  156. bbot/scanner/target.py +236 -434
  157. bbot/scripts/docs.py +1 -1
  158. bbot/test/bbot_fixtures.py +22 -3
  159. bbot/test/conftest.py +132 -100
  160. bbot/test/fastapi_test.py +17 -0
  161. bbot/test/owasp_mastg.apk +0 -0
  162. bbot/test/run_tests.sh +4 -4
  163. bbot/test/test.conf +2 -0
  164. bbot/test/test_step_1/test_bbot_fastapi.py +82 -0
  165. bbot/test/test_step_1/test_bloom_filter.py +2 -0
  166. bbot/test/test_step_1/test_cli.py +138 -64
  167. bbot/test/test_step_1/test_dns.py +392 -70
  168. bbot/test/test_step_1/test_engine.py +17 -17
  169. bbot/test/test_step_1/test_events.py +203 -37
  170. bbot/test/test_step_1/test_helpers.py +64 -28
  171. bbot/test/test_step_1/test_manager_deduplication.py +1 -1
  172. bbot/test/test_step_1/test_manager_scope_accuracy.py +336 -338
  173. bbot/test/test_step_1/test_modules_basic.py +69 -71
  174. bbot/test/test_step_1/test_presets.py +184 -96
  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 +5 -4
  179. bbot/test/test_step_1/test_target.py +243 -145
  180. bbot/test/test_step_1/test_web.py +48 -10
  181. bbot/test/test_step_2/module_tests/base.py +17 -20
  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 +17 -37
  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 -4
  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 +24 -11
  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 +6 -6
  233. bbot/test/test_step_2/module_tests/test_module_ntlm.py +7 -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_portscan.py +9 -8
  241. bbot/test/test_step_2/module_tests/test_module_postgres.py +74 -0
  242. bbot/test/test_step_2/module_tests/test_module_postman.py +84 -253
  243. bbot/test/test_step_2/module_tests/test_module_postman_download.py +439 -0
  244. bbot/test/test_step_2/module_tests/test_module_rapiddns.py +93 -1
  245. bbot/test/test_step_2/module_tests/test_module_securitytxt.py +50 -0
  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 +1 -1
  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 +2 -6
  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 -11
  261. bbot/test/test_step_2/module_tests/test_module_wayback.py +1 -1
  262. bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py +135 -0
  263. {bbot-2.0.1.4654rc0.dist-info → bbot-2.3.0.5397rc0.dist-info}/METADATA +48 -18
  264. bbot-2.3.0.5397rc0.dist-info/RECORD +421 -0
  265. {bbot-2.0.1.4654rc0.dist-info → bbot-2.3.0.5397rc0.dist-info}/WHEEL +1 -1
  266. bbot/modules/unstructured.py +0 -163
  267. bbot/test/test_step_2/module_tests/test_module_unstructured.py +0 -102
  268. bbot-2.0.1.4654rc0.dist-info/RECORD +0 -385
  269. {bbot-2.0.1.4654rc0.dist-info → bbot-2.3.0.5397rc0.dist-info}/LICENSE +0 -0
  270. {bbot-2.0.1.4654rc0.dist-info → bbot-2.3.0.5397rc0.dist-info}/entry_points.txt +0 -0
@@ -4,6 +4,7 @@ import ipaddress
4
4
 
5
5
  from ..bbot_fixtures import *
6
6
  from bbot.scanner import Scanner
7
+ from bbot.core.helpers.regexes import event_uuid_regex
7
8
 
8
9
 
9
10
  @pytest.mark.asyncio
@@ -13,10 +14,19 @@ async def test_events(events, helpers):
13
14
  await scan._prep()
14
15
 
15
16
  assert events.ipv4.type == "IP_ADDRESS"
17
+ assert events.ipv4.netloc == "8.8.8.8"
18
+ assert events.ipv4.port is None
16
19
  assert events.ipv6.type == "IP_ADDRESS"
20
+ assert events.ipv6.netloc == "[2001:4860:4860::8888]"
21
+ assert events.ipv6.port is None
22
+ assert events.ipv6_open_port.netloc == "[2001:4860:4860::8888]:443"
17
23
  assert events.netv4.type == "IP_RANGE"
24
+ assert events.netv4.netloc is None
25
+ assert "netloc" not in events.netv4.json()
18
26
  assert events.netv6.type == "IP_RANGE"
19
27
  assert events.domain.type == "DNS_NAME"
28
+ assert events.domain.netloc == "publicapis.org"
29
+ assert events.domain.port is None
20
30
  assert "domain" in events.domain.tags
21
31
  assert events.subdomain.type == "DNS_NAME"
22
32
  assert "subdomain" in events.subdomain.tags
@@ -32,6 +42,7 @@ async def test_events(events, helpers):
32
42
  # ip tests
33
43
  assert events.ipv4 == scan.make_event("8.8.8.8", dummy=True)
34
44
  assert "8.8.8.8" in events.ipv4
45
+ assert events.ipv4.host_filterable == "8.8.8.8"
35
46
  assert "8.8.8.8" == events.ipv4
36
47
  assert "8.8.8.8" in events.netv4
37
48
  assert "8.8.8.9" not in events.ipv4
@@ -49,11 +60,19 @@ async def test_events(events, helpers):
49
60
  assert events.emoji not in events.ipv4
50
61
  assert events.emoji not in events.netv6
51
62
  assert events.netv6 not in events.emoji
52
- assert "dead::c0de" == scan.make_event(" [DEaD::c0De]:88", "DNS_NAME", dummy=True)
63
+ ipv6_event = scan.make_event(" [DEaD::c0De]:88", "DNS_NAME", dummy=True)
64
+ assert "dead::c0de" == ipv6_event
65
+ assert ipv6_event.host_filterable == "dead::c0de"
66
+ range_to_ip = scan.make_event("1.2.3.4/32", dummy=True)
67
+ assert range_to_ip.type == "IP_ADDRESS"
68
+ range_to_ip = scan.make_event("dead::beef/128", dummy=True)
69
+ assert range_to_ip.type == "IP_ADDRESS"
53
70
 
54
71
  # hostname tests
55
72
  assert events.domain.host == "publicapis.org"
73
+ assert events.domain.host_filterable == "publicapis.org"
56
74
  assert events.subdomain.host == "api.publicapis.org"
75
+ assert events.subdomain.host_filterable == "api.publicapis.org"
57
76
  assert events.domain.host_stem == "publicapis"
58
77
  assert events.subdomain.host_stem == "api.publicapis"
59
78
  assert "api.publicapis.org" in events.domain
@@ -62,23 +81,39 @@ async def test_events(events, helpers):
62
81
  assert "fsocie.ty" not in events.subdomain
63
82
  assert events.subdomain in events.domain
64
83
  assert events.domain not in events.subdomain
65
- assert not events.ipv4 in events.domain
66
- assert not events.netv6 in events.domain
84
+ assert events.ipv4 not in events.domain
85
+ assert events.netv6 not in events.domain
67
86
  assert events.emoji not in events.domain
68
87
  assert events.domain not in events.emoji
69
- assert "evilcorp.com" == scan.make_event(" eViLcorp.COM.:88", "DNS_NAME", dummy=True)
70
- assert "evilcorp.com" == scan.make_event("evilcorp.com.", "DNS_NAME", dummy=True)
88
+ open_port_event = scan.make_event(" eViLcorp.COM.:88", "DNS_NAME", dummy=True)
89
+ dns_event = scan.make_event("evilcorp.com.", "DNS_NAME", dummy=True)
90
+ for e in (open_port_event, dns_event):
91
+ assert "evilcorp.com" == e
92
+ assert e.netloc == "evilcorp.com"
93
+ assert e.json()["netloc"] == "evilcorp.com"
94
+ assert e.port is None
95
+ assert "port" not in e.json()
71
96
 
72
97
  # url tests
73
- assert scan.make_event("http://evilcorp.com", dummy=True) == scan.make_event("http://evilcorp.com/", dummy=True)
98
+ url_no_trailing_slash = scan.make_event("http://evilcorp.com", dummy=True)
99
+ url_trailing_slash = scan.make_event("http://evilcorp.com/", dummy=True)
100
+ assert url_no_trailing_slash == url_trailing_slash
101
+ assert url_no_trailing_slash.host_filterable == "http://evilcorp.com/"
102
+ assert url_trailing_slash.host_filterable == "http://evilcorp.com/"
74
103
  assert events.url_unverified.host == "api.publicapis.org"
75
104
  assert events.url_unverified in events.domain
76
105
  assert events.url_unverified in events.subdomain
77
106
  assert "api.publicapis.org:443" in events.url_unverified
78
107
  assert "publicapis.org" not in events.url_unverified
79
108
  assert events.ipv4_url_unverified in events.ipv4
109
+ assert events.ipv4_url_unverified.netloc == "8.8.8.8:443"
110
+ assert events.ipv4_url_unverified.port == 443
111
+ assert events.ipv4_url_unverified.json()["port"] == 443
80
112
  assert events.ipv4_url_unverified in events.netv4
81
113
  assert events.ipv6_url_unverified in events.ipv6
114
+ assert events.ipv6_url_unverified.netloc == "[2001:4860:4860::8888]:443"
115
+ assert events.ipv6_url_unverified.port == 443
116
+ assert events.ipv6_url_unverified.json()["port"] == 443
82
117
  assert events.ipv6_url_unverified in events.netv6
83
118
  assert events.emoji not in events.url_unverified
84
119
  assert events.emoji not in events.ipv6_url_unverified
@@ -107,6 +142,7 @@ async def test_events(events, helpers):
107
142
  assert events.http_response.port == 80
108
143
  assert events.http_response.parsed_url.scheme == "http"
109
144
  assert events.http_response.with_port().geturl() == "http://example.com:80/"
145
+ assert events.http_response.host_filterable == "http://example.com/"
110
146
 
111
147
  http_response = scan.make_event(
112
148
  {
@@ -171,7 +207,7 @@ async def test_events(events, helpers):
171
207
 
172
208
  # scope distance
173
209
  event1 = scan.make_event("1.2.3.4", dummy=True)
174
- assert event1._scope_distance == None
210
+ assert event1._scope_distance is None
175
211
  event1.scope_distance = 0
176
212
  assert event1._scope_distance == 0
177
213
  event2 = scan.make_event("2.3.4.5", parent=event1)
@@ -192,6 +228,8 @@ async def test_events(events, helpers):
192
228
 
193
229
  org_stub_1 = scan.make_event("STUB1", "ORG_STUB", parent=scan.root_event)
194
230
  org_stub_1.scope_distance == 1
231
+ assert org_stub_1.netloc is None
232
+ assert "netloc" not in org_stub_1.json()
195
233
  org_stub_2 = scan.make_event("STUB2", "ORG_STUB", parent=org_stub_1)
196
234
  org_stub_2.scope_distance == 2
197
235
 
@@ -199,7 +237,7 @@ async def test_events(events, helpers):
199
237
  root_event = scan.make_event("0.0.0.0", dummy=True)
200
238
  root_event.scope_distance = 0
201
239
  internal_event1 = scan.make_event("1.2.3.4", parent=root_event, internal=True)
202
- assert internal_event1._internal == True
240
+ assert internal_event1._internal is True
203
241
  assert "internal" in internal_event1.tags
204
242
 
205
243
  # tag inheritance
@@ -231,8 +269,8 @@ async def test_events(events, helpers):
231
269
  # updating module
232
270
  event3 = scan.make_event("127.0.0.1", parent=scan.root_event)
233
271
  updated_event = scan.make_event(event3, internal=True)
234
- assert event3.internal == False
235
- assert updated_event.internal == True
272
+ assert event3.internal is False
273
+ assert updated_event.internal is True
236
274
 
237
275
  # event sorting
238
276
  parent1 = scan.make_event("127.0.0.1", parent=scan.root_event)
@@ -311,6 +349,16 @@ async def test_events(events, helpers):
311
349
  {"host": "evilcorp.com", "severity": "WACK", "description": "asdf"}, "VULNERABILITY", dummy=True
312
350
  )
313
351
 
352
+ # test tagging
353
+ ip_event_1 = scan.make_event("8.8.8.8", dummy=True)
354
+ assert "private-ip" not in ip_event_1.tags
355
+ ip_event_2 = scan.make_event("192.168.0.1", dummy=True)
356
+ assert "private-ip" in ip_event_2.tags
357
+ dns_event_1 = scan.make_event("evilcorp.com", dummy=True)
358
+ assert "domain" in dns_event_1.tags
359
+ dns_event_2 = scan.make_event("www.evilcorp.com", dummy=True)
360
+ assert "subdomain" in dns_event_2.tags
361
+
314
362
  # punycode - event type detection
315
363
 
316
364
  # japanese
@@ -402,39 +450,84 @@ async def test_events(events, helpers):
402
450
  == "http://xn--12c1bik6bbd8ab6hd1b5jc6jta.com/ทดสอบ"
403
451
  )
404
452
 
453
+ # test event uuid
454
+ import uuid
455
+
456
+ parent_event1 = scan.make_event("evilcorp.com", parent=scan.root_event, context="test context")
457
+ parent_event2 = scan.make_event("evilcorp.com", parent=scan.root_event, context="test context")
458
+
459
+ event1 = scan.make_event("evilcorp.com:80", parent=parent_event1, context="test context")
460
+ assert hasattr(event1, "_uuid")
461
+ assert hasattr(event1, "uuid")
462
+ assert isinstance(event1._uuid, uuid.UUID)
463
+ assert isinstance(event1.uuid, str)
464
+ assert event1.uuid == f"{event1.type}:{event1._uuid}"
465
+ event2 = scan.make_event("evilcorp.com:80", parent=parent_event2, context="test context")
466
+ assert hasattr(event2, "_uuid")
467
+ assert hasattr(event2, "uuid")
468
+ assert isinstance(event2._uuid, uuid.UUID)
469
+ assert isinstance(event2.uuid, str)
470
+ assert event2.uuid == f"{event2.type}:{event2._uuid}"
471
+ # ids should match because the event type + data is the same
472
+ assert event1.id == event2.id
473
+ # but uuids should be unique!
474
+ assert event1.uuid != event2.uuid
475
+ # parent ids should match
476
+ assert event1.parent_id == event2.parent_id == parent_event1.id == parent_event2.id
477
+ # uuids should not
478
+ assert event1.parent_uuid == parent_event1.uuid
479
+ assert event2.parent_uuid == parent_event2.uuid
480
+ assert event1.parent_uuid != event2.parent_uuid
481
+
405
482
  # test event serialization
406
483
  from bbot.core.event import event_from_json
407
484
 
408
485
  db_event = scan.make_event("evilcorp.com:80", parent=scan.root_event, context="test context")
486
+ assert db_event.parent == scan.root_event
487
+ assert db_event.parent is scan.root_event
409
488
  db_event._resolved_hosts = {"127.0.0.1"}
410
489
  db_event.scope_distance = 1
411
490
  assert db_event.discovery_context == "test context"
412
- assert db_event.discovery_path == [["OPEN_TCP_PORT:5098b5e3fc65b13bb4a5cee4201c2e160fa4ffac", "test context"]]
491
+ assert db_event.discovery_path == ["test context"]
492
+ assert len(db_event.parent_chain) == 1
493
+ assert all(event_uuid_regex.match(u) for u in db_event.parent_chain)
494
+ assert db_event.parent_chain[0] == str(db_event.uuid)
495
+ assert db_event.parent.uuid == scan.root_event.uuid
496
+ assert db_event.parent_uuid == scan.root_event.uuid
413
497
  timestamp = db_event.timestamp.isoformat()
414
498
  json_event = db_event.json()
499
+ assert isinstance(json_event["uuid"], str)
500
+ assert json_event["uuid"] == str(db_event.uuid)
501
+ assert json_event["parent_uuid"] == str(scan.root_event.uuid)
415
502
  assert json_event["scope_distance"] == 1
416
503
  assert json_event["data"] == "evilcorp.com:80"
417
504
  assert json_event["type"] == "OPEN_TCP_PORT"
418
505
  assert json_event["host"] == "evilcorp.com"
419
506
  assert json_event["timestamp"] == timestamp
420
507
  assert json_event["discovery_context"] == "test context"
421
- assert json_event["discovery_path"] == [["OPEN_TCP_PORT:5098b5e3fc65b13bb4a5cee4201c2e160fa4ffac", "test context"]]
508
+ assert json_event["discovery_path"] == ["test context"]
509
+ assert json_event["parent_chain"] == db_event.parent_chain
510
+ assert json_event["parent_chain"][0] == str(db_event.uuid)
422
511
  reconstituted_event = event_from_json(json_event)
512
+ assert isinstance(reconstituted_event._uuid, uuid.UUID)
513
+ assert str(reconstituted_event.uuid) == json_event["uuid"]
514
+ assert str(reconstituted_event.parent_uuid) == json_event["parent_uuid"]
515
+ assert reconstituted_event.uuid == db_event.uuid
516
+ assert reconstituted_event.parent_uuid == scan.root_event.uuid
423
517
  assert reconstituted_event.scope_distance == 1
424
518
  assert reconstituted_event.timestamp.isoformat() == timestamp
425
519
  assert reconstituted_event.data == "evilcorp.com:80"
426
520
  assert reconstituted_event.type == "OPEN_TCP_PORT"
427
521
  assert reconstituted_event.host == "evilcorp.com"
428
522
  assert reconstituted_event.discovery_context == "test context"
429
- assert reconstituted_event.discovery_path == [
430
- ["OPEN_TCP_PORT:5098b5e3fc65b13bb4a5cee4201c2e160fa4ffac", "test context"]
431
- ]
523
+ assert reconstituted_event.discovery_path == ["test context"]
524
+ assert reconstituted_event.parent_chain == db_event.parent_chain
432
525
  assert "127.0.0.1" in reconstituted_event.resolved_hosts
433
526
  hostless_event = scan.make_event("asdf", "ASDF", dummy=True)
434
527
  hostless_event_json = hostless_event.json()
435
528
  assert hostless_event_json["type"] == "ASDF"
436
529
  assert hostless_event_json["data"] == "asdf"
437
- assert not "host" in hostless_event_json
530
+ assert "host" not in hostless_event_json
438
531
 
439
532
  # SIEM-friendly serialize/deserialize
440
533
  json_event_siemfriendly = db_event.json(siem_friendly=True)
@@ -605,7 +698,7 @@ async def test_event_discovery_context():
605
698
  )
606
699
 
607
700
  events = [e async for e in scan.async_start()]
608
- assert len(events) == 6
701
+ assert len(events) == 7
609
702
 
610
703
  assert 1 == len(
611
704
  [
@@ -614,7 +707,7 @@ async def test_event_discovery_context():
614
707
  if e.type == "DNS_NAME"
615
708
  and e.data == "evilcorp.com"
616
709
  and e.discovery_context == f"Scan {scan.name} seeded with DNS_NAME: evilcorp.com"
617
- and [_[-1] for _ in e.discovery_path] == [f"Scan {scan.name} seeded with DNS_NAME: evilcorp.com"]
710
+ and e.discovery_path == [f"Scan {scan.name} seeded with DNS_NAME: evilcorp.com"]
618
711
  ]
619
712
  )
620
713
  assert 1 == len(
@@ -624,7 +717,7 @@ async def test_event_discovery_context():
624
717
  if e.type == "DNS_NAME"
625
718
  and e.data == "one.evilcorp.com"
626
719
  and e.discovery_context == "module_1 invoked forbidden magick to discover DNS_NAME one.evilcorp.com"
627
- and [_[-1] for _ in e.discovery_path]
720
+ and e.discovery_path
628
721
  == [
629
722
  f"Scan {scan.name} seeded with DNS_NAME: evilcorp.com",
630
723
  "module_1 invoked forbidden magick to discover DNS_NAME one.evilcorp.com",
@@ -639,7 +732,7 @@ async def test_event_discovery_context():
639
732
  and e.data == "two.evilcorp.com"
640
733
  and e.discovery_context
641
734
  == "module_1 pledged its allegiance to cthulu and was awarded DNS_NAME two.evilcorp.com"
642
- and [_[-1] for _ in e.discovery_path]
735
+ and e.discovery_path
643
736
  == [
644
737
  f"Scan {scan.name} seeded with DNS_NAME: evilcorp.com",
645
738
  "module_1 invoked forbidden magick to discover DNS_NAME one.evilcorp.com",
@@ -654,7 +747,7 @@ async def test_event_discovery_context():
654
747
  if e.type == "DNS_NAME"
655
748
  and e.data == "three.evilcorp.com"
656
749
  and e.discovery_context == "module_2 asked nicely and was given DNS_NAME three.evilcorp.com"
657
- and [_[-1] for _ in e.discovery_path]
750
+ and e.discovery_path
658
751
  == [
659
752
  f"Scan {scan.name} seeded with DNS_NAME: evilcorp.com",
660
753
  "module_1 invoked forbidden magick to discover DNS_NAME one.evilcorp.com",
@@ -676,11 +769,11 @@ async def test_event_discovery_context():
676
769
  if e.type == "DNS_NAME"
677
770
  and e.data == "four.evilcorp.com"
678
771
  and e.discovery_context == "module_2 used brute force to obtain DNS_NAME four.evilcorp.com"
679
- and [_[-1] for _ in e.discovery_path] == final_path
772
+ and e.discovery_path == final_path
680
773
  ]
681
774
  assert 1 == len(final_event)
682
775
  j = final_event[0].json()
683
- assert [_[-1] for _ in j["discovery_path"]] == final_path
776
+ assert j["discovery_path"] == final_path
684
777
 
685
778
  await scan._cleanup()
686
779
 
@@ -693,7 +786,7 @@ async def test_event_discovery_context():
693
786
  events = [e async for e in scan.async_start()]
694
787
  blsops_event = [e for e in events if e.type == "DNS_NAME" and e.data == "blsops.com"]
695
788
  assert len(blsops_event) == 1
696
- assert blsops_event[0].discovery_path[1][-1] == "URL_UNVERIFIED has host DNS_NAME: blacklanternsecurity.com"
789
+ assert blsops_event[0].discovery_path[1] == "URL_UNVERIFIED has host DNS_NAME: blacklanternsecurity.com"
697
790
 
698
791
  await scan._cleanup()
699
792
 
@@ -712,7 +805,7 @@ async def test_event_web_spider_distance(bbot_scanner):
712
805
  )
713
806
  assert url_event_3.web_spider_distance == 1
714
807
  assert "spider-danger" in url_event_3.tags
715
- assert not "spider-max" in url_event_3.tags
808
+ assert "spider-max" not in url_event_3.tags
716
809
  social_event = scan.make_event(
717
810
  {"platform": "github", "url": "http://www.evilcorp.com/test4"}, "SOCIAL", parent=url_event_3
718
811
  )
@@ -735,42 +828,42 @@ async def test_event_web_spider_distance(bbot_scanner):
735
828
 
736
829
  url_event = scan.make_event("http://www.evilcorp.com", "URL_UNVERIFIED", parent=scan.root_event)
737
830
  assert url_event.web_spider_distance == 0
738
- assert not "spider-danger" in url_event.tags
739
- assert not "spider-max" in url_event.tags
831
+ assert "spider-danger" not in url_event.tags
832
+ assert "spider-max" not in url_event.tags
740
833
  url_event_2 = scan.make_event(
741
834
  "http://www.evilcorp.com", "URL_UNVERIFIED", parent=scan.root_event, tags="spider-danger"
742
835
  )
743
836
  # spider distance shouldn't increment because it's not the same host
744
837
  assert url_event_2.web_spider_distance == 0
745
838
  assert "spider-danger" in url_event_2.tags
746
- assert not "spider-max" in url_event_2.tags
839
+ assert "spider-max" not in url_event_2.tags
747
840
  url_event_3 = scan.make_event(
748
841
  "http://www.evilcorp.com/3", "URL_UNVERIFIED", parent=url_event_2, tags="spider-danger"
749
842
  )
750
843
  assert url_event_3.web_spider_distance == 1
751
844
  assert "spider-danger" in url_event_3.tags
752
- assert not "spider-max" in url_event_3.tags
845
+ assert "spider-max" not in url_event_3.tags
753
846
  url_event_4 = scan.make_event("http://evilcorp.com", "URL_UNVERIFIED", parent=url_event_3)
754
847
  assert url_event_4.web_spider_distance == 0
755
- assert not "spider-danger" in url_event_4.tags
756
- assert not "spider-max" in url_event_4.tags
848
+ assert "spider-danger" not in url_event_4.tags
849
+ assert "spider-max" not in url_event_4.tags
757
850
  url_event_4.add_tag("spider-danger")
758
851
  assert url_event_4.web_spider_distance == 0
759
852
  assert "spider-danger" in url_event_4.tags
760
- assert not "spider-max" in url_event_4.tags
853
+ assert "spider-max" not in url_event_4.tags
761
854
  url_event_4.remove_tag("spider-danger")
762
855
  assert url_event_4.web_spider_distance == 0
763
- assert not "spider-danger" in url_event_4.tags
764
- assert not "spider-max" in url_event_4.tags
856
+ assert "spider-danger" not in url_event_4.tags
857
+ assert "spider-max" not in url_event_4.tags
765
858
  url_event_5 = scan.make_event("http://evilcorp.com/5", "URL_UNVERIFIED", parent=url_event_4)
766
859
  assert url_event_5.web_spider_distance == 0
767
- assert not "spider-danger" in url_event_5.tags
768
- assert not "spider-max" in url_event_5.tags
860
+ assert "spider-danger" not in url_event_5.tags
861
+ assert "spider-max" not in url_event_5.tags
769
862
  url_event_5.add_tag("spider-danger")
770
863
  # if host is the same as parent, web spider distance should auto-increment after adding spider-danger tag
771
864
  assert url_event_5.web_spider_distance == 1
772
865
  assert "spider-danger" in url_event_5.tags
773
- assert not "spider-max" in url_event_5.tags
866
+ assert "spider-max" not in url_event_5.tags
774
867
 
775
868
 
776
869
  def test_event_confidence():
@@ -845,3 +938,76 @@ def test_event_closest_host():
845
938
  vuln = scan.make_event(
846
939
  {"path": "/tmp/asdf.txt", "description": "test", "severity": "HIGH"}, "VULNERABILITY", parent=event3
847
940
  )
941
+
942
+
943
+ def test_event_magic():
944
+ from bbot.core.helpers.libmagic import get_magic_info, get_compression
945
+
946
+ import base64
947
+
948
+ zip_base64 = "UEsDBAoDAAAAAOMmZ1lR4FaHBQAAAAUAAAAIAAAAYXNkZi50eHRhc2RmClBLAQI/AwoDAAAAAOMmZ1lR4FaHBQAAAAUAAAAIACQAAAAAAAAAIICkgQAAAABhc2RmLnR4dAoAIAAAAAAAAQAYAICi2B77MNsBgKLYHvsw2wGAotge+zDbAVBLBQYAAAAAAQABAFoAAAArAAAAAAA="
949
+ zip_bytes = base64.b64decode(zip_base64)
950
+ zip_file = Path("/tmp/.bbottestzipasdkfjalsdf.zip")
951
+ with open(zip_file, "wb") as f:
952
+ f.write(zip_bytes)
953
+
954
+ # test magic helpers
955
+ extension, mime_type, description, confidence = get_magic_info(zip_file)
956
+ assert extension == ".zip"
957
+ assert mime_type == "application/zip"
958
+ assert description == "PKZIP Archive file"
959
+ assert confidence > 0
960
+ assert get_compression(mime_type) == "zip"
961
+
962
+ # test filesystem event - file
963
+ scan = Scanner()
964
+ event = scan.make_event({"path": zip_file}, "FILESYSTEM", parent=scan.root_event)
965
+ assert event.data == {
966
+ "path": "/tmp/.bbottestzipasdkfjalsdf.zip",
967
+ "magic_extension": ".zip",
968
+ "magic_mime_type": "application/zip",
969
+ "magic_description": "PKZIP Archive file",
970
+ "magic_confidence": 0.9,
971
+ "compression": "zip",
972
+ }
973
+ assert event.tags == {"file", "zip-archive", "compressed"}
974
+
975
+ # test filesystem event - folder
976
+ scan = Scanner()
977
+ event = scan.make_event({"path": "/tmp"}, "FILESYSTEM", parent=scan.root_event)
978
+ assert event.data == {"path": "/tmp"}
979
+ assert event.tags == {"folder"}
980
+
981
+ zip_file.unlink()
982
+
983
+
984
+ def test_event_hashing():
985
+ scan = Scanner("example.com")
986
+ url_event = scan.make_event("https://api.example.com/", "URL_UNVERIFIED", parent=scan.root_event)
987
+ host_event_1 = scan.make_event("www.example.com", "DNS_NAME", parent=url_event)
988
+ host_event_2 = scan.make_event("test.example.com", "DNS_NAME", parent=url_event)
989
+ finding_data = {"description": "Custom Yara Rule [find_string] Matched via identifier [str1]"}
990
+ finding1 = scan.make_event(finding_data, "FINDING", parent=host_event_1)
991
+ finding2 = scan.make_event(finding_data, "FINDING", parent=host_event_2)
992
+ finding3 = scan.make_event(finding_data, "FINDING", parent=host_event_2)
993
+
994
+ assert finding1.data == {
995
+ "description": "Custom Yara Rule [find_string] Matched via identifier [str1]",
996
+ "host": "www.example.com",
997
+ }
998
+ assert finding2.data == {
999
+ "description": "Custom Yara Rule [find_string] Matched via identifier [str1]",
1000
+ "host": "test.example.com",
1001
+ }
1002
+ assert finding3.data == {
1003
+ "description": "Custom Yara Rule [find_string] Matched via identifier [str1]",
1004
+ "host": "test.example.com",
1005
+ }
1006
+ assert finding1.id != finding2.id
1007
+ assert finding2.id == finding3.id
1008
+ assert finding1.data_id != finding2.data_id
1009
+ assert finding2.data_id == finding3.data_id
1010
+ assert finding1.data_hash != finding2.data_hash
1011
+ assert finding2.data_hash == finding3.data_hash
1012
+ assert hash(finding1) != hash(finding2)
1013
+ assert hash(finding2) == hash(finding3)