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.
- bbot/__init__.py +1 -1
- bbot/cli.py +3 -7
- bbot/core/config/files.py +0 -1
- bbot/core/config/logger.py +34 -4
- bbot/core/core.py +21 -6
- bbot/core/engine.py +9 -8
- bbot/core/event/base.py +162 -63
- bbot/core/helpers/bloom.py +10 -3
- bbot/core/helpers/command.py +9 -8
- bbot/core/helpers/depsinstaller/installer.py +89 -32
- bbot/core/helpers/depsinstaller/sudo_askpass.py +38 -2
- bbot/core/helpers/diff.py +10 -10
- bbot/core/helpers/dns/brute.py +18 -14
- bbot/core/helpers/dns/dns.py +16 -15
- bbot/core/helpers/dns/engine.py +159 -132
- bbot/core/helpers/dns/helpers.py +2 -2
- bbot/core/helpers/dns/mock.py +26 -8
- bbot/core/helpers/files.py +1 -1
- bbot/core/helpers/helper.py +7 -4
- bbot/core/helpers/interactsh.py +3 -3
- bbot/core/helpers/libmagic.py +65 -0
- bbot/core/helpers/misc.py +65 -22
- bbot/core/helpers/names_generator.py +17 -3
- bbot/core/helpers/process.py +0 -20
- bbot/core/helpers/regex.py +1 -1
- bbot/core/helpers/regexes.py +12 -6
- bbot/core/helpers/validators.py +1 -2
- bbot/core/helpers/web/client.py +1 -1
- bbot/core/helpers/web/engine.py +18 -13
- bbot/core/helpers/web/web.py +25 -116
- bbot/core/helpers/wordcloud.py +5 -5
- bbot/core/modules.py +36 -27
- bbot/core/multiprocess.py +58 -0
- bbot/core/shared_deps.py +46 -3
- bbot/db/sql/models.py +147 -0
- bbot/defaults.yml +15 -10
- bbot/errors.py +0 -8
- bbot/modules/anubisdb.py +2 -2
- bbot/modules/apkpure.py +63 -0
- bbot/modules/azure_tenant.py +2 -2
- bbot/modules/baddns.py +35 -19
- bbot/modules/baddns_direct.py +92 -0
- bbot/modules/baddns_zone.py +3 -8
- bbot/modules/badsecrets.py +4 -3
- bbot/modules/base.py +195 -51
- bbot/modules/bevigil.py +7 -7
- bbot/modules/binaryedge.py +7 -4
- bbot/modules/bufferoverrun.py +47 -0
- bbot/modules/builtwith.py +6 -10
- bbot/modules/bypass403.py +5 -5
- bbot/modules/c99.py +10 -7
- bbot/modules/censys.py +9 -13
- bbot/modules/certspotter.py +5 -3
- bbot/modules/chaos.py +9 -7
- bbot/modules/code_repository.py +1 -0
- bbot/modules/columbus.py +3 -3
- bbot/modules/crt.py +5 -3
- bbot/modules/deadly/dastardly.py +1 -1
- bbot/modules/deadly/ffuf.py +9 -9
- bbot/modules/deadly/nuclei.py +3 -3
- bbot/modules/deadly/vhost.py +4 -3
- bbot/modules/dehashed.py +1 -1
- bbot/modules/digitorus.py +1 -1
- bbot/modules/dnsbimi.py +145 -0
- bbot/modules/dnscaa.py +3 -3
- bbot/modules/dnsdumpster.py +4 -4
- bbot/modules/dnstlsrpt.py +144 -0
- bbot/modules/docker_pull.py +7 -5
- bbot/modules/dockerhub.py +2 -2
- bbot/modules/dotnetnuke.py +18 -19
- bbot/modules/emailformat.py +1 -1
- bbot/modules/extractous.py +122 -0
- bbot/modules/filedownload.py +9 -7
- bbot/modules/fullhunt.py +7 -4
- bbot/modules/generic_ssrf.py +5 -5
- bbot/modules/github_codesearch.py +3 -2
- bbot/modules/github_org.py +4 -4
- bbot/modules/github_workflows.py +4 -4
- bbot/modules/gitlab.py +2 -5
- bbot/modules/google_playstore.py +93 -0
- bbot/modules/gowitness.py +48 -50
- bbot/modules/hackertarget.py +5 -3
- bbot/modules/host_header.py +5 -5
- bbot/modules/httpx.py +1 -4
- bbot/modules/hunterio.py +3 -9
- bbot/modules/iis_shortnames.py +19 -30
- bbot/modules/internal/cloudcheck.py +27 -12
- bbot/modules/internal/dnsresolve.py +250 -276
- bbot/modules/internal/excavate.py +100 -64
- bbot/modules/internal/speculate.py +42 -33
- bbot/modules/internetdb.py +4 -2
- bbot/modules/ip2location.py +3 -5
- bbot/modules/ipneighbor.py +1 -1
- bbot/modules/ipstack.py +3 -8
- bbot/modules/jadx.py +87 -0
- bbot/modules/leakix.py +11 -10
- bbot/modules/myssl.py +2 -2
- bbot/modules/newsletters.py +2 -2
- bbot/modules/otx.py +5 -3
- bbot/modules/output/asset_inventory.py +7 -7
- bbot/modules/output/base.py +1 -1
- bbot/modules/output/csv.py +1 -2
- bbot/modules/output/http.py +20 -14
- bbot/modules/output/mysql.py +51 -0
- bbot/modules/output/neo4j.py +7 -2
- bbot/modules/output/postgres.py +49 -0
- bbot/modules/output/slack.py +0 -1
- bbot/modules/output/sqlite.py +29 -0
- bbot/modules/output/stdout.py +2 -2
- bbot/modules/output/teams.py +107 -6
- bbot/modules/paramminer_headers.py +5 -8
- bbot/modules/passivetotal.py +13 -13
- bbot/modules/portscan.py +32 -6
- bbot/modules/postman.py +50 -126
- bbot/modules/postman_download.py +220 -0
- bbot/modules/rapiddns.py +3 -8
- bbot/modules/report/asn.py +11 -11
- bbot/modules/robots.py +3 -3
- bbot/modules/securitytrails.py +7 -10
- bbot/modules/securitytxt.py +128 -0
- bbot/modules/shodan_dns.py +7 -9
- bbot/modules/sitedossier.py +1 -1
- bbot/modules/skymem.py +2 -2
- bbot/modules/social.py +2 -1
- bbot/modules/subdomaincenter.py +1 -1
- bbot/modules/subdomainradar.py +160 -0
- bbot/modules/telerik.py +8 -8
- bbot/modules/templates/bucket.py +1 -1
- bbot/modules/templates/github.py +22 -14
- bbot/modules/templates/postman.py +21 -0
- bbot/modules/templates/shodan.py +14 -13
- bbot/modules/templates/sql.py +95 -0
- bbot/modules/templates/subdomain_enum.py +53 -17
- bbot/modules/templates/webhook.py +2 -4
- bbot/modules/trickest.py +8 -37
- bbot/modules/trufflehog.py +18 -3
- bbot/modules/url_manipulation.py +3 -3
- bbot/modules/urlscan.py +1 -1
- bbot/modules/viewdns.py +1 -1
- bbot/modules/virustotal.py +8 -30
- bbot/modules/wafw00f.py +1 -1
- bbot/modules/wayback.py +1 -1
- bbot/modules/wpscan.py +17 -11
- bbot/modules/zoomeye.py +11 -6
- bbot/presets/baddns-thorough.yml +12 -0
- bbot/presets/fast.yml +16 -0
- bbot/presets/kitchen-sink.yml +1 -0
- bbot/presets/spider.yml +4 -0
- bbot/presets/subdomain-enum.yml +7 -7
- bbot/scanner/manager.py +5 -16
- bbot/scanner/preset/args.py +44 -26
- bbot/scanner/preset/environ.py +7 -2
- bbot/scanner/preset/path.py +7 -4
- bbot/scanner/preset/preset.py +36 -23
- bbot/scanner/scanner.py +176 -63
- bbot/scanner/target.py +236 -434
- bbot/scripts/docs.py +1 -1
- bbot/test/bbot_fixtures.py +22 -3
- bbot/test/conftest.py +132 -100
- bbot/test/fastapi_test.py +17 -0
- bbot/test/owasp_mastg.apk +0 -0
- bbot/test/run_tests.sh +4 -4
- bbot/test/test.conf +2 -0
- bbot/test/test_step_1/test_bbot_fastapi.py +82 -0
- bbot/test/test_step_1/test_bloom_filter.py +2 -0
- bbot/test/test_step_1/test_cli.py +138 -64
- bbot/test/test_step_1/test_dns.py +392 -70
- bbot/test/test_step_1/test_engine.py +17 -17
- bbot/test/test_step_1/test_events.py +203 -37
- bbot/test/test_step_1/test_helpers.py +64 -28
- bbot/test/test_step_1/test_manager_deduplication.py +1 -1
- bbot/test/test_step_1/test_manager_scope_accuracy.py +336 -338
- bbot/test/test_step_1/test_modules_basic.py +69 -71
- bbot/test/test_step_1/test_presets.py +184 -96
- bbot/test/test_step_1/test_python_api.py +7 -2
- bbot/test/test_step_1/test_regexes.py +35 -5
- bbot/test/test_step_1/test_scan.py +39 -5
- bbot/test/test_step_1/test_scope.py +5 -4
- bbot/test/test_step_1/test_target.py +243 -145
- bbot/test/test_step_1/test_web.py +48 -10
- bbot/test/test_step_2/module_tests/base.py +17 -20
- bbot/test/test_step_2/module_tests/test_module_anubisdb.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_apkpure.py +71 -0
- bbot/test/test_step_2/module_tests/test_module_asset_inventory.py +0 -1
- bbot/test/test_step_2/module_tests/test_module_azure_realm.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_baddns.py +6 -6
- bbot/test/test_step_2/module_tests/test_module_baddns_direct.py +62 -0
- bbot/test/test_step_2/module_tests/test_module_bevigil.py +29 -2
- bbot/test/test_step_2/module_tests/test_module_binaryedge.py +4 -2
- bbot/test/test_step_2/module_tests/test_module_bucket_amazon.py +2 -2
- bbot/test/test_step_2/module_tests/test_module_bucket_azure.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_bufferoverrun.py +35 -0
- bbot/test/test_step_2/module_tests/test_module_builtwith.py +2 -2
- bbot/test/test_step_2/module_tests/test_module_bypass403.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_c99.py +126 -0
- bbot/test/test_step_2/module_tests/test_module_censys.py +4 -1
- bbot/test/test_step_2/module_tests/test_module_cloudcheck.py +4 -0
- bbot/test/test_step_2/module_tests/test_module_code_repository.py +11 -1
- bbot/test/test_step_2/module_tests/test_module_columbus.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_credshed.py +3 -3
- bbot/test/test_step_2/module_tests/test_module_dastardly.py +2 -1
- bbot/test/test_step_2/module_tests/test_module_dehashed.py +2 -2
- bbot/test/test_step_2/module_tests/test_module_digitorus.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_discord.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_dnsbimi.py +103 -0
- bbot/test/test_step_2/module_tests/test_module_dnsbrute.py +9 -10
- bbot/test/test_step_2/module_tests/test_module_dnsbrute_mutations.py +1 -2
- bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py +1 -2
- bbot/test/test_step_2/module_tests/test_module_dnsdumpster.py +4 -4
- bbot/test/test_step_2/module_tests/test_module_dnstlsrpt.py +64 -0
- bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py +0 -8
- bbot/test/test_step_2/module_tests/test_module_excavate.py +17 -37
- bbot/test/test_step_2/module_tests/test_module_extractous.py +54 -0
- bbot/test/test_step_2/module_tests/test_module_ffuf_shortnames.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_filedownload.py +14 -14
- bbot/test/test_step_2/module_tests/test_module_git_clone.py +2 -2
- bbot/test/test_step_2/module_tests/test_module_github_org.py +19 -8
- bbot/test/test_step_2/module_tests/test_module_github_workflows.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_gitlab.py +9 -4
- bbot/test/test_step_2/module_tests/test_module_google_playstore.py +83 -0
- bbot/test/test_step_2/module_tests/test_module_gowitness.py +4 -4
- bbot/test/test_step_2/module_tests/test_module_host_header.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_http.py +4 -4
- bbot/test/test_step_2/module_tests/test_module_httpx.py +10 -8
- bbot/test/test_step_2/module_tests/test_module_hunterio.py +68 -4
- bbot/test/test_step_2/module_tests/test_module_jadx.py +55 -0
- bbot/test/test_step_2/module_tests/test_module_json.py +24 -11
- bbot/test/test_step_2/module_tests/test_module_leakix.py +7 -3
- bbot/test/test_step_2/module_tests/test_module_mysql.py +76 -0
- bbot/test/test_step_2/module_tests/test_module_myssl.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_neo4j.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_newsletters.py +6 -6
- bbot/test/test_step_2/module_tests/test_module_ntlm.py +7 -7
- bbot/test/test_step_2/module_tests/test_module_oauth.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_otx.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_paramminer_cookies.py +1 -2
- bbot/test/test_step_2/module_tests/test_module_paramminer_getparams.py +0 -6
- bbot/test/test_step_2/module_tests/test_module_paramminer_headers.py +2 -9
- bbot/test/test_step_2/module_tests/test_module_passivetotal.py +3 -1
- bbot/test/test_step_2/module_tests/test_module_portscan.py +9 -8
- bbot/test/test_step_2/module_tests/test_module_postgres.py +74 -0
- bbot/test/test_step_2/module_tests/test_module_postman.py +84 -253
- bbot/test/test_step_2/module_tests/test_module_postman_download.py +439 -0
- bbot/test/test_step_2/module_tests/test_module_rapiddns.py +93 -1
- bbot/test/test_step_2/module_tests/test_module_securitytxt.py +50 -0
- bbot/test/test_step_2/module_tests/test_module_shodan_dns.py +20 -1
- bbot/test/test_step_2/module_tests/test_module_sitedossier.py +2 -2
- bbot/test/test_step_2/module_tests/test_module_smuggler.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_social.py +11 -1
- bbot/test/test_step_2/module_tests/test_module_speculate.py +2 -6
- bbot/test/test_step_2/module_tests/test_module_splunk.py +4 -4
- bbot/test/test_step_2/module_tests/test_module_sqlite.py +18 -0
- bbot/test/test_step_2/module_tests/test_module_sslcert.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_stdout.py +5 -3
- bbot/test/test_step_2/module_tests/test_module_subdomaincenter.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_subdomainradar.py +208 -0
- bbot/test/test_step_2/module_tests/test_module_subdomains.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_teams.py +8 -6
- bbot/test/test_step_2/module_tests/test_module_telerik.py +1 -1
- bbot/test/test_step_2/module_tests/test_module_trufflehog.py +317 -11
- bbot/test/test_step_2/module_tests/test_module_wayback.py +1 -1
- bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py +135 -0
- {bbot-2.0.1.4654rc0.dist-info → bbot-2.3.0.5397rc0.dist-info}/METADATA +48 -18
- bbot-2.3.0.5397rc0.dist-info/RECORD +421 -0
- {bbot-2.0.1.4654rc0.dist-info → bbot-2.3.0.5397rc0.dist-info}/WHEEL +1 -1
- bbot/modules/unstructured.py +0 -163
- bbot/test/test_step_2/module_tests/test_module_unstructured.py +0 -102
- bbot-2.0.1.4654rc0.dist-info/RECORD +0 -385
- {bbot-2.0.1.4654rc0.dist-info → bbot-2.3.0.5397rc0.dist-info}/LICENSE +0 -0
- {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
|
-
|
|
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
|
|
66
|
-
assert
|
|
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
|
-
|
|
70
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
235
|
-
assert updated_event.internal
|
|
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 == [
|
|
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"] == [
|
|
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
|
-
|
|
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
|
|
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) ==
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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]
|
|
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
|
|
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
|
|
739
|
-
assert
|
|
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
|
|
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
|
|
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
|
|
756
|
-
assert
|
|
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
|
|
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
|
|
764
|
-
assert
|
|
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
|
|
768
|
-
assert
|
|
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
|
|
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)
|