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.
- 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 -4
- bbot/core/engine.py +9 -8
- bbot/core/event/base.py +131 -52
- bbot/core/helpers/bloom.py +10 -3
- bbot/core/helpers/command.py +8 -7
- bbot/core/helpers/depsinstaller/installer.py +31 -13
- bbot/core/helpers/diff.py +10 -10
- bbot/core/helpers/dns/brute.py +7 -4
- bbot/core/helpers/dns/dns.py +1 -2
- bbot/core/helpers/dns/engine.py +4 -6
- bbot/core/helpers/dns/helpers.py +2 -2
- bbot/core/helpers/dns/mock.py +0 -1
- 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 +1 -2
- bbot/core/helpers/web/web.py +4 -114
- 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 +12 -10
- 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 +20 -21
- 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 +29 -12
- bbot/modules/internal/dnsresolve.py +22 -22
- bbot/modules/internal/excavate.py +97 -59
- bbot/modules/internal/speculate.py +41 -32
- 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 -1
- 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 +8 -11
- 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 +18 -11
- bbot/modules/robots.py +3 -3
- bbot/modules/securitytrails.py +7 -10
- bbot/modules/securitytxt.py +1 -1
- 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 +51 -16
- bbot/modules/templates/webhook.py +2 -4
- bbot/modules/trickest.py +8 -37
- bbot/modules/trufflehog.py +10 -12
- 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 -2
- bbot/presets/spider.yml +4 -0
- bbot/presets/subdomain-enum.yml +7 -7
- bbot/presets/web/dotnet-audit.yml +0 -1
- bbot/scanner/manager.py +5 -16
- bbot/scanner/preset/args.py +46 -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 +172 -62
- bbot/scanner/target.py +236 -434
- bbot/scripts/docs.py +1 -1
- bbot/test/bbot_fixtures.py +13 -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__module__tests.py +0 -1
- bbot/test/test_step_1/test_bbot_fastapi.py +79 -0
- bbot/test/test_step_1/test_bloom_filter.py +2 -1
- bbot/test/test_step_1/test_cli.py +138 -64
- bbot/test/test_step_1/test_dns.py +61 -27
- bbot/test/test_step_1/test_engine.py +17 -19
- bbot/test/test_step_1/test_events.py +183 -30
- bbot/test/test_step_1/test_helpers.py +64 -29
- bbot/test/test_step_1/test_manager_deduplication.py +1 -1
- bbot/test/test_step_1/test_manager_scope_accuracy.py +333 -330
- bbot/test/test_step_1/test_modules_basic.py +68 -70
- bbot/test/test_step_1/test_presets.py +183 -100
- 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 +4 -3
- bbot/test/test_step_1/test_target.py +242 -145
- bbot/test/test_step_1/test_web.py +14 -10
- bbot/test/test_step_2/module_tests/base.py +15 -7
- 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 +28 -48
- 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 -6
- 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 +22 -9
- 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 +16 -16
- bbot/test/test_step_2/module_tests/test_module_ntlm.py +8 -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_pgp.py +2 -2
- 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_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 +14 -14
- bbot/test/test_step_2/module_tests/test_module_social.py +11 -1
- bbot/test/test_step_2/module_tests/test_module_speculate.py +4 -8
- 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 -14
- bbot/test/test_step_2/module_tests/test_module_viewdns.py +1 -1
- 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 +2 -2
- bbot/wordlists/devops_mutations.txt +1 -1
- bbot/wordlists/ffuf_shortname_candidates.txt +1 -1
- bbot/wordlists/nameservers.txt +1 -1
- bbot/wordlists/paramminer_headers.txt +1 -1
- bbot/wordlists/paramminer_parameters.txt +1 -1
- bbot/wordlists/raft-small-extensions-lowercase_CLEANED.txt +1 -1
- bbot/wordlists/valid_url_schemes.txt +1 -1
- {bbot-2.0.1.4720rc0.dist-info → bbot-2.3.0.5401rc0.dist-info}/METADATA +48 -18
- bbot-2.3.0.5401rc0.dist-info/RECORD +421 -0
- {bbot-2.0.1.4720rc0.dist-info → bbot-2.3.0.5401rc0.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.4720rc0.dist-info/RECORD +0 -387
- {bbot-2.0.1.4720rc0.dist-info → bbot-2.3.0.5401rc0.dist-info}/LICENSE +0 -0
- {bbot-2.0.1.4720rc0.dist-info → bbot-2.3.0.5401rc0.dist-info}/entry_points.txt +0 -0
bbot/core/shared_deps.py
CHANGED
|
@@ -79,13 +79,23 @@ DEP_CHROMIUM = [
|
|
|
79
79
|
"ignore_errors": True,
|
|
80
80
|
},
|
|
81
81
|
{
|
|
82
|
-
"name": "Install Chromium dependencies (
|
|
82
|
+
"name": "Install Chromium dependencies (Ubuntu 24.04)",
|
|
83
83
|
"package": {
|
|
84
|
-
"name": "
|
|
84
|
+
"name": "libasound2t64,libatk-bridge2.0-0,libatk1.0-0,libcairo2,libcups2,libdrm2,libgbm1,libnss3,libpango-1.0-0,libglib2.0-0,libxcomposite1,libxdamage1,libxfixes3,libxkbcommon0,libxrandr2",
|
|
85
85
|
"state": "present",
|
|
86
86
|
},
|
|
87
87
|
"become": True,
|
|
88
|
-
"when": "ansible_facts['
|
|
88
|
+
"when": "ansible_facts['distribution'] == 'Ubuntu' and ansible_facts['distribution_version'] == '24.04'",
|
|
89
|
+
"ignore_errors": True,
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"name": "Install Chromium dependencies (Other Debian-based)",
|
|
93
|
+
"package": {
|
|
94
|
+
"name": "libasound2,libatk-bridge2.0-0,libatk1.0-0,libcairo2,libcups2,libdrm2,libgbm1,libnss3,libpango-1.0-0,libglib2.0-0,libxcomposite1,libxdamage1,libxfixes3,libxkbcommon0,libxrandr2",
|
|
95
|
+
"state": "present",
|
|
96
|
+
},
|
|
97
|
+
"become": True,
|
|
98
|
+
"when": "ansible_facts['os_family'] == 'Debian' and not (ansible_facts['distribution'] == 'Ubuntu' and ansible_facts['distribution_version'] == '24.04')",
|
|
89
99
|
"ignore_errors": True,
|
|
90
100
|
},
|
|
91
101
|
{
|
|
@@ -149,6 +159,39 @@ DEP_MASSCAN = [
|
|
|
149
159
|
},
|
|
150
160
|
]
|
|
151
161
|
|
|
162
|
+
DEP_JAVA = [
|
|
163
|
+
{
|
|
164
|
+
"name": "Check if Java is installed",
|
|
165
|
+
"command": "which java",
|
|
166
|
+
"register": "java_installed",
|
|
167
|
+
"ignore_errors": True,
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"name": "Install latest JRE (Debian)",
|
|
171
|
+
"package": {"name": ["default-jre"], "state": "present"},
|
|
172
|
+
"become": True,
|
|
173
|
+
"when": "ansible_facts['os_family'] == 'Debian' and java_installed.rc != 0",
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"name": "Install latest JRE (Arch)",
|
|
177
|
+
"package": {"name": ["jre-openjdk"], "state": "present"},
|
|
178
|
+
"become": True,
|
|
179
|
+
"when": "ansible_facts['os_family'] == 'Archlinux' and java_installed.rc != 0",
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"name": "Install latest JRE (Fedora)",
|
|
183
|
+
"package": {"name": ["which", "java-latest-openjdk-headless"], "state": "present"},
|
|
184
|
+
"become": True,
|
|
185
|
+
"when": "ansible_facts['os_family'] == 'RedHat' and java_installed.rc != 0",
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"name": "Install latest JRE (Alpine)",
|
|
189
|
+
"package": {"name": ["openjdk11"], "state": "present"},
|
|
190
|
+
"become": True,
|
|
191
|
+
"when": "ansible_facts['os_family'] == 'Alpine' and java_installed.rc != 0",
|
|
192
|
+
},
|
|
193
|
+
]
|
|
194
|
+
|
|
152
195
|
# shared module dependencies -- ffuf, massdns, chromium, etc.
|
|
153
196
|
SHARED_DEPS = {}
|
|
154
197
|
for var, val in list(locals().items()):
|
bbot/db/sql/models.py
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# This file contains SQLModel (Pydantic + SQLAlchemy) models for BBOT events, scans, and targets.
|
|
2
|
+
# Used by the SQL output modules, but portable for outside use.
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
import logging
|
|
6
|
+
from pydantic import ConfigDict
|
|
7
|
+
from typing import List, Optional
|
|
8
|
+
from datetime import datetime, timezone
|
|
9
|
+
from typing_extensions import Annotated
|
|
10
|
+
from pydantic.functional_validators import AfterValidator
|
|
11
|
+
from sqlmodel import inspect, Column, Field, SQLModel, JSON, String, DateTime as SQLADateTime
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
log = logging.getLogger("bbot_server.models")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def naive_datetime_validator(d: datetime):
|
|
18
|
+
"""
|
|
19
|
+
Converts all dates into UTC, then drops timezone information.
|
|
20
|
+
|
|
21
|
+
This is needed to prevent inconsistencies in sqlite, because it is timezone-naive.
|
|
22
|
+
"""
|
|
23
|
+
# drop timezone info
|
|
24
|
+
return d.replace(tzinfo=None)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
NaiveUTC = Annotated[datetime, AfterValidator(naive_datetime_validator)]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class CustomJSONEncoder(json.JSONEncoder):
|
|
31
|
+
def default(self, obj):
|
|
32
|
+
# handle datetime
|
|
33
|
+
if isinstance(obj, datetime):
|
|
34
|
+
return obj.isoformat()
|
|
35
|
+
return super().default(obj)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class BBOTBaseModel(SQLModel):
|
|
39
|
+
model_config = ConfigDict(extra="ignore")
|
|
40
|
+
|
|
41
|
+
def __init__(self, *args, **kwargs):
|
|
42
|
+
self._validated = None
|
|
43
|
+
super().__init__(*args, **kwargs)
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def validated(self):
|
|
47
|
+
try:
|
|
48
|
+
if self._validated is None:
|
|
49
|
+
self._validated = self.__class__.model_validate(self)
|
|
50
|
+
return self._validated
|
|
51
|
+
except AttributeError:
|
|
52
|
+
return self
|
|
53
|
+
|
|
54
|
+
def to_json(self, **kwargs):
|
|
55
|
+
return json.dumps(self.validated.model_dump(), sort_keys=True, cls=CustomJSONEncoder, **kwargs)
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
def _pk_column_names(cls):
|
|
59
|
+
return [column.name for column in inspect(cls).primary_key]
|
|
60
|
+
|
|
61
|
+
def __hash__(self):
|
|
62
|
+
return hash(self.to_json())
|
|
63
|
+
|
|
64
|
+
def __eq__(self, other):
|
|
65
|
+
return hash(self) == hash(other)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
### EVENT ###
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class Event(BBOTBaseModel, table=True):
|
|
72
|
+
def __init__(self, *args, **kwargs):
|
|
73
|
+
super().__init__(*args, **kwargs)
|
|
74
|
+
data = self._get_data(self.data, self.type)
|
|
75
|
+
self.data = {self.type: data}
|
|
76
|
+
if self.host:
|
|
77
|
+
self.reverse_host = self.host[::-1]
|
|
78
|
+
|
|
79
|
+
def get_data(self):
|
|
80
|
+
return self._get_data(self.data, self.type)
|
|
81
|
+
|
|
82
|
+
@staticmethod
|
|
83
|
+
def _get_data(data, type):
|
|
84
|
+
# handle SIEM-friendly format
|
|
85
|
+
if isinstance(data, dict) and list(data) == [type]:
|
|
86
|
+
return data[type]
|
|
87
|
+
return data
|
|
88
|
+
|
|
89
|
+
uuid: str = Field(
|
|
90
|
+
primary_key=True,
|
|
91
|
+
index=True,
|
|
92
|
+
nullable=False,
|
|
93
|
+
)
|
|
94
|
+
id: str = Field(index=True)
|
|
95
|
+
type: str = Field(index=True)
|
|
96
|
+
scope_description: str
|
|
97
|
+
data: dict = Field(sa_type=JSON)
|
|
98
|
+
host: Optional[str]
|
|
99
|
+
port: Optional[int]
|
|
100
|
+
netloc: Optional[str]
|
|
101
|
+
# store the host in reversed form for efficient lookups by domain
|
|
102
|
+
reverse_host: Optional[str] = Field(default="", exclude=True, index=True)
|
|
103
|
+
resolved_hosts: List = Field(default=[], sa_type=JSON)
|
|
104
|
+
dns_children: dict = Field(default={}, sa_type=JSON)
|
|
105
|
+
web_spider_distance: int = 10
|
|
106
|
+
scope_distance: int = Field(default=10, index=True)
|
|
107
|
+
scan: str = Field(index=True)
|
|
108
|
+
timestamp: NaiveUTC = Field(index=True)
|
|
109
|
+
parent: str = Field(index=True)
|
|
110
|
+
tags: List = Field(default=[], sa_type=JSON)
|
|
111
|
+
module: str = Field(index=True)
|
|
112
|
+
module_sequence: str
|
|
113
|
+
discovery_context: str = ""
|
|
114
|
+
discovery_path: List[str] = Field(default=[], sa_type=JSON)
|
|
115
|
+
parent_chain: List[str] = Field(default=[], sa_type=JSON)
|
|
116
|
+
inserted_at: NaiveUTC = Field(default_factory=lambda: datetime.now(timezone.utc))
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
### SCAN ###
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class Scan(BBOTBaseModel, table=True):
|
|
123
|
+
id: str = Field(primary_key=True)
|
|
124
|
+
name: str
|
|
125
|
+
status: str
|
|
126
|
+
started_at: NaiveUTC = Field(index=True)
|
|
127
|
+
finished_at: Optional[NaiveUTC] = Field(default=None, sa_column=Column(SQLADateTime, nullable=True, index=True))
|
|
128
|
+
duration_seconds: Optional[float] = Field(default=None)
|
|
129
|
+
duration: Optional[str] = Field(default=None)
|
|
130
|
+
target: dict = Field(sa_type=JSON)
|
|
131
|
+
preset: dict = Field(sa_type=JSON)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
### TARGET ###
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class Target(BBOTBaseModel, table=True):
|
|
138
|
+
name: str = "Default Target"
|
|
139
|
+
strict_scope: bool = False
|
|
140
|
+
seeds: List = Field(default=[], sa_type=JSON)
|
|
141
|
+
whitelist: List = Field(default=None, sa_type=JSON)
|
|
142
|
+
blacklist: List = Field(default=[], sa_type=JSON)
|
|
143
|
+
hash: str = Field(sa_column=Column("hash", String(length=255), unique=True, primary_key=True, index=True))
|
|
144
|
+
scope_hash: str = Field(sa_column=Column("scope_hash", String(length=255), index=True))
|
|
145
|
+
seed_hash: str = Field(sa_column=Column("seed_hashhash", String(length=255), index=True))
|
|
146
|
+
whitelist_hash: str = Field(sa_column=Column("whitelist_hash", String(length=255), index=True))
|
|
147
|
+
blacklist_hash: str = Field(sa_column=Column("blacklist_hash", String(length=255), index=True))
|
bbot/defaults.yml
CHANGED
|
@@ -14,6 +14,9 @@ folder_blobs: false
|
|
|
14
14
|
### SCOPE ###
|
|
15
15
|
|
|
16
16
|
scope:
|
|
17
|
+
# strict scope means only exact DNS names are considered in-scope
|
|
18
|
+
# subdomains are not included unless they are explicitly provided in the target list
|
|
19
|
+
strict: false
|
|
17
20
|
# Filter by scope distance which events are displayed in the output
|
|
18
21
|
# 0 == show only in-scope events (affiliates are always shown)
|
|
19
22
|
# 1 == show all events up to distance-1 (1 hop from target)
|
|
@@ -71,7 +74,7 @@ dns:
|
|
|
71
74
|
|
|
72
75
|
web:
|
|
73
76
|
# HTTP proxy
|
|
74
|
-
http_proxy:
|
|
77
|
+
http_proxy:
|
|
75
78
|
# Web user-agent
|
|
76
79
|
user_agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.2151.97
|
|
77
80
|
# Set the maximum number of HTTP links that can be followed in a row (0 == no spidering allowed)
|
|
@@ -109,11 +112,18 @@ engine:
|
|
|
109
112
|
deps:
|
|
110
113
|
ffuf:
|
|
111
114
|
version: "2.1.0"
|
|
115
|
+
# How to handle installation of module dependencies
|
|
116
|
+
# Choices are:
|
|
117
|
+
# - abort_on_failure (default) - if a module dependency fails to install, abort the scan
|
|
118
|
+
# - retry_failed - try again to install failed dependencies
|
|
119
|
+
# - ignore_failed - run the scan regardless of what happens with dependency installation
|
|
120
|
+
# - disable - completely disable BBOT's dependency system (you are responsible for installing tools, pip packages, etc.)
|
|
121
|
+
behavior: abort_on_failure
|
|
112
122
|
|
|
113
123
|
### ADVANCED OPTIONS ###
|
|
114
124
|
|
|
115
125
|
# Load BBOT modules from these custom paths
|
|
116
|
-
|
|
126
|
+
module_dirs: []
|
|
117
127
|
|
|
118
128
|
# Infer certain events from others, e.g. IPs from IP ranges, DNS_NAMEs from URLs, etc.
|
|
119
129
|
speculate: True
|
|
@@ -126,14 +136,6 @@ dnsresolve: True
|
|
|
126
136
|
# Cloud provider tagging
|
|
127
137
|
cloudcheck: True
|
|
128
138
|
|
|
129
|
-
# How to handle installation of module dependencies
|
|
130
|
-
# Choices are:
|
|
131
|
-
# - abort_on_failure (default) - if a module dependency fails to install, abort the scan
|
|
132
|
-
# - retry_failed - try again to install failed dependencies
|
|
133
|
-
# - ignore_failed - run the scan regardless of what happens with dependency installation
|
|
134
|
-
# - disable - completely disable BBOT's dependency system (you are responsible for installing tools, pip packages, etc.)
|
|
135
|
-
deps_behavior: abort_on_failure
|
|
136
|
-
|
|
137
139
|
# Strip querystring from URLs by default
|
|
138
140
|
url_querystring_remove: True
|
|
139
141
|
# When query string is retained, by default collapse parameter values down to a single value per parameter
|
bbot/modules/anubisdb.py
CHANGED
|
@@ -20,7 +20,7 @@ class anubisdb(subdomain_enum):
|
|
|
20
20
|
|
|
21
21
|
async def request_url(self, query):
|
|
22
22
|
url = f"{self.base_url}/{self.helpers.quote(query)}"
|
|
23
|
-
return await self.
|
|
23
|
+
return await self.api_request(url)
|
|
24
24
|
|
|
25
25
|
def abort_if_pre(self, hostname):
|
|
26
26
|
"""
|
|
@@ -38,7 +38,7 @@ class anubisdb(subdomain_enum):
|
|
|
38
38
|
return True, "DNS name is unresolved"
|
|
39
39
|
return await super().abort_if(event)
|
|
40
40
|
|
|
41
|
-
def parse_results(self, r, query):
|
|
41
|
+
async def parse_results(self, r, query):
|
|
42
42
|
results = set()
|
|
43
43
|
json = r.json()
|
|
44
44
|
if json:
|
bbot/modules/apkpure.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from bbot.modules.base import BaseModule
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class apkpure(BaseModule):
|
|
7
|
+
watched_events = ["MOBILE_APP"]
|
|
8
|
+
produced_events = ["FILESYSTEM"]
|
|
9
|
+
flags = ["passive", "safe", "code-enum"]
|
|
10
|
+
meta = {
|
|
11
|
+
"description": "Download android applications from apkpure.com",
|
|
12
|
+
"created_date": "2024-10-11",
|
|
13
|
+
"author": "@domwhewell-sage",
|
|
14
|
+
}
|
|
15
|
+
options = {"output_folder": ""}
|
|
16
|
+
options_desc = {"output_folder": "Folder to download apk's to"}
|
|
17
|
+
|
|
18
|
+
async def setup(self):
|
|
19
|
+
output_folder = self.config.get("output_folder")
|
|
20
|
+
if output_folder:
|
|
21
|
+
self.output_dir = Path(output_folder) / "apk_files"
|
|
22
|
+
else:
|
|
23
|
+
self.output_dir = self.scan.home / "apk_files"
|
|
24
|
+
self.helpers.mkdir(self.output_dir)
|
|
25
|
+
return await super().setup()
|
|
26
|
+
|
|
27
|
+
async def filter_event(self, event):
|
|
28
|
+
if event.type == "MOBILE_APP":
|
|
29
|
+
if "android" not in event.tags:
|
|
30
|
+
return False, "event is not an android app"
|
|
31
|
+
return True
|
|
32
|
+
|
|
33
|
+
async def handle_event(self, event):
|
|
34
|
+
app_id = event.data.get("id", "")
|
|
35
|
+
path = await self.download_apk(app_id)
|
|
36
|
+
if path:
|
|
37
|
+
await self.emit_event(
|
|
38
|
+
{"path": str(path)},
|
|
39
|
+
"FILESYSTEM",
|
|
40
|
+
tags=["apk", "file"],
|
|
41
|
+
parent=event,
|
|
42
|
+
context=f'{{module}} downloaded the apk "{app_id}" to: {path}',
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
async def download_apk(self, app_id):
|
|
46
|
+
path = None
|
|
47
|
+
url = f"https://d.apkpure.com/b/XAPK/{app_id}?version=latest"
|
|
48
|
+
self.helpers.mkdir(self.output_dir / app_id)
|
|
49
|
+
response = await self.helpers.request(url, allow_redirects=True)
|
|
50
|
+
if response:
|
|
51
|
+
attachment = response.headers.get("Content-Disposition", "")
|
|
52
|
+
if "filename" in attachment:
|
|
53
|
+
match = re.search(r'filename="?([^"]+)"?', attachment)
|
|
54
|
+
if match:
|
|
55
|
+
filename = match.group(1)
|
|
56
|
+
extension = filename.split(".")[-1]
|
|
57
|
+
content = response.content
|
|
58
|
+
file_destination = self.output_dir / app_id / f"{app_id}.{extension}"
|
|
59
|
+
with open(file_destination, "wb") as f:
|
|
60
|
+
f.write(content)
|
|
61
|
+
self.info(f'Downloaded "{app_id}" from "{url}", saved to {file_destination}')
|
|
62
|
+
path = file_destination
|
|
63
|
+
return path
|
bbot/modules/azure_tenant.py
CHANGED
|
@@ -102,7 +102,7 @@ class azure_tenant(BaseModule):
|
|
|
102
102
|
status_code = getattr(r, "status_code", 0)
|
|
103
103
|
if status_code not in (200, 421):
|
|
104
104
|
self.verbose(f'Error retrieving azure_tenant domains for "{domain}" (status code: {status_code})')
|
|
105
|
-
return set(),
|
|
105
|
+
return set(), {}
|
|
106
106
|
found_domains = list(set(await self.helpers.re.findall(self.d_xml_regex, r.text)))
|
|
107
107
|
domains = set()
|
|
108
108
|
|
|
@@ -116,7 +116,7 @@ class azure_tenant(BaseModule):
|
|
|
116
116
|
self.scan.word_cloud.absorb_word(d)
|
|
117
117
|
|
|
118
118
|
r = await openid_task
|
|
119
|
-
openid_config =
|
|
119
|
+
openid_config = {}
|
|
120
120
|
with suppress(Exception):
|
|
121
121
|
openid_config = r.json()
|
|
122
122
|
|
bbot/modules/baddns.py
CHANGED
|
@@ -15,26 +15,26 @@ class baddns(BaseModule):
|
|
|
15
15
|
"created_date": "2024-01-18",
|
|
16
16
|
"author": "@liquidsec",
|
|
17
17
|
}
|
|
18
|
-
options = {"custom_nameservers": [], "only_high_confidence": False, "
|
|
18
|
+
options = {"custom_nameservers": [], "only_high_confidence": False, "enabled_submodules": []}
|
|
19
19
|
options_desc = {
|
|
20
20
|
"custom_nameservers": "Force BadDNS to use a list of custom nameservers",
|
|
21
21
|
"only_high_confidence": "Do not emit low-confidence or generic detections",
|
|
22
|
-
"
|
|
22
|
+
"enabled_submodules": "A list of submodules to enable. Empty list (default) enables CNAME, TXT and MX Only",
|
|
23
23
|
}
|
|
24
24
|
module_threads = 8
|
|
25
|
-
deps_pip = ["baddns~=1.
|
|
25
|
+
deps_pip = ["baddns~=1.4.13"]
|
|
26
26
|
|
|
27
27
|
def select_modules(self):
|
|
28
|
-
|
|
29
|
-
module_list = ["CNAME", "NS", "MX", "TXT"]
|
|
30
|
-
if self.config.get("enable_references", False):
|
|
31
|
-
module_list.append("references")
|
|
32
|
-
|
|
33
|
-
selected_modules = []
|
|
28
|
+
selected_submodules = []
|
|
34
29
|
for m in get_all_modules():
|
|
35
|
-
if m.name in
|
|
36
|
-
|
|
37
|
-
return
|
|
30
|
+
if m.name in self.enabled_submodules:
|
|
31
|
+
selected_submodules.append(m)
|
|
32
|
+
return selected_submodules
|
|
33
|
+
|
|
34
|
+
def set_modules(self):
|
|
35
|
+
self.enabled_submodules = self.config.get("enabled_submodules", [])
|
|
36
|
+
if self.enabled_submodules == []:
|
|
37
|
+
self.enabled_submodules = ["CNAME", "MX", "TXT"]
|
|
38
38
|
|
|
39
39
|
async def setup(self):
|
|
40
40
|
self.preset.core.logger.include_logger(logging.getLogger("baddns"))
|
|
@@ -43,10 +43,18 @@ class baddns(BaseModule):
|
|
|
43
43
|
self.custom_nameservers = self.helpers.chain_lists(self.custom_nameservers)
|
|
44
44
|
self.only_high_confidence = self.config.get("only_high_confidence", False)
|
|
45
45
|
self.signatures = load_signatures()
|
|
46
|
+
self.set_modules()
|
|
47
|
+
all_submodules_list = [m.name for m in get_all_modules()]
|
|
48
|
+
for m in self.enabled_submodules:
|
|
49
|
+
if m not in all_submodules_list:
|
|
50
|
+
self.hugewarning(
|
|
51
|
+
f"Selected BadDNS submodule [{m}] does not exist. Available submodules: [{','.join(all_submodules_list)}]"
|
|
52
|
+
)
|
|
53
|
+
return False
|
|
54
|
+
self.debug(f"Enabled BadDNS Submodules: [{','.join(self.enabled_submodules)}]")
|
|
46
55
|
return True
|
|
47
56
|
|
|
48
57
|
async def handle_event(self, event):
|
|
49
|
-
|
|
50
58
|
tasks = []
|
|
51
59
|
for ModuleClass in self.select_modules():
|
|
52
60
|
kwargs = {
|
|
@@ -62,11 +70,18 @@ class baddns(BaseModule):
|
|
|
62
70
|
kwargs["raw_query_retry_wait"] = 0
|
|
63
71
|
|
|
64
72
|
module_instance = ModuleClass(event.data, **kwargs)
|
|
65
|
-
|
|
66
|
-
tasks.append((module_instance,
|
|
67
|
-
|
|
68
|
-
for
|
|
69
|
-
if
|
|
73
|
+
task = asyncio.create_task(module_instance.dispatch())
|
|
74
|
+
tasks.append((module_instance, task))
|
|
75
|
+
|
|
76
|
+
async for completed_task in self.helpers.as_completed([task for _, task in tasks]):
|
|
77
|
+
module_instance = next((m for m, t in tasks if t == completed_task), None)
|
|
78
|
+
try:
|
|
79
|
+
task_result = await completed_task
|
|
80
|
+
except Exception as e:
|
|
81
|
+
self.warning(f"Task for {module_instance} raised an error: {e}")
|
|
82
|
+
task_result = None
|
|
83
|
+
|
|
84
|
+
if task_result:
|
|
70
85
|
results = module_instance.analyze()
|
|
71
86
|
if results and len(results) > 0:
|
|
72
87
|
for r in results:
|
|
@@ -99,7 +114,7 @@ class baddns(BaseModule):
|
|
|
99
114
|
context=f'{{module}}\'s "{r_dict["module"]}" module found {{event.type}}: {r_dict["description"]}',
|
|
100
115
|
)
|
|
101
116
|
else:
|
|
102
|
-
self.warning(f"Got unrecognized confidence level: {
|
|
117
|
+
self.warning(f"Got unrecognized confidence level: {r_dict['confidence']}")
|
|
103
118
|
|
|
104
119
|
found_domains = r_dict.get("found_domains", None)
|
|
105
120
|
if found_domains:
|
|
@@ -111,3 +126,4 @@ class baddns(BaseModule):
|
|
|
111
126
|
tags=[f"baddns-{module_instance.name.lower()}"],
|
|
112
127
|
context=f'{{module}}\'s "{r_dict["module"]}" module found {{event.type}}: {{event.data}}',
|
|
113
128
|
)
|
|
129
|
+
await module_instance.cleanup()
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
from baddns.base import get_all_modules
|
|
2
|
+
from baddns.lib.loader import load_signatures
|
|
3
|
+
from .base import BaseModule
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class baddns_direct(BaseModule):
|
|
9
|
+
watched_events = ["URL", "STORAGE_BUCKET"]
|
|
10
|
+
produced_events = ["FINDING", "VULNERABILITY"]
|
|
11
|
+
flags = ["active", "safe", "subdomain-enum", "baddns", "cloud-enum"]
|
|
12
|
+
meta = {
|
|
13
|
+
"description": "Check for unusual subdomain / service takeover edge cases that require direct detection",
|
|
14
|
+
"created_date": "2024-01-29",
|
|
15
|
+
"author": "@liquidsec",
|
|
16
|
+
}
|
|
17
|
+
options = {"custom_nameservers": []}
|
|
18
|
+
options_desc = {
|
|
19
|
+
"custom_nameservers": "Force BadDNS to use a list of custom nameservers",
|
|
20
|
+
}
|
|
21
|
+
module_threads = 8
|
|
22
|
+
deps_pip = ["baddns~=1.4.13"]
|
|
23
|
+
|
|
24
|
+
scope_distance_modifier = 1
|
|
25
|
+
|
|
26
|
+
async def setup(self):
|
|
27
|
+
self.preset.core.logger.include_logger(logging.getLogger("baddns"))
|
|
28
|
+
self.custom_nameservers = self.config.get("custom_nameservers", []) or None
|
|
29
|
+
if self.custom_nameservers:
|
|
30
|
+
self.custom_nameservers = self.helpers.chain_lists(self.custom_nameservers)
|
|
31
|
+
self.only_high_confidence = self.config.get("only_high_confidence", False)
|
|
32
|
+
self.signatures = load_signatures()
|
|
33
|
+
return True
|
|
34
|
+
|
|
35
|
+
def select_modules(self):
|
|
36
|
+
selected_modules = []
|
|
37
|
+
for m in get_all_modules():
|
|
38
|
+
if m.name in ["CNAME"]:
|
|
39
|
+
selected_modules.append(m)
|
|
40
|
+
return selected_modules
|
|
41
|
+
|
|
42
|
+
async def handle_event(self, event):
|
|
43
|
+
CNAME_direct_module = self.select_modules()[0]
|
|
44
|
+
kwargs = {
|
|
45
|
+
"http_client_class": self.scan.helpers.web.AsyncClient,
|
|
46
|
+
"dns_client": self.scan.helpers.dns.resolver,
|
|
47
|
+
"custom_nameservers": self.custom_nameservers,
|
|
48
|
+
"signatures": self.signatures,
|
|
49
|
+
"direct_mode": True,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
CNAME_direct_instance = CNAME_direct_module(event.host, **kwargs)
|
|
53
|
+
if await CNAME_direct_instance.dispatch():
|
|
54
|
+
results = CNAME_direct_instance.analyze()
|
|
55
|
+
if results and len(results) > 0:
|
|
56
|
+
for r in results:
|
|
57
|
+
r_dict = r.to_dict()
|
|
58
|
+
|
|
59
|
+
data = {
|
|
60
|
+
"description": f"Possible [{r_dict['signature']}] via direct BadDNS analysis. Indicator: [{r_dict['indicator']}] Trigger: [{r_dict['trigger']}] baddns Module: [{r_dict['module']}]",
|
|
61
|
+
"host": str(event.host),
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
await self.emit_event(
|
|
65
|
+
data,
|
|
66
|
+
"FINDING",
|
|
67
|
+
event,
|
|
68
|
+
tags=[f"baddns-{CNAME_direct_module.name.lower()}"],
|
|
69
|
+
context=f'{{module}}\'s "{r_dict["module"]}" module found {{event.type}}: {r_dict["description"]}',
|
|
70
|
+
)
|
|
71
|
+
await CNAME_direct_instance.cleanup()
|
|
72
|
+
|
|
73
|
+
async def filter_event(self, event):
|
|
74
|
+
if event.type == "STORAGE_BUCKET":
|
|
75
|
+
if str(event.module).startswith("bucket_"):
|
|
76
|
+
return False
|
|
77
|
+
self.debug(f"Processing STORAGE_BUCKET for {event.host}")
|
|
78
|
+
if event.type == "URL":
|
|
79
|
+
if event.scope_distance > 0:
|
|
80
|
+
self.debug(
|
|
81
|
+
f"Rejecting {event.host} due to not being in scope (scope distance: {str(event.scope_distance)})"
|
|
82
|
+
)
|
|
83
|
+
return False
|
|
84
|
+
if "cdn-cloudflare" not in event.tags:
|
|
85
|
+
self.debug(f"Rejecting {event.host} due to not being behind CloudFlare")
|
|
86
|
+
return False
|
|
87
|
+
if "status-200" in event.tags or "status-301" in event.tags:
|
|
88
|
+
self.debug(f"Rejecting {event.host} due to lack of non-standard status code")
|
|
89
|
+
return False
|
|
90
|
+
|
|
91
|
+
self.debug(f"Passed all checks and is processing {event.host}")
|
|
92
|
+
return True
|
bbot/modules/baddns_zone.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
from baddns.base import get_all_modules
|
|
2
1
|
from .baddns import baddns as baddns_module
|
|
3
2
|
|
|
4
3
|
|
|
@@ -17,14 +16,10 @@ class baddns_zone(baddns_module):
|
|
|
17
16
|
"only_high_confidence": "Do not emit low-confidence or generic detections",
|
|
18
17
|
}
|
|
19
18
|
module_threads = 8
|
|
20
|
-
deps_pip = ["baddns~=1.
|
|
19
|
+
deps_pip = ["baddns~=1.4.13"]
|
|
21
20
|
|
|
22
|
-
def
|
|
23
|
-
|
|
24
|
-
for m in get_all_modules():
|
|
25
|
-
if m.name in ["NSEC", "zonetransfer"]:
|
|
26
|
-
selected_modules.append(m)
|
|
27
|
-
return selected_modules
|
|
21
|
+
def set_modules(self):
|
|
22
|
+
self.enabled_submodules = ["NSEC", "zonetransfer"]
|
|
28
23
|
|
|
29
24
|
# minimize nsec records feeding back into themselves
|
|
30
25
|
async def filter_event(self, event):
|
bbot/modules/badsecrets.py
CHANGED
|
@@ -17,18 +17,19 @@ class badsecrets(BaseModule):
|
|
|
17
17
|
options_desc = {
|
|
18
18
|
"custom_secrets": "Include custom secrets loaded from a local file",
|
|
19
19
|
}
|
|
20
|
-
deps_pip = ["badsecrets~=0.
|
|
20
|
+
deps_pip = ["badsecrets~=0.6.21"]
|
|
21
21
|
|
|
22
22
|
async def setup(self):
|
|
23
23
|
self.custom_secrets = None
|
|
24
24
|
custom_secrets = self.config.get("custom_secrets", None)
|
|
25
25
|
if custom_secrets:
|
|
26
|
-
|
|
26
|
+
secrets_path = Path(custom_secrets).expanduser()
|
|
27
|
+
if secrets_path.is_file():
|
|
27
28
|
self.custom_secrets = custom_secrets
|
|
28
29
|
self.info(f"Successfully loaded secrets file [{custom_secrets}]")
|
|
29
30
|
else:
|
|
30
31
|
self.warning(f"custom secrets file [{custom_secrets}] is not valid")
|
|
31
|
-
return
|
|
32
|
+
return False, "Custom secrets file not valid"
|
|
32
33
|
return True
|
|
33
34
|
|
|
34
35
|
@property
|