bbot 2.0.1.4650rc0__tar.gz → 2.1.0.5028rc0__tar.gz
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.
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/PKG-INFO +9 -4
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/README.md +6 -2
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/__init__.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/core.py +0 -2
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/engine.py +4 -3
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/event/base.py +81 -22
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/command.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/depsinstaller/installer.py +59 -20
- bbot-2.1.0.5028rc0/bbot/core/helpers/depsinstaller/sudo_askpass.py +41 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/dns/brute.py +14 -13
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/dns/dns.py +15 -13
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/dns/engine.py +156 -127
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/dns/mock.py +26 -7
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/misc.py +25 -6
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/names_generator.py +17 -3
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/regexes.py +5 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/web/engine.py +17 -11
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/web/web.py +21 -111
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/modules.py +15 -5
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/defaults.yml +5 -2
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/errors.py +0 -8
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/anubisdb.py +1 -1
- bbot-2.1.0.5028rc0/bbot/modules/apkpure.py +53 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/baddns.py +48 -23
- bbot-2.1.0.5028rc0/bbot/modules/baddns_direct.py +93 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/baddns_zone.py +3 -8
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/badsecrets.py +3 -2
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/base.py +183 -39
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/bevigil.py +5 -5
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/binaryedge.py +6 -3
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/builtwith.py +4 -8
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/c99.py +6 -5
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/certspotter.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/chaos.py +5 -5
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/code_repository.py +1 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/columbus.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/crt.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/deadly/ffuf.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/deadly/nuclei.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/deadly/vhost.py +2 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/dehashed.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/dnsdumpster.py +2 -2
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/docker_pull.py +6 -4
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/dockerhub.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/dotnetnuke.py +18 -17
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/emailformat.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/filedownload.py +8 -6
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/fullhunt.py +6 -3
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/generic_ssrf.py +2 -2
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/github_codesearch.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/github_org.py +4 -4
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/github_workflows.py +3 -3
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/gitlab.py +2 -5
- bbot-2.1.0.5028rc0/bbot/modules/google_playstore.py +93 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/hackertarget.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/httpx.py +0 -3
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/hunterio.py +3 -9
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/iis_shortnames.py +13 -24
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/internal/cloudcheck.py +2 -2
- bbot-2.1.0.5028rc0/bbot/modules/internal/dnsresolve.py +318 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/internal/excavate.py +78 -38
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/internal/speculate.py +27 -7
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/internetdb.py +4 -2
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/ip2location.py +3 -5
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/ipstack.py +3 -8
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/leakix.py +6 -6
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/myssl.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/otx.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/output/csv.py +0 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/output/http.py +20 -14
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/output/neo4j.py +7 -2
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/output/slack.py +0 -1
- bbot-2.1.0.5028rc0/bbot/modules/output/teams.py +124 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/paramminer_headers.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/passivetotal.py +2 -2
- bbot-2.1.0.5028rc0/bbot/modules/postman.py +88 -0
- bbot-2.1.0.5028rc0/bbot/modules/postman_download.py +220 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/rapiddns.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/securitytrails.py +3 -8
- bbot-2.1.0.5028rc0/bbot/modules/securitytxt.py +128 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/shodan_dns.py +7 -9
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/skymem.py +2 -2
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/social.py +1 -0
- bbot-2.1.0.5028rc0/bbot/modules/subdomainradar.py +160 -0
- bbot-2.1.0.5028rc0/bbot/modules/templates/github.py +46 -0
- bbot-2.1.0.5028rc0/bbot/modules/templates/postman.py +21 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/templates/shodan.py +13 -12
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/templates/subdomain_enum.py +50 -14
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/templates/webhook.py +1 -3
- bbot-2.1.0.5028rc0/bbot/modules/trickest.py +46 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/trufflehog.py +17 -2
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/unstructured.py +13 -28
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/virustotal.py +6 -23
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/wayback.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/wpscan.py +9 -9
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/zoomeye.py +6 -3
- bbot-2.1.0.5028rc0/bbot/presets/baddns-thorough.yml +12 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/presets/kitchen-sink.yml +1 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/presets/subdomain-enum.yml +7 -7
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/scanner/manager.py +4 -14
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/scanner/preset/args.py +14 -11
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/scanner/preset/environ.py +7 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/scanner/preset/path.py +4 -3
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/scanner/preset/preset.py +6 -2
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/scanner/scanner.py +147 -42
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/bbot_fixtures.py +17 -1
- bbot-2.1.0.5028rc0/bbot/test/owasp_mastg.apk +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/test_cli.py +46 -8
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/test_dns.py +341 -56
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/test_events.py +95 -15
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/test_helpers.py +21 -2
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/test_manager_deduplication.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/test_manager_scope_accuracy.py +31 -33
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/test_modules_basic.py +17 -15
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/test_presets.py +79 -4
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/test_python_api.py +3 -2
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/test_regexes.py +30 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/test_scan.py +28 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/test_scope.py +5 -4
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/test_target.py +3 -3
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/test_web.py +40 -5
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/base.py +2 -13
- bbot-2.1.0.5028rc0/bbot/test/test_step_2/module_tests/test_module_apkpure.py +69 -0
- bbot-2.1.0.5028rc0/bbot/test/test_step_2/module_tests/test_module_baddns_direct.py +64 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_bevigil.py +27 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_binaryedge.py +2 -0
- bbot-2.1.0.5028rc0/bbot/test/test_step_2/module_tests/test_module_c99.py +151 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_code_repository.py +11 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_credshed.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_dehashed.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_discord.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_dnsbrute_mutations.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_excavate.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_git_clone.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_github_org.py +19 -8
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_github_workflows.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_gitlab.py +9 -4
- bbot-2.1.0.5028rc0/bbot/test/test_step_2/module_tests/test_module_google_playstore.py +83 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_httpx.py +3 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_hunterio.py +67 -3
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_json.py +24 -11
- bbot-2.1.0.5028rc0/bbot/test/test_step_2/module_tests/test_module_postman.py +113 -0
- bbot-2.1.0.5028rc0/bbot/test/test_step_2/module_tests/test_module_postman_download.py +439 -0
- bbot-2.1.0.5028rc0/bbot/test/test_step_2/module_tests/test_module_rapiddns.py +108 -0
- bbot-2.1.0.5028rc0/bbot/test/test_step_2/module_tests/test_module_securitytxt.py +50 -0
- bbot-2.1.0.5028rc0/bbot/test/test_step_2/module_tests/test_module_shodan_dns.py +40 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_social.py +11 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_sslcert.py +1 -1
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_stdout.py +5 -3
- bbot-2.1.0.5028rc0/bbot/test/test_step_2/module_tests/test_module_subdomainradar.py +208 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_teams.py +8 -6
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_trufflehog.py +315 -9
- bbot-2.1.0.5028rc0/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py +221 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/pyproject.toml +9 -7
- bbot-2.0.1.4650rc0/bbot/core/helpers/depsinstaller/sudo_askpass.py +0 -5
- bbot-2.0.1.4650rc0/bbot/modules/internal/dnsresolve.py +0 -355
- bbot-2.0.1.4650rc0/bbot/modules/output/teams.py +0 -23
- bbot-2.0.1.4650rc0/bbot/modules/postman.py +0 -164
- bbot-2.0.1.4650rc0/bbot/modules/templates/github.py +0 -38
- bbot-2.0.1.4650rc0/bbot/modules/trickest.py +0 -75
- bbot-2.0.1.4650rc0/bbot/test/test_step_2/module_tests/test_module_c99.py +0 -25
- bbot-2.0.1.4650rc0/bbot/test/test_step_2/module_tests/test_module_postman.py +0 -282
- bbot-2.0.1.4650rc0/bbot/test/test_step_2/module_tests/test_module_rapiddns.py +0 -16
- bbot-2.0.1.4650rc0/bbot/test/test_step_2/module_tests/test_module_shodan_dns.py +0 -21
- bbot-2.0.1.4650rc0/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py +0 -86
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/LICENSE +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/cli.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/__init__.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/config/__init__.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/config/files.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/config/logger.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/event/__init__.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/event/helpers.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/flags.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/__init__.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/async_helpers.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/bloom.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/cache.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/depsinstaller/__init__.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/diff.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/dns/__init__.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/dns/helpers.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/files.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/helper.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/interactsh.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/ntlm.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/process.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/ratelimiter.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/regex.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/url.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/validators.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/web/__init__.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/web/client.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/web/ssl_context.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/helpers/wordcloud.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/core/shared_deps.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/logger.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/__init__.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/ajaxpro.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/azure_realm.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/azure_tenant.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/bucket_amazon.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/bucket_azure.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/bucket_digitalocean.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/bucket_file_enum.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/bucket_firebase.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/bucket_google.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/bypass403.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/censys.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/credshed.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/deadly/dastardly.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/digitorus.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/dnsbrute.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/dnsbrute_mutations.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/dnscaa.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/dnscommonsrv.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/ffuf_shortnames.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/fingerprintx.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/git.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/git_clone.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/gowitness.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/host_header.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/hunt.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/internal/__init__.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/internal/aggregate.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/internal/base.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/ipneighbor.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/newsletters.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/ntlm.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/oauth.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/output/__init__.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/output/asset_inventory.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/output/base.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/output/discord.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/output/emails.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/output/json.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/output/python.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/output/splunk.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/output/stdout.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/output/subdomains.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/output/txt.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/output/web_report.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/output/websocket.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/paramminer_cookies.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/paramminer_getparams.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/pgp.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/portscan.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/report/affiliates.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/report/asn.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/report/base.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/robots.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/secretsdb.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/sitedossier.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/smuggler.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/sslcert.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/subdomaincenter.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/telerik.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/templates/bucket.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/url_manipulation.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/urlscan.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/viewdns.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/wafw00f.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/modules/wappalyzer.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/presets/cloud-enum.yml +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/presets/code-enum.yml +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/presets/email-enum.yml +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/presets/spider.yml +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/presets/web/dirbust-heavy.yml +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/presets/web/dirbust-light.yml +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/presets/web/dotnet-audit.yml +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/presets/web/iis-shortnames.yml +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/presets/web/paramminer.yml +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/presets/web-basic.yml +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/presets/web-screenshots.yml +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/presets/web-thorough.yml +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/scanner/__init__.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/scanner/dispatcher.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/scanner/preset/__init__.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/scanner/preset/conditions.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/scanner/stats.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/scanner/target.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/scripts/docs.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/__init__.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/conftest.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/coverage.cfg +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/run_tests.sh +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test.conf +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_output.ndjson +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/__init__.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/test__module__tests.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/test_bloom_filter.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/test_command.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/test_config.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/test_depsinstaller.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/test_docs.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/test_engine.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_1/test_files.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/__init__.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/__init__.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_affiliates.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_aggregate.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_ajaxpro.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_anubisdb.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_asn.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_asset_inventory.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_azure_realm.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_azure_tenant.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_baddns.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_baddns_zone.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_badsecrets.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_bucket_amazon.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_bucket_azure.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_bucket_digitalocean.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_bucket_file_enum.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_bucket_firebase.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_bucket_google.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_builtwith.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_bypass403.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_censys.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_certspotter.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_chaos.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_cloudcheck.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_columbus.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_crt.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_csv.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_dastardly.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_digitorus.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_dnscaa.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_dnsdumpster.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_dnsresolve.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_docker_pull.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_dockerhub.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_emailformat.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_emails.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_ffuf.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_ffuf_shortnames.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_filedownload.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_fingerprintx.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_fullhunt.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_generic_ssrf.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_git.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_github_codesearch.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_gowitness.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_hackertarget.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_host_header.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_http.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_hunt.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_iis_shortnames.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_internetdb.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_ip2location.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_ipneighbor.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_ipstack.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_leakix.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_myssl.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_neo4j.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_newsletters.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_ntlm.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_nuclei.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_oauth.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_otx.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_paramminer_cookies.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_paramminer_getparams.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_paramminer_headers.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_passivetotal.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_pgp.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_portscan.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_python.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_robots.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_secretsdb.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_securitytrails.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_sitedossier.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_skymem.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_slack.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_smuggler.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_speculate.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_splunk.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_subdomaincenter.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_subdomains.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_telerik.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_trickest.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_txt.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_unstructured.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_url_manipulation.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_urlscan.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_vhost.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_viewdns.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_virustotal.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_wafw00f.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_wappalyzer.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_wayback.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_web_report.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_websocket.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_wpscan.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/module_tests/test_module_zoomeye.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/test_step_2/template_tests/__init__.py +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/testsslcert.pem +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/test/testsslkey.pem +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/wordlists/devops_mutations.txt +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/wordlists/ffuf_shortname_candidates.txt +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/wordlists/ms_on_prem_subdomains.txt +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/wordlists/nameservers.txt +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/wordlists/paramminer_headers.txt +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/wordlists/paramminer_parameters.txt +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/wordlists/raft-small-extensions-lowercase_CLEANED.txt +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/wordlists/top_open_ports_nmap.txt +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/wordlists/valid_url_schemes.txt +0 -0
- {bbot-2.0.1.4650rc0 → bbot-2.1.0.5028rc0}/bbot/wordlists/wordninja_dns.txt.gz +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: bbot
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.1.0.5028rc0
|
|
4
4
|
Summary: OSINT automation for hackers.
|
|
5
5
|
Home-page: https://github.com/blacklanternsecurity/bbot
|
|
6
6
|
License: GPL-3.0
|
|
@@ -14,6 +14,7 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
18
|
Classifier: Topic :: Security
|
|
18
19
|
Requires-Dist: ansible (>=7.3,<9.0)
|
|
19
20
|
Requires-Dist: ansible-runner (>=2.3.2,<3.0.0)
|
|
@@ -26,7 +27,7 @@ Requires-Dist: httpx (>=0.27.0,<0.28.0)
|
|
|
26
27
|
Requires-Dist: idna (>=3.4,<4.0)
|
|
27
28
|
Requires-Dist: jinja2 (>=3.1.3,<4.0.0)
|
|
28
29
|
Requires-Dist: lxml (>=4.9.2,<6.0.0)
|
|
29
|
-
Requires-Dist: mmh3 (>=4.1
|
|
30
|
+
Requires-Dist: mmh3 (>=4.1,<6.0)
|
|
30
31
|
Requires-Dist: omegaconf (>=2.3.0,<3.0.0)
|
|
31
32
|
Requires-Dist: psutil (>=5.9.4,<6.0.0)
|
|
32
33
|
Requires-Dist: pycryptodome (>=3.17,<4.0)
|
|
@@ -355,13 +356,17 @@ For more information, see [Targets](https://www.blacklanternsecurity.com/bbot/St
|
|
|
355
356
|
|
|
356
357
|
Similar to Amass or Subfinder, BBOT supports API keys for various third-party services such as SecurityTrails, etc.
|
|
357
358
|
|
|
358
|
-
The standard way to do this is to enter your API keys in **`~/.config/bbot/bbot.yml
|
|
359
|
+
The standard way to do this is to enter your API keys in **`~/.config/bbot/bbot.yml`**. Note that multiple API keys are allowed:
|
|
359
360
|
```yaml
|
|
360
361
|
modules:
|
|
361
362
|
shodan_dns:
|
|
362
363
|
api_key: 4f41243847da693a4f356c0486114bc6
|
|
363
364
|
c99:
|
|
364
|
-
|
|
365
|
+
# multiple API keys
|
|
366
|
+
api_key:
|
|
367
|
+
- 21a270d5f59c9b05813a72bb41707266
|
|
368
|
+
- ea8f243d9885cf8ce9876a580224fd3c
|
|
369
|
+
- 5bc6ed268ab6488270e496d3183a1a27
|
|
365
370
|
virustotal:
|
|
366
371
|
api_key: dd5f0eee2e4a99b71a939bded450b246
|
|
367
372
|
securitytrails:
|
|
@@ -303,13 +303,17 @@ For more information, see [Targets](https://www.blacklanternsecurity.com/bbot/St
|
|
|
303
303
|
|
|
304
304
|
Similar to Amass or Subfinder, BBOT supports API keys for various third-party services such as SecurityTrails, etc.
|
|
305
305
|
|
|
306
|
-
The standard way to do this is to enter your API keys in **`~/.config/bbot/bbot.yml
|
|
306
|
+
The standard way to do this is to enter your API keys in **`~/.config/bbot/bbot.yml`**. Note that multiple API keys are allowed:
|
|
307
307
|
```yaml
|
|
308
308
|
modules:
|
|
309
309
|
shodan_dns:
|
|
310
310
|
api_key: 4f41243847da693a4f356c0486114bc6
|
|
311
311
|
c99:
|
|
312
|
-
|
|
312
|
+
# multiple API keys
|
|
313
|
+
api_key:
|
|
314
|
+
- 21a270d5f59c9b05813a72bb41707266
|
|
315
|
+
- ea8f243d9885cf8ce9876a580224fd3c
|
|
316
|
+
- 5bc6ed268ab6488270e496d3183a1a27
|
|
313
317
|
virustotal:
|
|
314
318
|
api_key: dd5f0eee2e4a99b71a939bded450b246
|
|
315
319
|
securitytrails:
|
|
@@ -643,6 +643,7 @@ class EngineServer(EngineBase):
|
|
|
643
643
|
self.log.warning(f"{self.name}: Timeout after {timeout:,} seconds in finished_tasks({tasks})")
|
|
644
644
|
for task in tasks:
|
|
645
645
|
task.cancel()
|
|
646
|
+
self._await_cancelled_task(task)
|
|
646
647
|
else:
|
|
647
648
|
if not in_exception_chain(e, (KeyboardInterrupt, asyncio.CancelledError)):
|
|
648
649
|
self.log.error(f"{self.name}: Unhandled exception in finished_tasks({tasks}): {e}")
|
|
@@ -664,9 +665,9 @@ class EngineServer(EngineBase):
|
|
|
664
665
|
child_task.cancel()
|
|
665
666
|
|
|
666
667
|
for task in [parent_task] + list(child_tasks):
|
|
667
|
-
await self.
|
|
668
|
+
await self._await_cancelled_task(task)
|
|
668
669
|
|
|
669
|
-
async def
|
|
670
|
+
async def _await_cancelled_task(self, task):
|
|
670
671
|
try:
|
|
671
672
|
await asyncio.wait_for(task, timeout=10)
|
|
672
673
|
except (TimeoutError, asyncio.exceptions.TimeoutError):
|
|
@@ -683,4 +684,4 @@ class EngineServer(EngineBase):
|
|
|
683
684
|
await self.cancel_task(client_id)
|
|
684
685
|
for client_id, tasks in self.child_tasks.items():
|
|
685
686
|
for task in tasks:
|
|
686
|
-
await self.
|
|
687
|
+
await self._await_cancelled_task(task)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import io
|
|
2
2
|
import re
|
|
3
|
+
import uuid
|
|
3
4
|
import json
|
|
4
5
|
import base64
|
|
5
6
|
import logging
|
|
@@ -24,6 +25,7 @@ from bbot.core.helpers import (
|
|
|
24
25
|
is_domain,
|
|
25
26
|
is_subdomain,
|
|
26
27
|
is_ip,
|
|
28
|
+
is_ip_type,
|
|
27
29
|
is_ptr,
|
|
28
30
|
is_uri,
|
|
29
31
|
url_depth,
|
|
@@ -58,9 +60,10 @@ class BaseEvent:
|
|
|
58
60
|
|
|
59
61
|
Attributes:
|
|
60
62
|
type (str): Specifies the type of the event, e.g., `IP_ADDRESS`, `DNS_NAME`.
|
|
61
|
-
id (str):
|
|
63
|
+
id (str): An identifier for the event (event type + sha1 hash of data). NOT universally unique.
|
|
64
|
+
uuid (UUID): A universally unique identifier for the event.
|
|
62
65
|
data (str or dict): The main data for the event, e.g., a URL or IP address.
|
|
63
|
-
data_graph (str): Representation of `self.data` for
|
|
66
|
+
data_graph (str): Representation of `self.data` for graph nodes (e.g. Neo4j).
|
|
64
67
|
data_human (str): Representation of `self.data` for human output.
|
|
65
68
|
data_id (str): Representation of `self.data` used to calculate the event's ID (and ultimately its hash, which is used for deduplication)
|
|
66
69
|
data_json (str): Representation of `self.data` to be used in JSON serialization.
|
|
@@ -75,6 +78,7 @@ class BaseEvent:
|
|
|
75
78
|
resolved_hosts (list of str): List of hosts to which the event data resolves, applicable for URLs and DNS names.
|
|
76
79
|
parent (BaseEvent): The parent event that led to the discovery of this event.
|
|
77
80
|
parent_id (str): The `id` attribute of the parent event.
|
|
81
|
+
parent_uuid (str): The `uuid` attribute of the parent event.
|
|
78
82
|
tags (set of str): Descriptive tags for the event, e.g., `mx-record`, `in-scope`.
|
|
79
83
|
module (BaseModule): The module that discovered the event.
|
|
80
84
|
module_sequence (str): The sequence of modules that participated in the discovery.
|
|
@@ -154,7 +158,7 @@ class BaseEvent:
|
|
|
154
158
|
Raises:
|
|
155
159
|
ValidationError: If either `scan` or `parent` are not specified and `_dummy` is False.
|
|
156
160
|
"""
|
|
157
|
-
|
|
161
|
+
self._uuid = uuid.uuid4()
|
|
158
162
|
self._id = None
|
|
159
163
|
self._hash = None
|
|
160
164
|
self._data = None
|
|
@@ -166,11 +170,13 @@ class BaseEvent:
|
|
|
166
170
|
self._parent = None
|
|
167
171
|
self._priority = None
|
|
168
172
|
self._parent_id = None
|
|
173
|
+
self._parent_uuid = None
|
|
169
174
|
self._host_original = None
|
|
170
175
|
self._scope_distance = None
|
|
171
176
|
self._module_priority = None
|
|
172
177
|
self._resolved_hosts = set()
|
|
173
178
|
self.dns_children = dict()
|
|
179
|
+
self.raw_dns_records = dict()
|
|
174
180
|
self._discovery_context = ""
|
|
175
181
|
self._discovery_context_regex = re.compile(r"\{(?:event|module)[^}]*\}")
|
|
176
182
|
self.web_spider_distance = 0
|
|
@@ -347,6 +353,12 @@ class BaseEvent:
|
|
|
347
353
|
return 80
|
|
348
354
|
return self._port
|
|
349
355
|
|
|
356
|
+
@property
|
|
357
|
+
def netloc(self):
|
|
358
|
+
if self.host and is_ip_type(self.host, network=False):
|
|
359
|
+
return make_netloc(self.host, self.port)
|
|
360
|
+
return None
|
|
361
|
+
|
|
350
362
|
@property
|
|
351
363
|
def host_stem(self):
|
|
352
364
|
"""
|
|
@@ -379,10 +391,20 @@ class BaseEvent:
|
|
|
379
391
|
"""
|
|
380
392
|
This event's full discovery context, including those of all its parents
|
|
381
393
|
"""
|
|
382
|
-
|
|
394
|
+
discovery_path = []
|
|
395
|
+
if self.parent is not None and self.parent is not self:
|
|
396
|
+
discovery_path = self.parent.discovery_path
|
|
397
|
+
return discovery_path + [self.discovery_context]
|
|
398
|
+
|
|
399
|
+
@property
|
|
400
|
+
def parent_chain(self):
|
|
401
|
+
"""
|
|
402
|
+
This event's full discovery context, including those of all its parents
|
|
403
|
+
"""
|
|
404
|
+
parent_chain = []
|
|
383
405
|
if self.parent is not None and self.parent is not self:
|
|
384
|
-
|
|
385
|
-
return
|
|
406
|
+
parent_chain = self.parent.parent_chain
|
|
407
|
+
return parent_chain + [str(self.uuid)]
|
|
386
408
|
|
|
387
409
|
@property
|
|
388
410
|
def words(self):
|
|
@@ -425,11 +447,6 @@ class BaseEvent:
|
|
|
425
447
|
no_host_information = not bool(self.host)
|
|
426
448
|
return self._always_emit or always_emit_tags or no_host_information
|
|
427
449
|
|
|
428
|
-
@property
|
|
429
|
-
def quick_emit(self):
|
|
430
|
-
no_host_information = not bool(self.host)
|
|
431
|
-
return self._quick_emit or no_host_information
|
|
432
|
-
|
|
433
450
|
@property
|
|
434
451
|
def id(self):
|
|
435
452
|
"""
|
|
@@ -439,6 +456,13 @@ class BaseEvent:
|
|
|
439
456
|
self._id = f"{self.type}:{self.data_hash.hex()}"
|
|
440
457
|
return self._id
|
|
441
458
|
|
|
459
|
+
@property
|
|
460
|
+
def uuid(self):
|
|
461
|
+
"""
|
|
462
|
+
A universally unique identifier for the event
|
|
463
|
+
"""
|
|
464
|
+
return f"{self.type}:{self._uuid}"
|
|
465
|
+
|
|
442
466
|
@property
|
|
443
467
|
def data_hash(self):
|
|
444
468
|
"""
|
|
@@ -556,6 +580,13 @@ class BaseEvent:
|
|
|
556
580
|
return parent_id
|
|
557
581
|
return self._parent_id
|
|
558
582
|
|
|
583
|
+
@property
|
|
584
|
+
def parent_uuid(self):
|
|
585
|
+
parent_uuid = getattr(self.get_parent(), "uuid", None)
|
|
586
|
+
if parent_uuid is not None:
|
|
587
|
+
return parent_uuid
|
|
588
|
+
return self._parent_uuid
|
|
589
|
+
|
|
559
590
|
@property
|
|
560
591
|
def validators(self):
|
|
561
592
|
"""
|
|
@@ -722,12 +753,12 @@ class BaseEvent:
|
|
|
722
753
|
Returns:
|
|
723
754
|
dict: JSON-serializable dictionary representation of the event object.
|
|
724
755
|
"""
|
|
725
|
-
# type, ID, scope description
|
|
726
756
|
j = dict()
|
|
727
|
-
|
|
757
|
+
# type, ID, scope description
|
|
758
|
+
for i in ("type", "id", "uuid", "scope_description", "netloc"):
|
|
728
759
|
v = getattr(self, i, "")
|
|
729
760
|
if v:
|
|
730
|
-
j.update({i: v})
|
|
761
|
+
j.update({i: str(v)})
|
|
731
762
|
# event data
|
|
732
763
|
data_attr = getattr(self, f"data_{mode}", None)
|
|
733
764
|
if data_attr is not None:
|
|
@@ -743,6 +774,8 @@ class BaseEvent:
|
|
|
743
774
|
j["host"] = str(self.host)
|
|
744
775
|
j["resolved_hosts"] = sorted(str(h) for h in self.resolved_hosts)
|
|
745
776
|
j["dns_children"] = {k: list(v) for k, v in self.dns_children.items()}
|
|
777
|
+
if isinstance(self.port, int):
|
|
778
|
+
j["port"] = self.port
|
|
746
779
|
# web spider distance
|
|
747
780
|
web_spider_distance = getattr(self, "web_spider_distance", None)
|
|
748
781
|
if web_spider_distance is not None:
|
|
@@ -758,6 +791,9 @@ class BaseEvent:
|
|
|
758
791
|
parent_id = self.parent_id
|
|
759
792
|
if parent_id:
|
|
760
793
|
j["parent"] = parent_id
|
|
794
|
+
parent_uuid = self.parent_uuid
|
|
795
|
+
if parent_uuid:
|
|
796
|
+
j["parent_uuid"] = parent_uuid
|
|
761
797
|
# tags
|
|
762
798
|
if self.tags:
|
|
763
799
|
j.update({"tags": list(self.tags)})
|
|
@@ -770,6 +806,7 @@ class BaseEvent:
|
|
|
770
806
|
# discovery context
|
|
771
807
|
j["discovery_context"] = self.discovery_context
|
|
772
808
|
j["discovery_path"] = self.discovery_path
|
|
809
|
+
j["parent_chain"] = self.parent_chain
|
|
773
810
|
|
|
774
811
|
# normalize non-primitive python objects
|
|
775
812
|
for k, v in list(j.items()):
|
|
@@ -909,6 +946,10 @@ class SCAN(BaseEvent):
|
|
|
909
946
|
def discovery_path(self):
|
|
910
947
|
return []
|
|
911
948
|
|
|
949
|
+
@property
|
|
950
|
+
def parent_chain(self):
|
|
951
|
+
return []
|
|
952
|
+
|
|
912
953
|
|
|
913
954
|
class FINISHED(BaseEvent):
|
|
914
955
|
"""
|
|
@@ -1053,6 +1094,17 @@ class DnsEvent(BaseEvent):
|
|
|
1053
1094
|
if parent_module_type == "DNS":
|
|
1054
1095
|
self.dns_resolve_distance += 1
|
|
1055
1096
|
# self.add_tag(f"resolve-distance-{self.dns_resolve_distance}")
|
|
1097
|
+
# tag subdomain / domain
|
|
1098
|
+
if is_subdomain(self.host):
|
|
1099
|
+
self.add_tag("subdomain")
|
|
1100
|
+
elif is_domain(self.host):
|
|
1101
|
+
self.add_tag("domain")
|
|
1102
|
+
# tag private IP
|
|
1103
|
+
try:
|
|
1104
|
+
if self.host.is_private:
|
|
1105
|
+
self.add_tag("private-ip")
|
|
1106
|
+
except AttributeError:
|
|
1107
|
+
pass
|
|
1056
1108
|
|
|
1057
1109
|
|
|
1058
1110
|
class IP_RANGE(DnsEvent):
|
|
@@ -1069,13 +1121,6 @@ class IP_RANGE(DnsEvent):
|
|
|
1069
1121
|
|
|
1070
1122
|
|
|
1071
1123
|
class DNS_NAME(DnsEvent):
|
|
1072
|
-
def __init__(self, *args, **kwargs):
|
|
1073
|
-
super().__init__(*args, **kwargs)
|
|
1074
|
-
if is_subdomain(self.data):
|
|
1075
|
-
self.add_tag("subdomain")
|
|
1076
|
-
elif is_domain(self.data):
|
|
1077
|
-
self.add_tag("domain")
|
|
1078
|
-
|
|
1079
1124
|
def sanitize_data(self, data):
|
|
1080
1125
|
return validators.validate_host(data)
|
|
1081
1126
|
|
|
@@ -1498,11 +1543,18 @@ class FILESYSTEM(DictPathEvent):
|
|
|
1498
1543
|
pass
|
|
1499
1544
|
|
|
1500
1545
|
|
|
1501
|
-
class RAW_DNS_RECORD(DictHostEvent):
|
|
1546
|
+
class RAW_DNS_RECORD(DictHostEvent, DnsEvent):
|
|
1502
1547
|
# don't emit raw DNS records for affiliates
|
|
1503
1548
|
_always_emit_tags = ["target"]
|
|
1504
1549
|
|
|
1505
1550
|
|
|
1551
|
+
class MOBILE_APP(DictEvent):
|
|
1552
|
+
_always_emit = True
|
|
1553
|
+
|
|
1554
|
+
def _pretty_string(self):
|
|
1555
|
+
return self.data["url"]
|
|
1556
|
+
|
|
1557
|
+
|
|
1506
1558
|
def make_event(
|
|
1507
1559
|
data,
|
|
1508
1560
|
event_type=None,
|
|
@@ -1671,6 +1723,9 @@ def event_from_json(j, siem_friendly=False):
|
|
|
1671
1723
|
data = j["data"]
|
|
1672
1724
|
kwargs["data"] = data
|
|
1673
1725
|
event = make_event(**kwargs)
|
|
1726
|
+
event_uuid = j.get("uuid", None)
|
|
1727
|
+
if event_uuid is not None:
|
|
1728
|
+
event._uuid = uuid.UUID(event_uuid.split(":")[-1])
|
|
1674
1729
|
|
|
1675
1730
|
resolved_hosts = j.get("resolved_hosts", [])
|
|
1676
1731
|
event._resolved_hosts = set(resolved_hosts)
|
|
@@ -1680,6 +1735,10 @@ def event_from_json(j, siem_friendly=False):
|
|
|
1680
1735
|
parent_id = j.get("parent", None)
|
|
1681
1736
|
if parent_id is not None:
|
|
1682
1737
|
event._parent_id = parent_id
|
|
1738
|
+
parent_uuid = j.get("parent_uuid", None)
|
|
1739
|
+
if parent_uuid is not None:
|
|
1740
|
+
parent_type, parent_uuid = parent_uuid.split(":", 1)
|
|
1741
|
+
event._parent_uuid = parent_type + ":" + str(uuid.UUID(parent_uuid))
|
|
1683
1742
|
return event
|
|
1684
1743
|
except KeyError as e:
|
|
1685
1744
|
raise ValidationError(f"Event missing required field: {e}")
|
|
@@ -295,7 +295,7 @@ def _prepare_command_kwargs(self, command, kwargs):
|
|
|
295
295
|
if sudo and os.geteuid() != 0:
|
|
296
296
|
self.depsinstaller.ensure_root()
|
|
297
297
|
env["SUDO_ASKPASS"] = str((self.tools_dir / self.depsinstaller.askpass_filename).resolve())
|
|
298
|
-
env["BBOT_SUDO_PASS"] = self.depsinstaller.
|
|
298
|
+
env["BBOT_SUDO_PASS"] = self.depsinstaller.encrypted_sudo_pw
|
|
299
299
|
kwargs["env"] = env
|
|
300
300
|
|
|
301
301
|
PATH = os.environ.get("PATH", "")
|
|
@@ -10,10 +10,11 @@ from pathlib import Path
|
|
|
10
10
|
from threading import Lock
|
|
11
11
|
from itertools import chain
|
|
12
12
|
from contextlib import suppress
|
|
13
|
+
from secrets import token_bytes
|
|
13
14
|
from ansible_runner.interface import run
|
|
14
15
|
from subprocess import CalledProcessError
|
|
15
16
|
|
|
16
|
-
from ..misc import can_sudo_without_password, os_platform
|
|
17
|
+
from ..misc import can_sudo_without_password, os_platform, rm_at_exit
|
|
17
18
|
|
|
18
19
|
log = logging.getLogger("bbot.core.helpers.depsinstaller")
|
|
19
20
|
|
|
@@ -29,14 +30,13 @@ class DepsInstaller:
|
|
|
29
30
|
http_timeout = self.web_config.get("http_timeout", 30)
|
|
30
31
|
os.environ["ANSIBLE_TIMEOUT"] = str(http_timeout)
|
|
31
32
|
|
|
33
|
+
# cache encrypted sudo pass
|
|
32
34
|
self.askpass_filename = "sudo_askpass.py"
|
|
35
|
+
self._sudo_password = None
|
|
36
|
+
self._sudo_cache_setup = False
|
|
37
|
+
self._setup_sudo_cache()
|
|
33
38
|
self._installed_sudo_askpass = False
|
|
34
|
-
|
|
35
|
-
if self._sudo_password is None:
|
|
36
|
-
if self.core.bbot_sudo_pass is not None:
|
|
37
|
-
self._sudo_password = self.core.bbot_sudo_pass
|
|
38
|
-
elif can_sudo_without_password():
|
|
39
|
-
self._sudo_password = ""
|
|
39
|
+
|
|
40
40
|
self.data_dir = self.parent_helper.cache_dir / "depsinstaller"
|
|
41
41
|
self.parent_helper.mkdir(self.data_dir)
|
|
42
42
|
self.setup_status_cache = self.data_dir / "setup_status.json"
|
|
@@ -314,20 +314,27 @@ class DepsInstaller:
|
|
|
314
314
|
|
|
315
315
|
def ensure_root(self, message=""):
|
|
316
316
|
self._install_sudo_askpass()
|
|
317
|
+
# skip if we've already done this
|
|
318
|
+
if self._sudo_password is not None:
|
|
319
|
+
return
|
|
317
320
|
with self.ensure_root_lock:
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
321
|
+
# first check if the environment variable is set
|
|
322
|
+
_sudo_password = os.environ.get("BBOT_SUDO_PASS", None)
|
|
323
|
+
if _sudo_password is not None or os.geteuid() == 0 or can_sudo_without_password():
|
|
324
|
+
# if we're already root or we can sudo without a password, there's no need to prompt
|
|
325
|
+
return
|
|
326
|
+
|
|
327
|
+
if message:
|
|
328
|
+
log.warning(message)
|
|
329
|
+
while not self._sudo_password:
|
|
330
|
+
# sleep for a split second to flush previous log messages
|
|
331
|
+
sleep(0.1)
|
|
332
|
+
_sudo_password = getpass.getpass(prompt="[USER] Please enter sudo password: ")
|
|
333
|
+
if self.parent_helper.verify_sudo_password(_sudo_password):
|
|
334
|
+
log.success("Authentication successful")
|
|
335
|
+
self._sudo_password = _sudo_password
|
|
336
|
+
else:
|
|
337
|
+
log.warning("Incorrect password")
|
|
331
338
|
|
|
332
339
|
def install_core_deps(self):
|
|
333
340
|
to_install = set()
|
|
@@ -343,6 +350,38 @@ class DepsInstaller:
|
|
|
343
350
|
self.ensure_root()
|
|
344
351
|
self.apt_install(list(to_install))
|
|
345
352
|
|
|
353
|
+
def _setup_sudo_cache(self):
|
|
354
|
+
if not self._sudo_cache_setup:
|
|
355
|
+
self._sudo_cache_setup = True
|
|
356
|
+
# write temporary encryption key, to be deleted upon scan completion
|
|
357
|
+
self._sudo_temp_keyfile = self.parent_helper.temp_filename()
|
|
358
|
+
# remove it at exit
|
|
359
|
+
rm_at_exit(self._sudo_temp_keyfile)
|
|
360
|
+
# generate random 32-byte key
|
|
361
|
+
random_key = token_bytes(32)
|
|
362
|
+
# write key to file and set secure permissions
|
|
363
|
+
self._sudo_temp_keyfile.write_bytes(random_key)
|
|
364
|
+
self._sudo_temp_keyfile.chmod(0o600)
|
|
365
|
+
# export path to environment variable, for use in askpass script
|
|
366
|
+
os.environ["BBOT_SUDO_KEYFILE"] = str(self._sudo_temp_keyfile.resolve())
|
|
367
|
+
|
|
368
|
+
@property
|
|
369
|
+
def encrypted_sudo_pw(self):
|
|
370
|
+
if self._sudo_password is None:
|
|
371
|
+
return ""
|
|
372
|
+
return self._encrypt_sudo_pw(self._sudo_password)
|
|
373
|
+
|
|
374
|
+
def _encrypt_sudo_pw(self, pw):
|
|
375
|
+
from Crypto.Cipher import AES
|
|
376
|
+
from Crypto.Util.Padding import pad
|
|
377
|
+
|
|
378
|
+
key = self._sudo_temp_keyfile.read_bytes()
|
|
379
|
+
cipher = AES.new(key, AES.MODE_CBC)
|
|
380
|
+
ct_bytes = cipher.encrypt(pad(pw.encode(), AES.block_size))
|
|
381
|
+
iv = cipher.iv.hex()
|
|
382
|
+
ct = ct_bytes.hex()
|
|
383
|
+
return f"{iv}:{ct}"
|
|
384
|
+
|
|
346
385
|
def _install_sudo_askpass(self):
|
|
347
386
|
if not self._installed_sudo_askpass:
|
|
348
387
|
self._installed_sudo_askpass = True
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from Crypto.Cipher import AES
|
|
6
|
+
from Crypto.Util.Padding import unpad
|
|
7
|
+
|
|
8
|
+
ENV_VAR_NAME = "BBOT_SUDO_PASS"
|
|
9
|
+
KEY_ENV_VAR_PATH = "BBOT_SUDO_KEYFILE"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def decrypt_password(encrypted_data, key):
|
|
13
|
+
iv, ciphertext = encrypted_data.split(":")
|
|
14
|
+
iv = bytes.fromhex(iv)
|
|
15
|
+
ct = bytes.fromhex(ciphertext)
|
|
16
|
+
cipher = AES.new(key, AES.MODE_CBC, iv)
|
|
17
|
+
pt = unpad(cipher.decrypt(ct), AES.block_size)
|
|
18
|
+
return pt.decode("utf-8")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def main():
|
|
22
|
+
encrypted_password = os.environ.get(ENV_VAR_NAME, "")
|
|
23
|
+
# remove variable from environment once we've got it
|
|
24
|
+
os.environ.pop(ENV_VAR_NAME, None)
|
|
25
|
+
encryption_keypath = Path(os.environ.get(KEY_ENV_VAR_PATH, ""))
|
|
26
|
+
|
|
27
|
+
if not encrypted_password or not encryption_keypath.is_file():
|
|
28
|
+
print("Error: Encrypted password or encryption key not found in environment variables.", file=sys.stderr)
|
|
29
|
+
sys.exit(1)
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
key = encryption_keypath.read_bytes()
|
|
33
|
+
decrypted_password = decrypt_password(encrypted_password, key)
|
|
34
|
+
print(decrypted_password, end="")
|
|
35
|
+
except Exception as e:
|
|
36
|
+
print(f'Error decrypting password "{encrypted_password}": {str(e)}', file=sys.stderr)
|
|
37
|
+
sys.exit(1)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
if __name__ == "__main__":
|
|
41
|
+
main()
|
|
@@ -15,15 +15,17 @@ class DNSBrute:
|
|
|
15
15
|
>>> results = await self.helpers.dns.brute(self, domain, subdomains)
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
_nameservers_url = (
|
|
19
19
|
"https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt"
|
|
20
20
|
)
|
|
21
21
|
|
|
22
22
|
def __init__(self, parent_helper):
|
|
23
23
|
self.parent_helper = parent_helper
|
|
24
24
|
self.log = logging.getLogger("bbot.helper.dns.brute")
|
|
25
|
+
self.dns_config = self.parent_helper.config.get("dns", {})
|
|
25
26
|
self.num_canaries = 100
|
|
26
|
-
self.max_resolvers = self.
|
|
27
|
+
self.max_resolvers = self.dns_config.get("brute_threads", 1000)
|
|
28
|
+
self.nameservers_url = self.dns_config.get("brute_nameservers", self._nameservers_url)
|
|
27
29
|
self.devops_mutations = list(self.parent_helper.word_cloud.devops_mutations)
|
|
28
30
|
self.digit_regex = self.parent_helper.re.compile(r"\d+")
|
|
29
31
|
self._resolver_file = None
|
|
@@ -39,18 +41,12 @@ class DNSBrute:
|
|
|
39
41
|
type = "A"
|
|
40
42
|
type = str(type).strip().upper()
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
domain_wildcard_rdtypes.add(rdtype)
|
|
47
|
-
if any([r in domain_wildcard_rdtypes for r in (type, "CNAME")]):
|
|
48
|
-
self.log.info(
|
|
49
|
-
f"Aborting massdns on {domain} because it's a wildcard domain ({','.join(domain_wildcard_rdtypes)})"
|
|
44
|
+
wildcard_rdtypes = await self.parent_helper.dns.is_wildcard_domain(domain, (type, "CNAME"))
|
|
45
|
+
if wildcard_rdtypes:
|
|
46
|
+
self.log.hugewarning(
|
|
47
|
+
f"Aborting massdns on {domain} because it's a wildcard domain ({','.join(wildcard_rdtypes)})"
|
|
50
48
|
)
|
|
51
49
|
return []
|
|
52
|
-
else:
|
|
53
|
-
self.log.debug(f"{domain}: A is not in domain_wildcard_rdtypes:{domain_wildcard_rdtypes}")
|
|
54
50
|
|
|
55
51
|
canaries = self.gen_random_subdomains(self.num_canaries)
|
|
56
52
|
canaries_list = list(canaries)
|
|
@@ -148,10 +144,15 @@ class DNSBrute:
|
|
|
148
144
|
|
|
149
145
|
async def resolver_file(self):
|
|
150
146
|
if self._resolver_file is None:
|
|
151
|
-
self.
|
|
147
|
+
self._resolver_file_original = await self.parent_helper.wordlist(
|
|
152
148
|
self.nameservers_url,
|
|
153
149
|
cache_hrs=24 * 7,
|
|
154
150
|
)
|
|
151
|
+
nameservers = set(self.parent_helper.read_file(self._resolver_file_original))
|
|
152
|
+
nameservers.difference_update(self.parent_helper.dns.system_resolvers)
|
|
153
|
+
# exclude system nameservers from brute-force
|
|
154
|
+
# this helps prevent rate-limiting which might cause BBOT's main dns queries to fail
|
|
155
|
+
self._resolver_file = self.parent_helper.tempfile(nameservers, pipe=False)
|
|
155
156
|
return self._resolver_file
|
|
156
157
|
|
|
157
158
|
def gen_random_subdomains(self, n=50):
|
|
@@ -66,7 +66,7 @@ class DNSHelper(EngineClient):
|
|
|
66
66
|
self.resolver.timeout = self.timeout
|
|
67
67
|
self.resolver.lifetime = self.timeout
|
|
68
68
|
|
|
69
|
-
self.runaway_limit = self.
|
|
69
|
+
self.runaway_limit = self.dns_config.get("runaway_limit", 5)
|
|
70
70
|
|
|
71
71
|
# wildcard handling
|
|
72
72
|
self.wildcard_disable = self.dns_config.get("wildcard_disable", False)
|
|
@@ -117,8 +117,11 @@ class DNSHelper(EngineClient):
|
|
|
117
117
|
self._brute = DNSBrute(self.parent_helper)
|
|
118
118
|
return self._brute
|
|
119
119
|
|
|
120
|
-
@async_cachedmethod(
|
|
121
|
-
|
|
120
|
+
@async_cachedmethod(
|
|
121
|
+
lambda self: self._is_wildcard_cache,
|
|
122
|
+
key=lambda query, rdtypes, raw_dns_records: (query, tuple(sorted(rdtypes)), bool(raw_dns_records)),
|
|
123
|
+
)
|
|
124
|
+
async def is_wildcard(self, query, rdtypes, raw_dns_records=None):
|
|
122
125
|
"""
|
|
123
126
|
Use this method to check whether a *host* is a wildcard entry
|
|
124
127
|
|
|
@@ -150,9 +153,6 @@ class DNSHelper(EngineClient):
|
|
|
150
153
|
Note:
|
|
151
154
|
`is_wildcard` can be True, False, or None (indicating that wildcard detection was inconclusive)
|
|
152
155
|
"""
|
|
153
|
-
if [ips, rdtype].count(None) == 1:
|
|
154
|
-
raise ValueError("Both ips and rdtype must be specified")
|
|
155
|
-
|
|
156
156
|
query = self._wildcard_prevalidation(query)
|
|
157
157
|
if not query:
|
|
158
158
|
return {}
|
|
@@ -161,15 +161,17 @@ class DNSHelper(EngineClient):
|
|
|
161
161
|
if is_domain(query):
|
|
162
162
|
return {}
|
|
163
163
|
|
|
164
|
-
return await self.run_and_return("is_wildcard", query=query,
|
|
164
|
+
return await self.run_and_return("is_wildcard", query=query, rdtypes=rdtypes, raw_dns_records=raw_dns_records)
|
|
165
165
|
|
|
166
|
-
@async_cachedmethod(
|
|
167
|
-
|
|
166
|
+
@async_cachedmethod(
|
|
167
|
+
lambda self: self._is_wildcard_domain_cache, key=lambda domain, rdtypes: (domain, tuple(sorted(rdtypes)))
|
|
168
|
+
)
|
|
169
|
+
async def is_wildcard_domain(self, domain, rdtypes):
|
|
168
170
|
domain = self._wildcard_prevalidation(domain)
|
|
169
171
|
if not domain:
|
|
170
172
|
return {}
|
|
171
173
|
|
|
172
|
-
return await self.run_and_return("is_wildcard_domain", domain=domain,
|
|
174
|
+
return await self.run_and_return("is_wildcard_domain", domain=domain, rdtypes=rdtypes)
|
|
173
175
|
|
|
174
176
|
def _wildcard_prevalidation(self, host):
|
|
175
177
|
if self.wildcard_disable:
|
|
@@ -192,8 +194,8 @@ class DNSHelper(EngineClient):
|
|
|
192
194
|
|
|
193
195
|
return host
|
|
194
196
|
|
|
195
|
-
async def _mock_dns(self, mock_data):
|
|
197
|
+
async def _mock_dns(self, mock_data, custom_lookup_fn=None):
|
|
196
198
|
from .mock import MockResolver
|
|
197
199
|
|
|
198
|
-
self.resolver = MockResolver(mock_data)
|
|
199
|
-
await self.run_and_return("_mock_dns", mock_data=mock_data)
|
|
200
|
+
self.resolver = MockResolver(mock_data, custom_lookup_fn=custom_lookup_fn)
|
|
201
|
+
await self.run_and_return("_mock_dns", mock_data=mock_data, custom_lookup_fn=custom_lookup_fn)
|