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
@@ -4,19 +4,28 @@ 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
10
11
  async def test_events(events, helpers):
11
-
12
12
  scan = Scanner()
13
13
  await scan._prep()
14
14
 
15
15
  assert events.ipv4.type == "IP_ADDRESS"
16
+ assert events.ipv4.netloc == "8.8.8.8"
17
+ assert events.ipv4.port is None
16
18
  assert events.ipv6.type == "IP_ADDRESS"
19
+ assert events.ipv6.netloc == "[2001:4860:4860::8888]"
20
+ assert events.ipv6.port is None
21
+ assert events.ipv6_open_port.netloc == "[2001:4860:4860::8888]:443"
17
22
  assert events.netv4.type == "IP_RANGE"
23
+ assert events.netv4.netloc is None
24
+ assert "netloc" not in events.netv4.json()
18
25
  assert events.netv6.type == "IP_RANGE"
19
26
  assert events.domain.type == "DNS_NAME"
27
+ assert events.domain.netloc == "publicapis.org"
28
+ assert events.domain.port is None
20
29
  assert "domain" in events.domain.tags
21
30
  assert events.subdomain.type == "DNS_NAME"
22
31
  assert "subdomain" in events.subdomain.tags
@@ -32,6 +41,7 @@ async def test_events(events, helpers):
32
41
  # ip tests
33
42
  assert events.ipv4 == scan.make_event("8.8.8.8", dummy=True)
34
43
  assert "8.8.8.8" in events.ipv4
44
+ assert events.ipv4.host_filterable == "8.8.8.8"
35
45
  assert "8.8.8.8" == events.ipv4
36
46
  assert "8.8.8.8" in events.netv4
37
47
  assert "8.8.8.9" not in events.ipv4
@@ -49,11 +59,19 @@ async def test_events(events, helpers):
49
59
  assert events.emoji not in events.ipv4
50
60
  assert events.emoji not in events.netv6
51
61
  assert events.netv6 not in events.emoji
52
- assert "dead::c0de" == scan.make_event(" [DEaD::c0De]:88", "DNS_NAME", dummy=True)
62
+ ipv6_event = scan.make_event(" [DEaD::c0De]:88", "DNS_NAME", dummy=True)
63
+ assert "dead::c0de" == ipv6_event
64
+ assert ipv6_event.host_filterable == "dead::c0de"
65
+ range_to_ip = scan.make_event("1.2.3.4/32", dummy=True)
66
+ assert range_to_ip.type == "IP_ADDRESS"
67
+ range_to_ip = scan.make_event("dead::beef/128", dummy=True)
68
+ assert range_to_ip.type == "IP_ADDRESS"
53
69
 
54
70
  # hostname tests
55
71
  assert events.domain.host == "publicapis.org"
72
+ assert events.domain.host_filterable == "publicapis.org"
56
73
  assert events.subdomain.host == "api.publicapis.org"
74
+ assert events.subdomain.host_filterable == "api.publicapis.org"
57
75
  assert events.domain.host_stem == "publicapis"
58
76
  assert events.subdomain.host_stem == "api.publicapis"
59
77
  assert "api.publicapis.org" in events.domain
@@ -62,23 +80,39 @@ async def test_events(events, helpers):
62
80
  assert "fsocie.ty" not in events.subdomain
63
81
  assert events.subdomain in events.domain
64
82
  assert events.domain not in events.subdomain
65
- assert not events.ipv4 in events.domain
66
- assert not events.netv6 in events.domain
83
+ assert events.ipv4 not in events.domain
84
+ assert events.netv6 not in events.domain
67
85
  assert events.emoji not in events.domain
68
86
  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)
87
+ open_port_event = scan.make_event(" eViLcorp.COM.:88", "DNS_NAME", dummy=True)
88
+ dns_event = scan.make_event("evilcorp.com.", "DNS_NAME", dummy=True)
89
+ for e in (open_port_event, dns_event):
90
+ assert "evilcorp.com" == e
91
+ assert e.netloc == "evilcorp.com"
92
+ assert e.json()["netloc"] == "evilcorp.com"
93
+ assert e.port is None
94
+ assert "port" not in e.json()
71
95
 
72
96
  # url tests
73
- assert scan.make_event("http://evilcorp.com", dummy=True) == scan.make_event("http://evilcorp.com/", dummy=True)
97
+ url_no_trailing_slash = scan.make_event("http://evilcorp.com", dummy=True)
98
+ url_trailing_slash = scan.make_event("http://evilcorp.com/", dummy=True)
99
+ assert url_no_trailing_slash == url_trailing_slash
100
+ assert url_no_trailing_slash.host_filterable == "http://evilcorp.com/"
101
+ assert url_trailing_slash.host_filterable == "http://evilcorp.com/"
74
102
  assert events.url_unverified.host == "api.publicapis.org"
75
103
  assert events.url_unverified in events.domain
76
104
  assert events.url_unverified in events.subdomain
77
105
  assert "api.publicapis.org:443" in events.url_unverified
78
106
  assert "publicapis.org" not in events.url_unverified
79
107
  assert events.ipv4_url_unverified in events.ipv4
108
+ assert events.ipv4_url_unverified.netloc == "8.8.8.8:443"
109
+ assert events.ipv4_url_unverified.port == 443
110
+ assert events.ipv4_url_unverified.json()["port"] == 443
80
111
  assert events.ipv4_url_unverified in events.netv4
81
112
  assert events.ipv6_url_unverified in events.ipv6
113
+ assert events.ipv6_url_unverified.netloc == "[2001:4860:4860::8888]:443"
114
+ assert events.ipv6_url_unverified.port == 443
115
+ assert events.ipv6_url_unverified.json()["port"] == 443
82
116
  assert events.ipv6_url_unverified in events.netv6
83
117
  assert events.emoji not in events.url_unverified
84
118
  assert events.emoji not in events.ipv6_url_unverified
@@ -107,6 +141,7 @@ async def test_events(events, helpers):
107
141
  assert events.http_response.port == 80
108
142
  assert events.http_response.parsed_url.scheme == "http"
109
143
  assert events.http_response.with_port().geturl() == "http://example.com:80/"
144
+ assert events.http_response.host_filterable == "http://example.com/"
110
145
 
111
146
  http_response = scan.make_event(
112
147
  {
@@ -171,7 +206,7 @@ async def test_events(events, helpers):
171
206
 
172
207
  # scope distance
173
208
  event1 = scan.make_event("1.2.3.4", dummy=True)
174
- assert event1._scope_distance == None
209
+ assert event1._scope_distance is None
175
210
  event1.scope_distance = 0
176
211
  assert event1._scope_distance == 0
177
212
  event2 = scan.make_event("2.3.4.5", parent=event1)
@@ -192,6 +227,8 @@ async def test_events(events, helpers):
192
227
 
193
228
  org_stub_1 = scan.make_event("STUB1", "ORG_STUB", parent=scan.root_event)
194
229
  org_stub_1.scope_distance == 1
230
+ assert org_stub_1.netloc is None
231
+ assert "netloc" not in org_stub_1.json()
195
232
  org_stub_2 = scan.make_event("STUB2", "ORG_STUB", parent=org_stub_1)
196
233
  org_stub_2.scope_distance == 2
197
234
 
@@ -199,7 +236,7 @@ async def test_events(events, helpers):
199
236
  root_event = scan.make_event("0.0.0.0", dummy=True)
200
237
  root_event.scope_distance = 0
201
238
  internal_event1 = scan.make_event("1.2.3.4", parent=root_event, internal=True)
202
- assert internal_event1._internal == True
239
+ assert internal_event1._internal is True
203
240
  assert "internal" in internal_event1.tags
204
241
 
205
242
  # tag inheritance
@@ -231,8 +268,8 @@ async def test_events(events, helpers):
231
268
  # updating module
232
269
  event3 = scan.make_event("127.0.0.1", parent=scan.root_event)
233
270
  updated_event = scan.make_event(event3, internal=True)
234
- assert event3.internal == False
235
- assert updated_event.internal == True
271
+ assert event3.internal is False
272
+ assert updated_event.internal is True
236
273
 
237
274
  # event sorting
238
275
  parent1 = scan.make_event("127.0.0.1", parent=scan.root_event)
@@ -412,17 +449,55 @@ async def test_events(events, helpers):
412
449
  == "http://xn--12c1bik6bbd8ab6hd1b5jc6jta.com/ทดสอบ"
413
450
  )
414
451
 
452
+ # test event uuid
453
+ import uuid
454
+
455
+ parent_event1 = scan.make_event("evilcorp.com", parent=scan.root_event, context="test context")
456
+ parent_event2 = scan.make_event("evilcorp.com", parent=scan.root_event, context="test context")
457
+
458
+ event1 = scan.make_event("evilcorp.com:80", parent=parent_event1, context="test context")
459
+ assert hasattr(event1, "_uuid")
460
+ assert hasattr(event1, "uuid")
461
+ assert isinstance(event1._uuid, uuid.UUID)
462
+ assert isinstance(event1.uuid, str)
463
+ assert event1.uuid == f"{event1.type}:{event1._uuid}"
464
+ event2 = scan.make_event("evilcorp.com:80", parent=parent_event2, context="test context")
465
+ assert hasattr(event2, "_uuid")
466
+ assert hasattr(event2, "uuid")
467
+ assert isinstance(event2._uuid, uuid.UUID)
468
+ assert isinstance(event2.uuid, str)
469
+ assert event2.uuid == f"{event2.type}:{event2._uuid}"
470
+ # ids should match because the event type + data is the same
471
+ assert event1.id == event2.id
472
+ # but uuids should be unique!
473
+ assert event1.uuid != event2.uuid
474
+ # parent ids should match
475
+ assert event1.parent_id == event2.parent_id == parent_event1.id == parent_event2.id
476
+ # uuids should not
477
+ assert event1.parent_uuid == parent_event1.uuid
478
+ assert event2.parent_uuid == parent_event2.uuid
479
+ assert event1.parent_uuid != event2.parent_uuid
480
+
415
481
  # test event serialization
416
482
  from bbot.core.event import event_from_json
417
483
 
418
484
  db_event = scan.make_event("evilcorp.com:80", parent=scan.root_event, context="test context")
485
+ assert db_event.parent == scan.root_event
486
+ assert db_event.parent is scan.root_event
419
487
  db_event._resolved_hosts = {"127.0.0.1"}
420
488
  db_event.scope_distance = 1
421
489
  assert db_event.discovery_context == "test context"
422
490
  assert db_event.discovery_path == ["test context"]
423
- assert db_event.parent_chain == ["OPEN_TCP_PORT:5098b5e3fc65b13bb4a5cee4201c2e160fa4ffac"]
491
+ assert len(db_event.parent_chain) == 1
492
+ assert all(event_uuid_regex.match(u) for u in db_event.parent_chain)
493
+ assert db_event.parent_chain[0] == str(db_event.uuid)
494
+ assert db_event.parent.uuid == scan.root_event.uuid
495
+ assert db_event.parent_uuid == scan.root_event.uuid
424
496
  timestamp = db_event.timestamp.isoformat()
425
497
  json_event = db_event.json()
498
+ assert isinstance(json_event["uuid"], str)
499
+ assert json_event["uuid"] == str(db_event.uuid)
500
+ assert json_event["parent_uuid"] == str(scan.root_event.uuid)
426
501
  assert json_event["scope_distance"] == 1
427
502
  assert json_event["data"] == "evilcorp.com:80"
428
503
  assert json_event["type"] == "OPEN_TCP_PORT"
@@ -430,8 +505,14 @@ async def test_events(events, helpers):
430
505
  assert json_event["timestamp"] == timestamp
431
506
  assert json_event["discovery_context"] == "test context"
432
507
  assert json_event["discovery_path"] == ["test context"]
433
- assert json_event["parent_chain"] == ["OPEN_TCP_PORT:5098b5e3fc65b13bb4a5cee4201c2e160fa4ffac"]
508
+ assert json_event["parent_chain"] == db_event.parent_chain
509
+ assert json_event["parent_chain"][0] == str(db_event.uuid)
434
510
  reconstituted_event = event_from_json(json_event)
511
+ assert isinstance(reconstituted_event._uuid, uuid.UUID)
512
+ assert str(reconstituted_event.uuid) == json_event["uuid"]
513
+ assert str(reconstituted_event.parent_uuid) == json_event["parent_uuid"]
514
+ assert reconstituted_event.uuid == db_event.uuid
515
+ assert reconstituted_event.parent_uuid == scan.root_event.uuid
435
516
  assert reconstituted_event.scope_distance == 1
436
517
  assert reconstituted_event.timestamp.isoformat() == timestamp
437
518
  assert reconstituted_event.data == "evilcorp.com:80"
@@ -439,13 +520,13 @@ async def test_events(events, helpers):
439
520
  assert reconstituted_event.host == "evilcorp.com"
440
521
  assert reconstituted_event.discovery_context == "test context"
441
522
  assert reconstituted_event.discovery_path == ["test context"]
442
- assert reconstituted_event.parent_chain == ["OPEN_TCP_PORT:5098b5e3fc65b13bb4a5cee4201c2e160fa4ffac"]
523
+ assert reconstituted_event.parent_chain == db_event.parent_chain
443
524
  assert "127.0.0.1" in reconstituted_event.resolved_hosts
444
525
  hostless_event = scan.make_event("asdf", "ASDF", dummy=True)
445
526
  hostless_event_json = hostless_event.json()
446
527
  assert hostless_event_json["type"] == "ASDF"
447
528
  assert hostless_event_json["data"] == "asdf"
448
- assert not "host" in hostless_event_json
529
+ assert "host" not in hostless_event_json
449
530
 
450
531
  # SIEM-friendly serialize/deserialize
451
532
  json_event_siemfriendly = db_event.json(siem_friendly=True)
@@ -535,7 +616,6 @@ async def test_events(events, helpers):
535
616
 
536
617
  @pytest.mark.asyncio
537
618
  async def test_event_discovery_context():
538
-
539
619
  from bbot.modules.base import BaseModule
540
620
 
541
621
  scan = Scanner("evilcorp.com")
@@ -616,7 +696,7 @@ async def test_event_discovery_context():
616
696
  )
617
697
 
618
698
  events = [e async for e in scan.async_start()]
619
- assert len(events) == 6
699
+ assert len(events) == 7
620
700
 
621
701
  assert 1 == len(
622
702
  [
@@ -723,7 +803,7 @@ async def test_event_web_spider_distance(bbot_scanner):
723
803
  )
724
804
  assert url_event_3.web_spider_distance == 1
725
805
  assert "spider-danger" in url_event_3.tags
726
- assert not "spider-max" in url_event_3.tags
806
+ assert "spider-max" not in url_event_3.tags
727
807
  social_event = scan.make_event(
728
808
  {"platform": "github", "url": "http://www.evilcorp.com/test4"}, "SOCIAL", parent=url_event_3
729
809
  )
@@ -746,42 +826,42 @@ async def test_event_web_spider_distance(bbot_scanner):
746
826
 
747
827
  url_event = scan.make_event("http://www.evilcorp.com", "URL_UNVERIFIED", parent=scan.root_event)
748
828
  assert url_event.web_spider_distance == 0
749
- assert not "spider-danger" in url_event.tags
750
- assert not "spider-max" in url_event.tags
829
+ assert "spider-danger" not in url_event.tags
830
+ assert "spider-max" not in url_event.tags
751
831
  url_event_2 = scan.make_event(
752
832
  "http://www.evilcorp.com", "URL_UNVERIFIED", parent=scan.root_event, tags="spider-danger"
753
833
  )
754
834
  # spider distance shouldn't increment because it's not the same host
755
835
  assert url_event_2.web_spider_distance == 0
756
836
  assert "spider-danger" in url_event_2.tags
757
- assert not "spider-max" in url_event_2.tags
837
+ assert "spider-max" not in url_event_2.tags
758
838
  url_event_3 = scan.make_event(
759
839
  "http://www.evilcorp.com/3", "URL_UNVERIFIED", parent=url_event_2, tags="spider-danger"
760
840
  )
761
841
  assert url_event_3.web_spider_distance == 1
762
842
  assert "spider-danger" in url_event_3.tags
763
- assert not "spider-max" in url_event_3.tags
843
+ assert "spider-max" not in url_event_3.tags
764
844
  url_event_4 = scan.make_event("http://evilcorp.com", "URL_UNVERIFIED", parent=url_event_3)
765
845
  assert url_event_4.web_spider_distance == 0
766
- assert not "spider-danger" in url_event_4.tags
767
- assert not "spider-max" in url_event_4.tags
846
+ assert "spider-danger" not in url_event_4.tags
847
+ assert "spider-max" not in url_event_4.tags
768
848
  url_event_4.add_tag("spider-danger")
769
849
  assert url_event_4.web_spider_distance == 0
770
850
  assert "spider-danger" in url_event_4.tags
771
- assert not "spider-max" in url_event_4.tags
851
+ assert "spider-max" not in url_event_4.tags
772
852
  url_event_4.remove_tag("spider-danger")
773
853
  assert url_event_4.web_spider_distance == 0
774
- assert not "spider-danger" in url_event_4.tags
775
- assert not "spider-max" in url_event_4.tags
854
+ assert "spider-danger" not in url_event_4.tags
855
+ assert "spider-max" not in url_event_4.tags
776
856
  url_event_5 = scan.make_event("http://evilcorp.com/5", "URL_UNVERIFIED", parent=url_event_4)
777
857
  assert url_event_5.web_spider_distance == 0
778
- assert not "spider-danger" in url_event_5.tags
779
- assert not "spider-max" in url_event_5.tags
858
+ assert "spider-danger" not in url_event_5.tags
859
+ assert "spider-max" not in url_event_5.tags
780
860
  url_event_5.add_tag("spider-danger")
781
861
  # if host is the same as parent, web spider distance should auto-increment after adding spider-danger tag
782
862
  assert url_event_5.web_spider_distance == 1
783
863
  assert "spider-danger" in url_event_5.tags
784
- assert not "spider-max" in url_event_5.tags
864
+ assert "spider-max" not in url_event_5.tags
785
865
 
786
866
 
787
867
  def test_event_confidence():
@@ -856,3 +936,76 @@ def test_event_closest_host():
856
936
  vuln = scan.make_event(
857
937
  {"path": "/tmp/asdf.txt", "description": "test", "severity": "HIGH"}, "VULNERABILITY", parent=event3
858
938
  )
939
+
940
+
941
+ def test_event_magic():
942
+ from bbot.core.helpers.libmagic import get_magic_info, get_compression
943
+
944
+ import base64
945
+
946
+ zip_base64 = "UEsDBAoDAAAAAOMmZ1lR4FaHBQAAAAUAAAAIAAAAYXNkZi50eHRhc2RmClBLAQI/AwoDAAAAAOMmZ1lR4FaHBQAAAAUAAAAIACQAAAAAAAAAIICkgQAAAABhc2RmLnR4dAoAIAAAAAAAAQAYAICi2B77MNsBgKLYHvsw2wGAotge+zDbAVBLBQYAAAAAAQABAFoAAAArAAAAAAA="
947
+ zip_bytes = base64.b64decode(zip_base64)
948
+ zip_file = Path("/tmp/.bbottestzipasdkfjalsdf.zip")
949
+ with open(zip_file, "wb") as f:
950
+ f.write(zip_bytes)
951
+
952
+ # test magic helpers
953
+ extension, mime_type, description, confidence = get_magic_info(zip_file)
954
+ assert extension == ".zip"
955
+ assert mime_type == "application/zip"
956
+ assert description == "PKZIP Archive file"
957
+ assert confidence > 0
958
+ assert get_compression(mime_type) == "zip"
959
+
960
+ # test filesystem event - file
961
+ scan = Scanner()
962
+ event = scan.make_event({"path": zip_file}, "FILESYSTEM", parent=scan.root_event)
963
+ assert event.data == {
964
+ "path": "/tmp/.bbottestzipasdkfjalsdf.zip",
965
+ "magic_extension": ".zip",
966
+ "magic_mime_type": "application/zip",
967
+ "magic_description": "PKZIP Archive file",
968
+ "magic_confidence": 0.9,
969
+ "compression": "zip",
970
+ }
971
+ assert event.tags == {"file", "zip-archive", "compressed"}
972
+
973
+ # test filesystem event - folder
974
+ scan = Scanner()
975
+ event = scan.make_event({"path": "/tmp"}, "FILESYSTEM", parent=scan.root_event)
976
+ assert event.data == {"path": "/tmp"}
977
+ assert event.tags == {"folder"}
978
+
979
+ zip_file.unlink()
980
+
981
+
982
+ def test_event_hashing():
983
+ scan = Scanner("example.com")
984
+ url_event = scan.make_event("https://api.example.com/", "URL_UNVERIFIED", parent=scan.root_event)
985
+ host_event_1 = scan.make_event("www.example.com", "DNS_NAME", parent=url_event)
986
+ host_event_2 = scan.make_event("test.example.com", "DNS_NAME", parent=url_event)
987
+ finding_data = {"description": "Custom Yara Rule [find_string] Matched via identifier [str1]"}
988
+ finding1 = scan.make_event(finding_data, "FINDING", parent=host_event_1)
989
+ finding2 = scan.make_event(finding_data, "FINDING", parent=host_event_2)
990
+ finding3 = scan.make_event(finding_data, "FINDING", parent=host_event_2)
991
+
992
+ assert finding1.data == {
993
+ "description": "Custom Yara Rule [find_string] Matched via identifier [str1]",
994
+ "host": "www.example.com",
995
+ }
996
+ assert finding2.data == {
997
+ "description": "Custom Yara Rule [find_string] Matched via identifier [str1]",
998
+ "host": "test.example.com",
999
+ }
1000
+ assert finding3.data == {
1001
+ "description": "Custom Yara Rule [find_string] Matched via identifier [str1]",
1002
+ "host": "test.example.com",
1003
+ }
1004
+ assert finding1.id != finding2.id
1005
+ assert finding2.id == finding3.id
1006
+ assert finding1.data_id != finding2.data_id
1007
+ assert finding2.data_id == finding3.data_id
1008
+ assert finding1.data_hash != finding2.data_hash
1009
+ assert finding2.data_hash == finding3.data_hash
1010
+ assert hash(finding1) != hash(finding2)
1011
+ assert hash(finding2) == hash(finding3)
@@ -49,6 +49,8 @@ async def test_helpers_misc(helpers, scan, bbot_scanner, bbot_httpserver):
49
49
  assert helpers.url_depth("http://evilcorp.com/") == 0
50
50
  assert helpers.url_depth("http://evilcorp.com") == 0
51
51
 
52
+ assert helpers.parent_url("http://evilcorp.com/subdir1/subdir2?foo=bar") == "http://evilcorp.com/subdir1"
53
+
52
54
  ### MISC ###
53
55
  assert helpers.is_domain("evilcorp.co.uk")
54
56
  assert not helpers.is_domain("www.evilcorp.co.uk")
@@ -62,8 +64,8 @@ async def test_helpers_misc(helpers, scan, bbot_scanner, bbot_httpserver):
62
64
  assert not helpers.is_subdomain("notreal")
63
65
  assert helpers.is_url("http://evilcorp.co.uk/asdf?a=b&c=d#asdf")
64
66
  assert helpers.is_url("https://evilcorp.co.uk/asdf?a=b&c=d#asdf")
65
- assert helpers.is_uri("ftp://evilcorp.co.uk") == True
66
- assert helpers.is_uri("http://evilcorp.co.uk") == True
67
+ assert helpers.is_uri("ftp://evilcorp.co.uk") is True
68
+ assert helpers.is_uri("http://evilcorp.co.uk") is True
67
69
  assert helpers.is_uri("evilcorp.co.uk", return_scheme=True) == ""
68
70
  assert helpers.is_uri("ftp://evilcorp.co.uk", return_scheme=True) == "ftp"
69
71
  assert helpers.is_uri("FTP://evilcorp.co.uk", return_scheme=True) == "ftp"
@@ -91,8 +93,34 @@ async def test_helpers_misc(helpers, scan, bbot_scanner, bbot_httpserver):
91
93
  ipaddress.ip_network("0.0.0.0/0"),
92
94
  ]
93
95
  assert helpers.is_ip("127.0.0.1")
96
+ assert helpers.is_ip("127.0.0.1", include_network=True)
97
+ assert helpers.is_ip("127.0.0.1", version=4)
98
+ assert not helpers.is_ip("127.0.0.1", version=6)
94
99
  assert not helpers.is_ip("127.0.0.0.1")
100
+
101
+ assert helpers.is_ip("dead::beef")
102
+ assert helpers.is_ip("dead::beef", include_network=True)
103
+ assert not helpers.is_ip("dead::beef", version=4)
104
+ assert helpers.is_ip("dead::beef", version=6)
105
+ assert not helpers.is_ip("dead:::beef")
106
+
107
+ assert not helpers.is_ip("1.2.3.4/24")
108
+ assert helpers.is_ip("1.2.3.4/24", include_network=True)
109
+ assert not helpers.is_ip("1.2.3.4/24", version=4)
110
+ assert helpers.is_ip("1.2.3.4/24", include_network=True, version=4)
111
+ assert not helpers.is_ip("1.2.3.4/24", include_network=True, version=6)
112
+
113
+ assert not helpers.is_ip_type("127.0.0.1")
114
+ assert helpers.is_ip_type(ipaddress.ip_address("127.0.0.1"))
115
+ assert not helpers.is_ip_type(ipaddress.ip_address("127.0.0.1"), network=True)
116
+ assert helpers.is_ip_type(ipaddress.ip_address("127.0.0.1"), network=False)
117
+ assert helpers.is_ip_type(ipaddress.ip_network("127.0.0.0/8"))
118
+ assert helpers.is_ip_type(ipaddress.ip_network("127.0.0.0/8"), network=True)
119
+ assert not helpers.is_ip_type(ipaddress.ip_network("127.0.0.0/8"), network=False)
120
+
95
121
  assert helpers.is_dns_name("evilcorp.com")
122
+ assert not helpers.is_dns_name("evilcorp.com:80")
123
+ assert not helpers.is_dns_name("http://evilcorp.com:80")
96
124
  assert helpers.is_dns_name("evilcorp")
97
125
  assert not helpers.is_dns_name("evilcorp", include_local=False)
98
126
  assert helpers.is_dns_name("ドメイン.テスト")
@@ -210,8 +238,12 @@ async def test_helpers_misc(helpers, scan, bbot_scanner, bbot_httpserver):
210
238
 
211
239
  ipv4_netloc = helpers.make_netloc("192.168.1.1", 80)
212
240
  assert ipv4_netloc == "192.168.1.1:80"
213
- ipv6_netloc = helpers.make_netloc("dead::beef", "443")
214
- assert ipv6_netloc == "[dead::beef]:443"
241
+ assert helpers.make_netloc("192.168.1.1") == "192.168.1.1"
242
+ assert helpers.make_netloc(ipaddress.ip_address("192.168.1.1"), None) == "192.168.1.1"
243
+ assert helpers.make_netloc("dead::beef", "443") == "[dead::beef]:443"
244
+ assert helpers.make_netloc(ipaddress.ip_address("dead::beef"), 443) == "[dead::beef]:443"
245
+ assert helpers.make_netloc("dead::beef", None) == "[dead::beef]"
246
+ assert helpers.make_netloc(ipaddress.ip_address("dead::beef"), None) == "[dead::beef]"
215
247
 
216
248
  assert helpers.get_file_extension("https://evilcorp.com/evilcorp.com/test/asdf.TXT") == "txt"
217
249
  assert helpers.get_file_extension("/etc/conf/test.tar.gz") == "gz"
@@ -251,7 +283,7 @@ async def test_helpers_misc(helpers, scan, bbot_scanner, bbot_httpserver):
251
283
  replaced = helpers.search_format_dict(
252
284
  {"asdf": [{"wat": {"here": "#{replaceme}!"}}, {500: True}]}, replaceme="asdf"
253
285
  )
254
- assert replaced["asdf"][1][500] == True
286
+ assert replaced["asdf"][1][500] is True
255
287
  assert replaced["asdf"][0]["wat"]["here"] == "asdf!"
256
288
 
257
289
  filtered_dict = helpers.filter_dict(
@@ -283,7 +315,7 @@ async def test_helpers_misc(helpers, scan, bbot_scanner, bbot_httpserver):
283
315
  fuzzy=True,
284
316
  exclude_keys="modules",
285
317
  )
286
- assert not "secrets_db" in filtered_dict4["modules"]
318
+ assert "secrets_db" not in filtered_dict4["modules"]
287
319
  assert "ipneighbor" in filtered_dict4["modules"]
288
320
  assert "secret" in filtered_dict4["modules"]["ipneighbor"]
289
321
  assert "asdf" not in filtered_dict4["modules"]["ipneighbor"]
@@ -376,15 +408,15 @@ async def test_helpers_misc(helpers, scan, bbot_scanner, bbot_httpserver):
376
408
  assert helpers.validators.validate_host("LOCALHOST ") == "localhost"
377
409
  assert helpers.validators.validate_host(" 192.168.1.1") == "192.168.1.1"
378
410
  assert helpers.validators.validate_host(" Dead::c0dE ") == "dead::c0de"
379
- assert helpers.validators.soft_validate(" evilCorp.COM", "host") == True
380
- assert helpers.validators.soft_validate("!@#$", "host") == False
411
+ assert helpers.validators.soft_validate(" evilCorp.COM", "host") is True
412
+ assert helpers.validators.soft_validate("!@#$", "host") is False
381
413
  with pytest.raises(ValueError):
382
414
  assert helpers.validators.validate_host("!@#$")
383
415
  # ports
384
416
  assert helpers.validators.validate_port(666) == 666
385
417
  assert helpers.validators.validate_port(666666) == 65535
386
- assert helpers.validators.soft_validate(666, "port") == True
387
- assert helpers.validators.soft_validate("!@#$", "port") == False
418
+ assert helpers.validators.soft_validate(666, "port") is True
419
+ assert helpers.validators.soft_validate("!@#$", "port") is False
388
420
  with pytest.raises(ValueError):
389
421
  helpers.validators.validate_port("asdf")
390
422
  # top tcp ports
@@ -396,7 +428,7 @@ async def test_helpers_misc(helpers, scan, bbot_scanner, bbot_httpserver):
396
428
  assert top_tcp_ports[-10:] == [65526, 65527, 65528, 65529, 65530, 65531, 65532, 65533, 65534, 65535]
397
429
  assert len(top_tcp_ports) == 65535
398
430
  assert len(set(top_tcp_ports)) == 65535
399
- assert all([isinstance(i, int) for i in top_tcp_ports])
431
+ assert all(isinstance(i, int) for i in top_tcp_ports)
400
432
  top_tcp_ports = helpers.top_tcp_ports(10, as_string=True)
401
433
  assert top_tcp_ports == "80,23,443,21,22,25,3389,110,445,139"
402
434
  # urls
@@ -405,25 +437,29 @@ async def test_helpers_misc(helpers, scan, bbot_scanner, bbot_httpserver):
405
437
  helpers.validators.validate_url_parsed(" httP://evilcorP.com/asdf?a=b&c=d#e").geturl()
406
438
  == "http://evilcorp.com/asdf"
407
439
  )
408
- assert helpers.validators.soft_validate(" httP://evilcorP.com/asdf?a=b&c=d#e", "url") == True
409
- assert helpers.validators.soft_validate("!@#$", "url") == False
440
+ assert helpers.validators.soft_validate(" httP://evilcorP.com/asdf?a=b&c=d#e", "url") is True
441
+ assert helpers.validators.soft_validate("!@#$", "url") is False
410
442
  with pytest.raises(ValueError):
411
443
  helpers.validators.validate_url("!@#$")
412
444
  # severities
413
445
  assert helpers.validators.validate_severity(" iNfo") == "INFO"
414
- assert helpers.validators.soft_validate(" iNfo", "severity") == True
415
- assert helpers.validators.soft_validate("NOPE", "severity") == False
446
+ assert helpers.validators.soft_validate(" iNfo", "severity") is True
447
+ assert helpers.validators.soft_validate("NOPE", "severity") is False
416
448
  with pytest.raises(ValueError):
417
449
  helpers.validators.validate_severity("NOPE")
418
450
  # emails
419
451
  assert helpers.validators.validate_email(" bOb@eViLcorp.COM") == "bob@evilcorp.com"
420
- assert helpers.validators.soft_validate(" bOb@eViLcorp.COM", "email") == True
421
- assert helpers.validators.soft_validate("!@#$", "email") == False
452
+ assert helpers.validators.soft_validate(" bOb@eViLcorp.COM", "email") is True
453
+ assert helpers.validators.soft_validate("!@#$", "email") is False
422
454
  with pytest.raises(ValueError):
423
455
  helpers.validators.validate_email("!@#$")
424
456
 
425
457
  assert type(helpers.make_date()) == str
426
458
 
459
+ # string formatter
460
+ s = "asdf {unused} {used}"
461
+ assert helpers.safe_format(s, used="fdsa") == "asdf {unused} fdsa"
462
+
427
463
  # punycode
428
464
  assert helpers.smart_encode_punycode("ドメイン.テスト") == "xn--eckwd4c7c.xn--zckzah"
429
465
  assert helpers.smart_decode_punycode("xn--eckwd4c7c.xn--zckzah") == "ドメイン.テスト"
@@ -497,9 +533,9 @@ async def test_helpers_misc(helpers, scan, bbot_scanner, bbot_httpserver):
497
533
  truncated_filename.unlink()
498
534
 
499
535
  # misc DNS helpers
500
- assert helpers.is_ptr("wsc-11-22-33-44-wat.evilcorp.com") == True
501
- assert helpers.is_ptr("wsc-11-22-33-wat.evilcorp.com") == False
502
- assert helpers.is_ptr("11wat.evilcorp.com") == False
536
+ assert helpers.is_ptr("wsc-11-22-33-44-wat.evilcorp.com") is True
537
+ assert helpers.is_ptr("wsc-11-22-33-wat.evilcorp.com") is False
538
+ assert helpers.is_ptr("11wat.evilcorp.com") is False
503
539
 
504
540
  ## NTLM
505
541
  testheader = "TlRMTVNTUAACAAAAHgAeADgAAAAVgorilwL+bvnVipUAAAAAAAAAAJgAmABWAAAACgBjRQAAAA9XAEkATgAtAFMANAAyAE4ATwBCAEQAVgBUAEsAOAACAB4AVwBJAE4ALQBTADQAMgBOAE8AQgBEAFYAVABLADgAAQAeAFcASQBOAC0AUwA0ADIATgBPAEIARABWAFQASwA4AAQAHgBXAEkATgAtAFMANAAyAE4ATwBCAEQAVgBUAEsAOAADAB4AVwBJAE4ALQBTADQAMgBOAE8AQgBEAFYAVABLADgABwAIAHUwOZlfoNgBAAAAAA=="
@@ -577,8 +613,8 @@ async def test_helpers_misc(helpers, scan, bbot_scanner, bbot_httpserver):
577
613
  assert len(helpers.get_exception_chain(e)) == 2
578
614
  assert len([_ for _ in helpers.get_exception_chain(e) if isinstance(_, KeyboardInterrupt)]) == 1
579
615
  assert len([_ for _ in helpers.get_exception_chain(e) if isinstance(_, ValueError)]) == 1
580
- assert helpers.in_exception_chain(e, (KeyboardInterrupt, asyncio.CancelledError)) == True
581
- assert helpers.in_exception_chain(e, (TypeError, OSError)) == False
616
+ assert helpers.in_exception_chain(e, (KeyboardInterrupt, asyncio.CancelledError)) is True
617
+ assert helpers.in_exception_chain(e, (TypeError, OSError)) is False
582
618
  test_ran = True
583
619
  assert test_ran
584
620
  test_ran = False
@@ -591,9 +627,9 @@ async def test_helpers_misc(helpers, scan, bbot_scanner, bbot_httpserver):
591
627
  assert len(helpers.get_exception_chain(e)) == 2
592
628
  assert len([_ for _ in helpers.get_exception_chain(e) if isinstance(_, AttributeError)]) == 1
593
629
  assert len([_ for _ in helpers.get_exception_chain(e) if isinstance(_, ValueError)]) == 1
594
- assert helpers.in_exception_chain(e, (KeyboardInterrupt, asyncio.CancelledError)) == False
595
- assert helpers.in_exception_chain(e, (KeyboardInterrupt, AttributeError)) == True
596
- assert helpers.in_exception_chain(e, (AttributeError,)) == True
630
+ assert helpers.in_exception_chain(e, (KeyboardInterrupt, asyncio.CancelledError)) is False
631
+ assert helpers.in_exception_chain(e, (KeyboardInterrupt, AttributeError)) is True
632
+ assert helpers.in_exception_chain(e, (AttributeError,)) is True
597
633
  test_ran = True
598
634
  assert test_ran
599
635
 
@@ -821,7 +857,6 @@ def test_liststring_invalidfnchars(helpers):
821
857
  # test parameter validation
822
858
  @pytest.mark.asyncio
823
859
  async def test_parameter_validation(helpers):
824
-
825
860
  getparam_valid_params = {
826
861
  "name",
827
862
  "age",
@@ -850,7 +885,7 @@ async def test_parameter_validation(helpers):
850
885
  if helpers.validate_parameter(p, "getparam"):
851
886
  assert p in getparam_valid_params and p not in getparam_invalid_params
852
887
  else:
853
- assert p in getparam_invalid_params and not p in getparam_valid_params
888
+ assert p in getparam_invalid_params and p not in getparam_valid_params
854
889
 
855
890
  header_valid_params = {
856
891
  "name",
@@ -881,7 +916,7 @@ async def test_parameter_validation(helpers):
881
916
  if helpers.validate_parameter(p, "header"):
882
917
  assert p in header_valid_params and p not in header_invalid_params
883
918
  else:
884
- assert p in header_invalid_params and not p in header_valid_params
919
+ assert p in header_invalid_params and p not in header_valid_params
885
920
 
886
921
  cookie_valid_params = {
887
922
  "name",
@@ -911,4 +946,4 @@ async def test_parameter_validation(helpers):
911
946
  if helpers.validate_parameter(p, "cookie"):
912
947
  assert p in cookie_valid_params and p not in cookie_invalid_params
913
948
  else:
914
- assert p in cookie_invalid_params and not p in cookie_valid_params
949
+ assert p in cookie_invalid_params and p not in cookie_valid_params
@@ -91,7 +91,7 @@ async def test_manager_deduplication(bbot_scanner):
91
91
  _dns_mock=dns_mock_chain,
92
92
  )
93
93
 
94
- assert len(events) == 21
94
+ assert len(events) == 22
95
95
  assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "accept_dupes.test.notreal" and str(e.module) == "accept_dupes"])
96
96
  assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "default_module.test.notreal" and str(e.module) == "default_module"])
97
97
  assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "no_suppress_dupes.test.notreal" and str(e.module) == "no_suppress_dupes" and e.parent.data == "accept_dupes.test.notreal"])