moriarty-project 0.1.6__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.
- moriarty/__init__.py +5 -0
- moriarty/adapters/__init__.py +0 -0
- moriarty/agent/__init__.py +0 -0
- moriarty/assets/modules/.gitkeep +0 -0
- moriarty/assets/modules/asia/douban.yaml +19 -0
- moriarty/assets/modules/asia/kakao.yaml +19 -0
- moriarty/assets/modules/asia/line.yaml +19 -0
- moriarty/assets/modules/asia/mixi.yaml +19 -0
- moriarty/assets/modules/asia/naver.yaml +19 -0
- moriarty/assets/modules/asia/qq.yaml +19 -0
- moriarty/assets/modules/asia/vk.yaml +19 -0
- moriarty/assets/modules/asia/wechat.yaml +19 -0
- moriarty/assets/modules/asia/weibo.yaml +19 -0
- moriarty/assets/modules/asia/xiaohongshu.yaml +19 -0
- moriarty/assets/modules/behance.yaml +47 -0
- moriarty/assets/modules/business/crunchbase.yaml +27 -0
- moriarty/assets/modules/business/fiverr.yaml +32 -0
- moriarty/assets/modules/business/freelancer.yaml +27 -0
- moriarty/assets/modules/business/glassdoor.yaml +27 -0
- moriarty/assets/modules/business/guru.yaml +26 -0
- moriarty/assets/modules/business/indeed.yaml +25 -0
- moriarty/assets/modules/business/monster.yaml +25 -0
- moriarty/assets/modules/business/peopleperhour.yaml +26 -0
- moriarty/assets/modules/business/toptal.yaml +28 -0
- moriarty/assets/modules/business/upwork.yaml +27 -0
- moriarty/assets/modules/business/ziprecruiter.yaml +25 -0
- moriarty/assets/modules/content/buymeacoffee.yaml +27 -0
- moriarty/assets/modules/content/gumroad.yaml +27 -0
- moriarty/assets/modules/content/ko-fi.yaml +32 -0
- moriarty/assets/modules/content/onlyfans.yaml +27 -0
- moriarty/assets/modules/content/patreon.yaml +33 -0
- moriarty/assets/modules/content/substack.yaml +32 -0
- moriarty/assets/modules/creative/500px.yaml +31 -0
- moriarty/assets/modules/creative/artstation.yaml +33 -0
- moriarty/assets/modules/creative/deviantart.yaml +32 -0
- moriarty/assets/modules/creative/flickr.yaml +31 -0
- moriarty/assets/modules/creative/pexels.yaml +26 -0
- moriarty/assets/modules/creative/unsplash.yaml +26 -0
- moriarty/assets/modules/creative/vimeo.yaml +31 -0
- moriarty/assets/modules/crypto/binance.yaml +27 -0
- moriarty/assets/modules/crypto/bitcointalk.yaml +33 -0
- moriarty/assets/modules/crypto/coinbase.yaml +26 -0
- moriarty/assets/modules/crypto/etherscan.yaml +32 -0
- moriarty/assets/modules/crypto/foundation.yaml +28 -0
- moriarty/assets/modules/crypto/kraken.yaml +27 -0
- moriarty/assets/modules/crypto/mirror.yaml +27 -0
- moriarty/assets/modules/crypto/niftygateway.yaml +26 -0
- moriarty/assets/modules/crypto/opensea.yaml +32 -0
- moriarty/assets/modules/crypto/rarible.yaml +27 -0
- moriarty/assets/modules/crypto/superrare.yaml +29 -0
- moriarty/assets/modules/dating/bumble.yaml +25 -0
- moriarty/assets/modules/dating/grindr.yaml +27 -0
- moriarty/assets/modules/dating/happn.yaml +25 -0
- moriarty/assets/modules/dating/her.yaml +27 -0
- moriarty/assets/modules/dating/hinge.yaml +25 -0
- moriarty/assets/modules/dating/match.yaml +25 -0
- moriarty/assets/modules/dating/meetme.yaml +27 -0
- moriarty/assets/modules/dating/okcupid.yaml +25 -0
- moriarty/assets/modules/dating/pof.yaml +25 -0
- moriarty/assets/modules/dating/tinder.yaml +25 -0
- moriarty/assets/modules/dating-nsfw/adultfriendfinder.yaml +28 -0
- moriarty/assets/modules/dating-nsfw/ashley-madison.yaml +26 -0
- moriarty/assets/modules/design/adobe-portfolio.yaml +27 -0
- moriarty/assets/modules/design/carbonmade.yaml +27 -0
- moriarty/assets/modules/design/cgsociety.yaml +27 -0
- moriarty/assets/modules/design/coroflot.yaml +27 -0
- moriarty/assets/modules/design/figma.yaml +27 -0
- moriarty/assets/modules/design/sketch.yaml +26 -0
- moriarty/assets/modules/dev/bitbucket.yaml +35 -0
- moriarty/assets/modules/dev/codeforces.yaml +32 -0
- moriarty/assets/modules/dev/codepen.yaml +34 -0
- moriarty/assets/modules/dev/hackerone.yaml +32 -0
- moriarty/assets/modules/dev/hackthebox.yaml +27 -0
- moriarty/assets/modules/dev/huggingface.yaml +27 -0
- moriarty/assets/modules/dev/kaggle.yaml +32 -0
- moriarty/assets/modules/dev/leetcode.yaml +32 -0
- moriarty/assets/modules/dev/replit.yaml +31 -0
- moriarty/assets/modules/dribbble.yaml +53 -0
- moriarty/assets/modules/ecommerce/etsy.yaml +32 -0
- moriarty/assets/modules/education/duolingo.yaml +32 -0
- moriarty/assets/modules/education/edx.yaml +26 -0
- moriarty/assets/modules/education/khanacademy.yaml +26 -0
- moriarty/assets/modules/education/lynda.yaml +27 -0
- moriarty/assets/modules/education/memrise.yaml +27 -0
- moriarty/assets/modules/education/pluralsight.yaml +27 -0
- moriarty/assets/modules/education/skillshare.yaml +27 -0
- moriarty/assets/modules/education/udacity.yaml +27 -0
- moriarty/assets/modules/email/github_email.yaml +40 -0
- moriarty/assets/modules/email/gravatar.yaml +23 -0
- moriarty/assets/modules/europe/badoo.yaml +19 -0
- moriarty/assets/modules/europe/lovoo.yaml +19 -0
- moriarty/assets/modules/europe/myspace.yaml +19 -0
- moriarty/assets/modules/europe/netlog.yaml +19 -0
- moriarty/assets/modules/europe/ok.yaml +19 -0
- moriarty/assets/modules/europe/skyrock.yaml +19 -0
- moriarty/assets/modules/europe/studivz.yaml +19 -0
- moriarty/assets/modules/europe/tuenti.yaml +19 -0
- moriarty/assets/modules/europe/viadeo.yaml +19 -0
- moriarty/assets/modules/europe/xing.yaml +19 -0
- moriarty/assets/modules/fitness/fitbit.yaml +27 -0
- moriarty/assets/modules/fitness/garmin.yaml +27 -0
- moriarty/assets/modules/fitness/myfitnesspal.yaml +27 -0
- moriarty/assets/modules/fitness/strava.yaml +33 -0
- moriarty/assets/modules/fitness/zwift.yaml +28 -0
- moriarty/assets/modules/food/allrecipes.yaml +27 -0
- moriarty/assets/modules/food/tasty.yaml +27 -0
- moriarty/assets/modules/food/yelp.yaml +32 -0
- moriarty/assets/modules/food/zomato.yaml +28 -0
- moriarty/assets/modules/forums/4chan.yaml +26 -0
- moriarty/assets/modules/forums/8kun.yaml +26 -0
- moriarty/assets/modules/forums/9gag.yaml +26 -0
- moriarty/assets/modules/forums/discourse.yaml +26 -0
- moriarty/assets/modules/forums/disqus.yaml +31 -0
- moriarty/assets/modules/forums/hackernews.yaml +32 -0
- moriarty/assets/modules/forums/launchpad.yaml +27 -0
- moriarty/assets/modules/forums/phpbb.yaml +25 -0
- moriarty/assets/modules/forums/quora.yaml +32 -0
- moriarty/assets/modules/forums/serverfault.yaml +27 -0
- moriarty/assets/modules/forums/slashdot.yaml +28 -0
- moriarty/assets/modules/forums/stackexchange.yaml +32 -0
- moriarty/assets/modules/forums/superuser.yaml +27 -0
- moriarty/assets/modules/forums/vbulletin.yaml +25 -0
- moriarty/assets/modules/forums/xenforo.yaml +25 -0
- moriarty/assets/modules/forums-nsfw/kiwifarms.yaml +25 -0
- moriarty/assets/modules/forums-nsfw/lolcow.yaml +26 -0
- moriarty/assets/modules/gaming/apextracker.yaml +27 -0
- moriarty/assets/modules/gaming/battlenet.yaml +26 -0
- moriarty/assets/modules/gaming/chess.yaml +30 -0
- moriarty/assets/modules/gaming/discord-public.yaml +27 -0
- moriarty/assets/modules/gaming/dotabuff.yaml +32 -0
- moriarty/assets/modules/gaming/epicgames.yaml +25 -0
- moriarty/assets/modules/gaming/faceit.yaml +33 -0
- moriarty/assets/modules/gaming/fortnitetracker.yaml +32 -0
- moriarty/assets/modules/gaming/gog.yaml +26 -0
- moriarty/assets/modules/gaming/itch.yaml +32 -0
- moriarty/assets/modules/gaming/kongregate.yaml +25 -0
- moriarty/assets/modules/gaming/minecraft.yaml +31 -0
- moriarty/assets/modules/gaming/opgg.yaml +32 -0
- moriarty/assets/modules/gaming/origin.yaml +26 -0
- moriarty/assets/modules/gaming/playstation.yaml +30 -0
- moriarty/assets/modules/gaming/roblox.yaml +31 -0
- moriarty/assets/modules/gaming/xbox.yaml +25 -0
- moriarty/assets/modules/github.yaml +68 -0
- moriarty/assets/modules/gitlab.yaml +60 -0
- moriarty/assets/modules/instagram.yaml +48 -0
- moriarty/assets/modules/latam/fotolog.yaml +27 -0
- moriarty/assets/modules/latam/orkut.yaml +26 -0
- moriarty/assets/modules/latam/taringa.yaml +27 -0
- moriarty/assets/modules/learning/coursera.yaml +26 -0
- moriarty/assets/modules/learning/udemy.yaml +26 -0
- moriarty/assets/modules/linkedin.yaml +40 -0
- moriarty/assets/modules/marketplaces/depop.yaml +28 -0
- moriarty/assets/modules/marketplaces/ebay.yaml +32 -0
- moriarty/assets/modules/marketplaces/grailed.yaml +27 -0
- moriarty/assets/modules/marketplaces/mercari.yaml +26 -0
- moriarty/assets/modules/marketplaces/poshmark.yaml +27 -0
- moriarty/assets/modules/marketplaces/reverb.yaml +27 -0
- moriarty/assets/modules/marketplaces/vinted.yaml +28 -0
- moriarty/assets/modules/medium.yaml +44 -0
- moriarty/assets/modules/music/audiomack.yaml +26 -0
- moriarty/assets/modules/music/bandcamp.yaml +30 -0
- moriarty/assets/modules/music/beatport.yaml +28 -0
- moriarty/assets/modules/music/deezer.yaml +26 -0
- moriarty/assets/modules/music/discogs.yaml +32 -0
- moriarty/assets/modules/music/genius.yaml +26 -0
- moriarty/assets/modules/music/lastfm.yaml +30 -0
- moriarty/assets/modules/music/mixcloud.yaml +26 -0
- moriarty/assets/modules/music/reverbnation.yaml +31 -0
- moriarty/assets/modules/music/soundcloud.yaml +31 -0
- moriarty/assets/modules/music/spotify.yaml +26 -0
- moriarty/assets/modules/music/tidal.yaml +26 -0
- moriarty/assets/modules/nsfw/adultwork.yaml +27 -0
- moriarty/assets/modules/nsfw/bongacams.yaml +28 -0
- moriarty/assets/modules/nsfw/cam4.yaml +28 -0
- moriarty/assets/modules/nsfw/chaturbate.yaml +28 -0
- moriarty/assets/modules/nsfw/clips4sale.yaml +27 -0
- moriarty/assets/modules/nsfw/extralunchmoney.yaml +27 -0
- moriarty/assets/modules/nsfw/fansly.yaml +28 -0
- moriarty/assets/modules/nsfw/fetlife.yaml +28 -0
- moriarty/assets/modules/nsfw/iwantclips.yaml +27 -0
- moriarty/assets/modules/nsfw/justforfans.yaml +28 -0
- moriarty/assets/modules/nsfw/loyalfans.yaml +28 -0
- moriarty/assets/modules/nsfw/manyvids.yaml +27 -0
- moriarty/assets/modules/nsfw/myfreecams.yaml +28 -0
- moriarty/assets/modules/nsfw/niteflirt.yaml +26 -0
- moriarty/assets/modules/nsfw/pornhub.yaml +32 -0
- moriarty/assets/modules/nsfw/redtube.yaml +27 -0
- moriarty/assets/modules/nsfw/stripchat.yaml +28 -0
- moriarty/assets/modules/nsfw/xhamster.yaml +27 -0
- moriarty/assets/modules/nsfw/xvideos.yaml +27 -0
- moriarty/assets/modules/nsfw/youporn.yaml +27 -0
- moriarty/assets/modules/photography/eyeem.yaml +25 -0
- moriarty/assets/modules/photography/fotki.yaml +25 -0
- moriarty/assets/modules/photography/photobucket.yaml +26 -0
- moriarty/assets/modules/photography/smugmug.yaml +25 -0
- moriarty/assets/modules/photography/vsco.yaml +27 -0
- moriarty/assets/modules/pinterest.yaml +40 -0
- moriarty/assets/modules/podcasts/anchor.yaml +26 -0
- moriarty/assets/modules/podcasts/castbox.yaml +26 -0
- moriarty/assets/modules/podcasts/podbean.yaml +26 -0
- moriarty/assets/modules/professional/about.yaml +31 -0
- moriarty/assets/modules/professional/academia.yaml +27 -0
- moriarty/assets/modules/professional/angellist.yaml +27 -0
- moriarty/assets/modules/professional/calendly.yaml +26 -0
- moriarty/assets/modules/professional/issuu.yaml +27 -0
- moriarty/assets/modules/professional/mendeley.yaml +27 -0
- moriarty/assets/modules/professional/notion.yaml +27 -0
- moriarty/assets/modules/professional/orcid.yaml +27 -0
- moriarty/assets/modules/professional/producthunt.yaml +31 -0
- moriarty/assets/modules/professional/researchgate.yaml +32 -0
- moriarty/assets/modules/professional/scribd.yaml +27 -0
- moriarty/assets/modules/professional/slideshare.yaml +31 -0
- moriarty/assets/modules/professional/trello.yaml +26 -0
- moriarty/assets/modules/professional/typeform.yaml +27 -0
- moriarty/assets/modules/reddit.yaml +46 -0
- moriarty/assets/modules/regional/amino.yaml +27 -0
- moriarty/assets/modules/regional/ask-fm.yaml +32 -0
- moriarty/assets/modules/regional/babycenter.yaml +26 -0
- moriarty/assets/modules/regional/cafemom.yaml +27 -0
- moriarty/assets/modules/regional/care2.yaml +27 -0
- moriarty/assets/modules/regional/diaspora.yaml +26 -0
- moriarty/assets/modules/regional/ello.yaml +27 -0
- moriarty/assets/modules/regional/gaia.yaml +27 -0
- moriarty/assets/modules/regional/habbo.yaml +27 -0
- moriarty/assets/modules/regional/imvu.yaml +27 -0
- moriarty/assets/modules/regional/lemmy.yaml +27 -0
- moriarty/assets/modules/regional/peertube.yaml +26 -0
- moriarty/assets/modules/regional/pixelfed.yaml +27 -0
- moriarty/assets/modules/regional/plurk.yaml +26 -0
- moriarty/assets/modules/regional/recroom.yaml +27 -0
- moriarty/assets/modules/regional/secondlife.yaml +26 -0
- moriarty/assets/modules/regional/vine-archive.yaml +27 -0
- moriarty/assets/modules/regional/vrchat.yaml +27 -0
- moriarty/assets/modules/regional/weheartit.yaml +27 -0
- moriarty/assets/modules/social/anilist.yaml +27 -0
- moriarty/assets/modules/social/beacons.yaml +26 -0
- moriarty/assets/modules/social/blogger.yaml +27 -0
- moriarty/assets/modules/social/crunchyroll.yaml +27 -0
- moriarty/assets/modules/social/discord.yaml +27 -0
- moriarty/assets/modules/social/dreamwidth.yaml +26 -0
- moriarty/assets/modules/social/facebook.yaml +34 -0
- moriarty/assets/modules/social/goodreads.yaml +32 -0
- moriarty/assets/modules/social/imdb.yaml +27 -0
- moriarty/assets/modules/social/kitsu.yaml +27 -0
- moriarty/assets/modules/social/letterboxd.yaml +32 -0
- moriarty/assets/modules/social/linktree.yaml +26 -0
- moriarty/assets/modules/social/livejournal.yaml +27 -0
- moriarty/assets/modules/social/mastodon.yaml +30 -0
- moriarty/assets/modules/social/minds.yaml +25 -0
- moriarty/assets/modules/social/myanimelist.yaml +32 -0
- moriarty/assets/modules/social/ravelry.yaml +27 -0
- moriarty/assets/modules/social/snapchat.yaml +25 -0
- moriarty/assets/modules/social/telegram.yaml +35 -0
- moriarty/assets/modules/social/tiktok.yaml +35 -0
- moriarty/assets/modules/social/trakt.yaml +28 -0
- moriarty/assets/modules/social/wattpad.yaml +32 -0
- moriarty/assets/modules/social/wordpress-com.yaml +26 -0
- moriarty/assets/modules/sports/espn.yaml +26 -0
- moriarty/assets/modules/sports/untappd.yaml +32 -0
- moriarty/assets/modules/stackoverflow.yaml +47 -0
- moriarty/assets/modules/steam.yaml +47 -0
- moriarty/assets/modules/streaming/caffeine.yaml +25 -0
- moriarty/assets/modules/streaming/dlive.yaml +27 -0
- moriarty/assets/modules/streaming/trovo.yaml +25 -0
- moriarty/assets/modules/travel/airbnb.yaml +26 -0
- moriarty/assets/modules/travel/booking.yaml +26 -0
- moriarty/assets/modules/travel/couchsurfing.yaml +27 -0
- moriarty/assets/modules/travel/tripadvisor.yaml +32 -0
- moriarty/assets/modules/tumblr.yaml +40 -0
- moriarty/assets/modules/twitch.yaml +48 -0
- moriarty/assets/modules/twitter.yaml +39 -0
- moriarty/assets/modules/youtube.yaml +42 -0
- moriarty/assets/templates/cves/CVE-2017-5638.yaml +27 -0
- moriarty/assets/templates/cves/CVE-2018-7600.yaml +30 -0
- moriarty/assets/templates/cves/CVE-2019-11510.yaml +27 -0
- moriarty/assets/templates/cves/CVE-2019-19781.yaml +28 -0
- moriarty/assets/templates/cves/CVE-2020-14882.yaml +28 -0
- moriarty/assets/templates/cves/CVE-2020-14883.yaml +29 -0
- moriarty/assets/templates/cves/CVE-2020-3452.yaml +28 -0
- moriarty/assets/templates/cves/CVE-2020-5902.yaml +28 -0
- moriarty/assets/templates/cves/CVE-2021-21972.yaml +31 -0
- moriarty/assets/templates/cves/CVE-2021-21985.yaml +28 -0
- moriarty/assets/templates/cves/CVE-2021-26084.yaml +30 -0
- moriarty/assets/templates/cves/CVE-2021-41773.yaml +25 -0
- moriarty/assets/templates/cves/CVE-2021-42013.yaml +28 -0
- moriarty/assets/templates/cves/CVE-2021-44228.yaml +27 -0
- moriarty/assets/templates/cves/CVE-2022-0185.yaml +21 -0
- moriarty/assets/templates/cves/CVE-2022-1388.yaml +36 -0
- moriarty/assets/templates/cves/CVE-2022-22954.yaml +28 -0
- moriarty/assets/templates/cves/CVE-2022-22965.yaml +31 -0
- moriarty/assets/templates/cves/CVE-2022-26134.yaml +27 -0
- moriarty/assets/templates/cves/CVE-2023-22515.yaml +27 -0
- moriarty/assets/templates/cves/CVE-2023-22527.yaml +29 -0
- moriarty/assets/templates/cves/CVE-2023-23752.yaml +33 -0
- moriarty/assets/templates/cves/CVE-2023-27350.yaml +27 -0
- moriarty/assets/templates/cves/CVE-2023-2868.yaml +27 -0
- moriarty/assets/templates/cves/CVE-2023-34362.yaml +27 -0
- moriarty/assets/templates/cves/CVE-2023-3519.yaml +28 -0
- moriarty/assets/templates/cves/CVE-2023-4966.yaml +27 -0
- moriarty/assets/templates/default-logins/admin-weak.yaml +40 -0
- moriarty/assets/templates/default-logins/wordpress-default.yaml +38 -0
- moriarty/assets/templates/exposures/aws-credentials.yaml +35 -0
- moriarty/assets/templates/exposures/backup-files.yaml +36 -0
- moriarty/assets/templates/exposures/database-files.yaml +34 -0
- moriarty/assets/templates/exposures/docker-exposed.yaml +31 -0
- moriarty/assets/templates/exposures/env-exposed.yaml +41 -0
- moriarty/assets/templates/exposures/git-exposed.yaml +41 -0
- moriarty/assets/templates/exposures/phpinfo.yaml +36 -0
- moriarty/assets/templates/exposures/svn-exposed.yaml +28 -0
- moriarty/assets/templates/fuzzing/api-endpoints.yaml +39 -0
- moriarty/assets/templates/fuzzing/common-files.yaml +37 -0
- moriarty/assets/templates/fuzzing/open-redirect-fuzz.yaml +35 -0
- moriarty/assets/templates/fuzzing/xss-search-fuzz.yaml +29 -0
- moriarty/assets/templates/git-config.yaml +18 -0
- moriarty/assets/templates/misconfigurations/cors-misconfiguration.yaml +30 -0
- moriarty/assets/templates/misconfigurations/debug-enabled.yaml +29 -0
- moriarty/assets/templates/misconfigurations/directory-listing.yaml +33 -0
- moriarty/assets/templates/misconfigurations/jwt-none-algo.yaml +30 -0
- moriarty/assets/templates/misconfigurations/ssl-tls-weak.yaml +23 -0
- moriarty/assets/templates/vulnerabilities/lfi-basic.yaml +31 -0
- moriarty/assets/templates/vulnerabilities/open-redirect.yaml +31 -0
- moriarty/assets/templates/vulnerabilities/rce-basic.yaml +34 -0
- moriarty/assets/templates/vulnerabilities/sqli-error.yaml +39 -0
- moriarty/assets/templates/vulnerabilities/ssrf-basic.yaml +31 -0
- moriarty/assets/templates/vulnerabilities/xss-reflected.yaml +38 -0
- moriarty/assets/templates/vulnerabilities/xxe-basic.yaml +30 -0
- moriarty/assets/wordlists/subdomains-1000.txt +1063 -0
- moriarty/cli/__init__.py +3 -0
- moriarty/cli/app.py +120 -0
- moriarty/cli/async_utils.py +19 -0
- moriarty/cli/dns.py +83 -0
- moriarty/cli/domain_cmd.py +572 -0
- moriarty/cli/email.py +383 -0
- moriarty/cli/email_investigate.py +224 -0
- moriarty/cli/intelligence.py +329 -0
- moriarty/cli/output.py +62 -0
- moriarty/cli/rdap.py +94 -0
- moriarty/cli/state.py +38 -0
- moriarty/cli/tls.py +91 -0
- moriarty/cli/user.py +227 -0
- moriarty/core/cache_backend.py +223 -0
- moriarty/core/config_manager.py +303 -0
- moriarty/correlator/__init__.py +0 -0
- moriarty/data/__init__.py +81 -0
- moriarty/data/ioc/__init__.py +142 -0
- moriarty/data/ioc/matcher.py +254 -0
- moriarty/data/ioc/types.py +267 -0
- moriarty/data/local_intelligence.py +507 -0
- moriarty/data/signature_loaders/__init__.py +103 -0
- moriarty/data/signature_loaders/base.py +54 -0
- moriarty/data/signature_loaders/ioc_feed.py +356 -0
- moriarty/data/signature_loaders/wappalyzer.py +112 -0
- moriarty/dsl/__init__.py +0 -0
- moriarty/dsl/loader.py +99 -0
- moriarty/dsl/schema.py +47 -0
- moriarty/export/__init__.py +0 -0
- moriarty/intelligence/__init__.py +27 -0
- moriarty/intelligence/__main__.py +150 -0
- moriarty/intelligence/config.py +395 -0
- moriarty/intelligence/ioc.py +267 -0
- moriarty/intelligence/signatures.py +550 -0
- moriarty/intelligence/storage.py +501 -0
- moriarty/interop/__init__.py +0 -0
- moriarty/logging/__init__.py +0 -0
- moriarty/logging/config.py +47 -0
- moriarty/models/__init__.py +16 -0
- moriarty/models/assertion.py +24 -0
- moriarty/models/entity.py +22 -0
- moriarty/models/evidence.py +37 -0
- moriarty/models/relation.py +24 -0
- moriarty/models/types.py +28 -0
- moriarty/modules/__init__.py +0 -0
- moriarty/modules/avatar_hash.py +184 -0
- moriarty/modules/directory_fuzzer.py +322 -0
- moriarty/modules/dns_scan.py +40 -0
- moriarty/modules/domain_scanner.py +620 -0
- moriarty/modules/email_check.py +98 -0
- moriarty/modules/email_investigate.py +267 -0
- moriarty/modules/email_security.py +274 -0
- moriarty/modules/googlemaps_lookup.py +106 -0
- moriarty/modules/headless_executor.py +201 -0
- moriarty/modules/orchestrator.py +60 -0
- moriarty/modules/passive_recon.py +444 -0
- moriarty/modules/phone_extractor.py +151 -0
- moriarty/modules/pipeline_orchestrator.py +726 -0
- moriarty/modules/port_scanner.py +129 -0
- moriarty/modules/rdap.py +61 -0
- moriarty/modules/rdap_extended.py +188 -0
- moriarty/modules/stealth_mode.py +610 -0
- moriarty/modules/subdomain_discovery.py +595 -0
- moriarty/modules/technology_profiler.py +361 -0
- moriarty/modules/template_executor.py +239 -0
- moriarty/modules/template_scanner.py +1048 -0
- moriarty/modules/tls_scan.py +46 -0
- moriarty/modules/tls_validator.py +188 -0
- moriarty/modules/vuln_scanner.py +483 -0
- moriarty/modules/waf_detector.py +585 -0
- moriarty/modules/wayback_discovery.py +234 -0
- moriarty/modules/web_crawler.py +163 -0
- moriarty/net/__init__.py +0 -0
- moriarty/net/dns_cache.py +175 -0
- moriarty/net/dns_client.py +188 -0
- moriarty/net/rdap_client.py +52 -0
- moriarty/net/smtp_client.py +114 -0
- moriarty/net/tls_client.py +111 -0
- moriarty/parsers/__init__.py +0 -0
- moriarty/parsers/html_parser.py +136 -0
- moriarty/tests/__init__.py +0 -0
- moriarty/tests/test_email_service.py +17 -0
- moriarty/tests/test_models.py +46 -0
- moriarty/tests/test_orchestrator.py +30 -0
- moriarty/tests/test_tls_client.py +18 -0
- moriarty_project-0.1.6.dist-info/METADATA +388 -0
- moriarty_project-0.1.6.dist-info/RECORD +418 -0
- moriarty_project-0.1.6.dist-info/WHEEL +4 -0
- moriarty_project-0.1.6.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,595 @@
|
|
1
|
+
"""Descoberta avançada de subdomínios usando 20+ fontes."""
|
2
|
+
import asyncio
|
3
|
+
import re
|
4
|
+
from dataclasses import dataclass
|
5
|
+
from typing import List, Optional, Set
|
6
|
+
|
7
|
+
import httpx
|
8
|
+
import structlog
|
9
|
+
from rich.console import Console
|
10
|
+
from rich.progress import Progress
|
11
|
+
|
12
|
+
logger = structlog.get_logger(__name__)
|
13
|
+
console = Console()
|
14
|
+
|
15
|
+
|
16
|
+
@dataclass
|
17
|
+
class SubdomainResult:
|
18
|
+
"""Resultado de subdomain discovery."""
|
19
|
+
subdomain: str
|
20
|
+
source: str
|
21
|
+
is_valid: bool = False
|
22
|
+
ip_addresses: List[str] = None
|
23
|
+
has_mx: bool = False
|
24
|
+
|
25
|
+
|
26
|
+
class SubdomainDiscovery:
|
27
|
+
"""
|
28
|
+
Descoberta de subdomínios usando múltiplas fontes.
|
29
|
+
|
30
|
+
Fontes suportadas:
|
31
|
+
1. crt.sh (Certificate Transparency)
|
32
|
+
2. VirusTotal
|
33
|
+
3. SecurityTrails
|
34
|
+
4. Shodan
|
35
|
+
5. DNSDumpster
|
36
|
+
6. AlienVault OTX
|
37
|
+
7. ThreatCrowd
|
38
|
+
8. Wayback Machine
|
39
|
+
9. CommonCrawl
|
40
|
+
10. Google Dorking
|
41
|
+
11. Bing
|
42
|
+
12. Yahoo
|
43
|
+
13. Ask
|
44
|
+
14. DNS Bruteforce
|
45
|
+
15. Zone Transfer
|
46
|
+
16. Reverse DNS
|
47
|
+
17. DNSSEC
|
48
|
+
18. NSEC Walking
|
49
|
+
19. Subdomain Permutations
|
50
|
+
20. GitHub Code Search
|
51
|
+
"""
|
52
|
+
|
53
|
+
# Wordlist comum para bruteforce
|
54
|
+
COMMON_SUBDOMAINS = [
|
55
|
+
"www", "mail", "ftp", "localhost", "webmail", "smtp", "pop", "ns1", "webdisk",
|
56
|
+
"ns2", "cpanel", "whm", "autodiscover", "autoconfig", "m", "imap", "test",
|
57
|
+
"ns", "blog", "pop3", "dev", "www2", "admin", "forum", "news", "vpn", "ns3",
|
58
|
+
"mail2", "new", "mysql", "old", "lists", "support", "mobile", "mx", "static",
|
59
|
+
"docs", "beta", "shop", "sql", "secure", "demo", "cp", "calendar", "wiki",
|
60
|
+
"web", "media", "email", "images", "img", "www1", "intranet", "portal", "video",
|
61
|
+
"sip", "dns2", "api", "cdn", "stats", "dns1", "ns4", "www3", "dns", "search",
|
62
|
+
"staging", "server", "mx1", "chat", "wap", "my", "svn", "mail1", "sites", "proxy",
|
63
|
+
"ads", "host", "crm", "cms", "backup", "mx2", "lyncdiscover", "info", "apps",
|
64
|
+
"download", "remote", "db", "forums", "store", "relay", "files", "newsletter",
|
65
|
+
"app", "live", "owa", "en", "start", "sms", "office", "exchange", "ipv4"
|
66
|
+
]
|
67
|
+
|
68
|
+
def __init__(
|
69
|
+
self,
|
70
|
+
domain: str,
|
71
|
+
sources: Optional[List[str]] = None,
|
72
|
+
validate: bool = True,
|
73
|
+
recursive: bool = False,
|
74
|
+
wordlist: Optional[str] = None,
|
75
|
+
timeout: float = 10.0,
|
76
|
+
use_cache: bool = True,
|
77
|
+
):
|
78
|
+
self.domain = domain.lower().strip()
|
79
|
+
self.sources = sources or ["all"]
|
80
|
+
self.validate = validate
|
81
|
+
self.recursive = recursive
|
82
|
+
self.wordlist_path = wordlist
|
83
|
+
self.timeout = timeout
|
84
|
+
self.use_cache = use_cache
|
85
|
+
self.results: Set[str] = set()
|
86
|
+
self.rate_limiters: dict = {}
|
87
|
+
|
88
|
+
# Carrega config para API keys
|
89
|
+
try:
|
90
|
+
from moriarty.core.config_manager import config_manager
|
91
|
+
self.config = config_manager
|
92
|
+
except:
|
93
|
+
self.config = None
|
94
|
+
|
95
|
+
# Carrega wordlist customizada ou usa expandida
|
96
|
+
if wordlist:
|
97
|
+
with open(wordlist, 'r') as f:
|
98
|
+
self.custom_wordlist = [line.strip() for line in f if line.strip()]
|
99
|
+
else:
|
100
|
+
# Usa wordlist expandida (1000+)
|
101
|
+
from pathlib import Path
|
102
|
+
wordlist_1000 = Path(__file__).parent.parent / 'assets' / 'wordlists' / 'subdomains-1000.txt'
|
103
|
+
if wordlist_1000.exists():
|
104
|
+
with open(wordlist_1000, 'r') as f:
|
105
|
+
self.custom_wordlist = [line.strip() for line in f if line.strip()]
|
106
|
+
else:
|
107
|
+
self.custom_wordlist = self.COMMON_SUBDOMAINS
|
108
|
+
|
109
|
+
async def discover(self) -> List[str]:
|
110
|
+
"""Executa discovery em todas as fontes."""
|
111
|
+
logger.info("subdomain.discovery.start", domain=self.domain, sources=len(self.sources))
|
112
|
+
|
113
|
+
# Tenta carregar do cache primeiro
|
114
|
+
if self.use_cache:
|
115
|
+
cached = self._load_from_cache()
|
116
|
+
if cached:
|
117
|
+
logger.info("subdomain.discovery.cache_hit", count=len(cached))
|
118
|
+
return cached
|
119
|
+
|
120
|
+
tasks = []
|
121
|
+
|
122
|
+
# Certificate Transparency
|
123
|
+
if "all" in self.sources or "crtsh" in self.sources:
|
124
|
+
tasks.append(self._with_rate_limit(self._crtsh(), "crtsh"))
|
125
|
+
|
126
|
+
# VirusTotal
|
127
|
+
if "all" in self.sources or "virustotal" in self.sources:
|
128
|
+
tasks.append(self._with_rate_limit(self._virustotal(), "virustotal"))
|
129
|
+
|
130
|
+
# SecurityTrails
|
131
|
+
if "all" in self.sources or "securitytrails" in self.sources:
|
132
|
+
tasks.append(self._with_rate_limit(self._securitytrails(), "securitytrails"))
|
133
|
+
|
134
|
+
# Shodan
|
135
|
+
if "all" in self.sources or "shodan" in self.sources:
|
136
|
+
tasks.append(self._with_rate_limit(self._shodan(), "shodan"))
|
137
|
+
|
138
|
+
# Wayback Machine
|
139
|
+
if "all" in self.sources or "wayback" in self.sources:
|
140
|
+
tasks.append(self._wayback())
|
141
|
+
|
142
|
+
# CommonCrawl
|
143
|
+
if "all" in self.sources or "commoncrawl" in self.sources:
|
144
|
+
tasks.append(self._commoncrawl())
|
145
|
+
|
146
|
+
# AlienVault OTX
|
147
|
+
if "all" in self.sources or "alienvault" in self.sources:
|
148
|
+
tasks.append(self._alienvault())
|
149
|
+
|
150
|
+
# ThreatCrowd
|
151
|
+
if "all" in self.sources or "threatcrowd" in self.sources:
|
152
|
+
tasks.append(self._threatcrowd())
|
153
|
+
|
154
|
+
# DNS Bruteforce
|
155
|
+
if "all" in self.sources or "bruteforce" in self.sources:
|
156
|
+
tasks.append(self._dns_bruteforce())
|
157
|
+
|
158
|
+
# Permutations
|
159
|
+
if "all" in self.sources or "permutations" in self.sources:
|
160
|
+
tasks.append(self._permutations())
|
161
|
+
|
162
|
+
# Zone Transfer
|
163
|
+
if "all" in self.sources or "zonetransfer" in self.sources:
|
164
|
+
tasks.append(self._zone_transfer())
|
165
|
+
|
166
|
+
# Executa todas as tasks
|
167
|
+
with Progress() as progress:
|
168
|
+
task_id = progress.add_task("[cyan]Descobrindo subdomínios...", total=len(tasks))
|
169
|
+
|
170
|
+
for coro in asyncio.as_completed(tasks):
|
171
|
+
await coro
|
172
|
+
progress.advance(task_id)
|
173
|
+
|
174
|
+
# Validação DNS
|
175
|
+
if self.validate:
|
176
|
+
await self._validate_subdomains()
|
177
|
+
|
178
|
+
# Salva no cache
|
179
|
+
if self.use_cache:
|
180
|
+
self._save_to_cache(list(self.results))
|
181
|
+
|
182
|
+
logger.info("subdomain.discovery.complete", domain=self.domain, count=len(self.results))
|
183
|
+
|
184
|
+
return sorted(list(self.results))
|
185
|
+
|
186
|
+
async def _with_rate_limit(self, coro, source: str):
|
187
|
+
"""Aplica rate limiting por fonte."""
|
188
|
+
# Rate limits diferentes por fonte
|
189
|
+
rate_limits = {
|
190
|
+
"crtsh": 0.5, # 1 req/0.5s
|
191
|
+
"virustotal": 4.0, # API limitada
|
192
|
+
"securitytrails": 1.0,
|
193
|
+
"shodan": 1.0,
|
194
|
+
"alienvault": 0.5,
|
195
|
+
"threatcrowd": 2.0,
|
196
|
+
}
|
197
|
+
|
198
|
+
delay = rate_limits.get(source, 0)
|
199
|
+
if delay > 0:
|
200
|
+
if source in self.rate_limiters:
|
201
|
+
elapsed = asyncio.get_event_loop().time() - self.rate_limiters[source]
|
202
|
+
if elapsed < delay:
|
203
|
+
await asyncio.sleep(delay - elapsed)
|
204
|
+
|
205
|
+
result = await coro
|
206
|
+
self.rate_limiters[source] = asyncio.get_event_loop().time()
|
207
|
+
return result
|
208
|
+
|
209
|
+
def _get_api_key(self, service: str) -> Optional[str]:
|
210
|
+
"""Retorna API key configurada para o serviço."""
|
211
|
+
if not self.config:
|
212
|
+
return None
|
213
|
+
|
214
|
+
try:
|
215
|
+
return self.config.get_api_key(service)
|
216
|
+
except Exception:
|
217
|
+
return None
|
218
|
+
|
219
|
+
def _load_from_cache(self) -> Optional[List[str]]:
|
220
|
+
"""Carrega resultados do cache."""
|
221
|
+
import pickle
|
222
|
+
from pathlib import Path
|
223
|
+
import time
|
224
|
+
|
225
|
+
cache_dir = Path.home() / '.moriarty' / 'cache' / 'subdomains'
|
226
|
+
cache_dir.mkdir(parents=True, exist_ok=True)
|
227
|
+
|
228
|
+
cache_file = cache_dir / f"{self.domain}.pkl"
|
229
|
+
|
230
|
+
if cache_file.exists():
|
231
|
+
# Verifica se cache não expirou (24h)
|
232
|
+
age = time.time() - cache_file.stat().st_mtime
|
233
|
+
if age < 86400: # 24 horas
|
234
|
+
try:
|
235
|
+
with open(cache_file, 'rb') as f:
|
236
|
+
return pickle.load(f)
|
237
|
+
except:
|
238
|
+
pass
|
239
|
+
|
240
|
+
return None
|
241
|
+
|
242
|
+
def _save_to_cache(self, subdomains: List[str]):
|
243
|
+
"""Salva resultados no cache."""
|
244
|
+
import pickle
|
245
|
+
from pathlib import Path
|
246
|
+
|
247
|
+
cache_dir = Path.home() / '.moriarty' / 'cache' / 'subdomains'
|
248
|
+
cache_dir.mkdir(parents=True, exist_ok=True)
|
249
|
+
|
250
|
+
cache_file = cache_dir / f"{self.domain}.pkl"
|
251
|
+
|
252
|
+
try:
|
253
|
+
with open(cache_file, 'wb') as f:
|
254
|
+
pickle.dump(subdomains, f)
|
255
|
+
logger.info("subdomain.cache.saved", file=str(cache_file))
|
256
|
+
except Exception as e:
|
257
|
+
logger.warning("subdomain.cache.save_error", error=str(e))
|
258
|
+
|
259
|
+
async def _virustotal(self):
|
260
|
+
"""Busca subdomínios via VirusTotal API v3."""
|
261
|
+
api_key = self._get_api_key("virustotal")
|
262
|
+
if not api_key:
|
263
|
+
logger.debug("subdomain.virustotal.no_key")
|
264
|
+
return
|
265
|
+
|
266
|
+
headers = {"x-apikey": api_key}
|
267
|
+
base_url = f"https://www.virustotal.com/api/v3/domains/{self.domain}/subdomains"
|
268
|
+
next_url: Optional[str] = base_url
|
269
|
+
params = {"limit": 40}
|
270
|
+
|
271
|
+
try:
|
272
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
273
|
+
while next_url:
|
274
|
+
response = await client.get(next_url, headers=headers, params=params if next_url == base_url else None)
|
275
|
+
if response.status_code != 200:
|
276
|
+
logger.warning(
|
277
|
+
"subdomain.virustotal.http_error",
|
278
|
+
status=response.status_code,
|
279
|
+
body=response.text[:200],
|
280
|
+
)
|
281
|
+
break
|
282
|
+
|
283
|
+
data = response.json()
|
284
|
+
for item in data.get("data", []):
|
285
|
+
identifier = (item.get("id") or item.get("value") or "").strip().lower()
|
286
|
+
if identifier and identifier.endswith(self.domain):
|
287
|
+
self.results.add(identifier)
|
288
|
+
|
289
|
+
next_url = data.get("links", {}).get("next")
|
290
|
+
|
291
|
+
logger.info("subdomain.virustotal.found", count=len(self.results))
|
292
|
+
|
293
|
+
except Exception as e:
|
294
|
+
logger.warning("subdomain.virustotal.error", error=str(e))
|
295
|
+
|
296
|
+
async def _securitytrails(self):
|
297
|
+
"""Busca subdomínios via SecurityTrails API."""
|
298
|
+
api_key = self._get_api_key("securitytrails")
|
299
|
+
if not api_key:
|
300
|
+
logger.debug("subdomain.securitytrails.no_key")
|
301
|
+
return
|
302
|
+
|
303
|
+
headers = {"APIKEY": api_key}
|
304
|
+
url = f"https://api.securitytrails.com/v1/domain/{self.domain}/subdomains"
|
305
|
+
params = {"children_only": "false", "include_inactive": "true"}
|
306
|
+
|
307
|
+
try:
|
308
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
309
|
+
response = await client.get(url, headers=headers, params=params)
|
310
|
+
|
311
|
+
if response.status_code != 200:
|
312
|
+
logger.warning(
|
313
|
+
"subdomain.securitytrails.http_error",
|
314
|
+
status=response.status_code,
|
315
|
+
body=response.text[:200],
|
316
|
+
)
|
317
|
+
return
|
318
|
+
|
319
|
+
data = response.json()
|
320
|
+
for sub in data.get("subdomains", []):
|
321
|
+
if not sub:
|
322
|
+
continue
|
323
|
+
hostname = f"{sub.strip().lower()}.{self.domain}"
|
324
|
+
self.results.add(hostname)
|
325
|
+
|
326
|
+
for record in data.get("records", []):
|
327
|
+
fqdn = (record.get("hostname") or record.get("fqdn") or "").lower()
|
328
|
+
if fqdn and fqdn.endswith(self.domain):
|
329
|
+
self.results.add(fqdn)
|
330
|
+
|
331
|
+
logger.info("subdomain.securitytrails.found", count=len(self.results))
|
332
|
+
|
333
|
+
except Exception as e:
|
334
|
+
logger.warning("subdomain.securitytrails.error", error=str(e))
|
335
|
+
|
336
|
+
async def _shodan(self):
|
337
|
+
"""Busca subdomínios via Shodan API."""
|
338
|
+
api_key = self._get_api_key("shodan")
|
339
|
+
if not api_key:
|
340
|
+
logger.debug("subdomain.shodan.no_key")
|
341
|
+
return
|
342
|
+
|
343
|
+
params = {"key": api_key}
|
344
|
+
url = f"https://api.shodan.io/dns/domain/{self.domain}"
|
345
|
+
|
346
|
+
try:
|
347
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
348
|
+
response = await client.get(url, params=params)
|
349
|
+
|
350
|
+
if response.status_code != 200:
|
351
|
+
logger.warning(
|
352
|
+
"subdomain.shodan.http_error",
|
353
|
+
status=response.status_code,
|
354
|
+
body=response.text[:200],
|
355
|
+
)
|
356
|
+
return
|
357
|
+
|
358
|
+
data = response.json()
|
359
|
+
for sub in data.get("subdomains", []):
|
360
|
+
if not sub:
|
361
|
+
continue
|
362
|
+
hostname = f"{sub.strip().lower()}.{self.domain}"
|
363
|
+
self.results.add(hostname)
|
364
|
+
|
365
|
+
for record in data.get("data", []):
|
366
|
+
hostname = (record.get("subdomain") or record.get("domain") or "").lower()
|
367
|
+
if hostname and hostname.endswith(self.domain):
|
368
|
+
self.results.add(hostname)
|
369
|
+
|
370
|
+
logger.info("subdomain.shodan.found", count=len(self.results))
|
371
|
+
|
372
|
+
except Exception as e:
|
373
|
+
logger.warning("subdomain.shodan.error", error=str(e))
|
374
|
+
|
375
|
+
async def _crtsh(self):
|
376
|
+
"""Busca via Certificate Transparency (crt.sh)."""
|
377
|
+
try:
|
378
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
379
|
+
url = f"https://crt.sh/?q=%.{self.domain}&output=json"
|
380
|
+
response = await client.get(url)
|
381
|
+
|
382
|
+
if response.status_code == 200:
|
383
|
+
data = response.json()
|
384
|
+
for entry in data:
|
385
|
+
name = entry.get("name_value", "")
|
386
|
+
# Pode vir com múltiplos nomes separados por \n
|
387
|
+
for subdomain in name.split("\n"):
|
388
|
+
subdomain = subdomain.strip().lower()
|
389
|
+
if subdomain.endswith(self.domain) and "*" not in subdomain:
|
390
|
+
self.results.add(subdomain)
|
391
|
+
|
392
|
+
logger.info("subdomain.crtsh.found", count=len([r for r in self.results]))
|
393
|
+
except Exception as e:
|
394
|
+
logger.warning("subdomain.crtsh.error", error=str(e))
|
395
|
+
|
396
|
+
async def _wayback(self):
|
397
|
+
"""Busca via Wayback Machine."""
|
398
|
+
try:
|
399
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
400
|
+
url = f"http://web.archive.org/cdx/search/cdx?url=*.{self.domain}/*&output=json&collapse=urlkey"
|
401
|
+
response = await client.get(url)
|
402
|
+
|
403
|
+
if response.status_code == 200:
|
404
|
+
data = response.json()
|
405
|
+
for entry in data[1:]: # Pula header
|
406
|
+
url = entry[2]
|
407
|
+
# Extrai subdomain da URL
|
408
|
+
match = re.search(rf'([a-z0-9\-\.]+\.{re.escape(self.domain)})', url, re.IGNORECASE)
|
409
|
+
if match:
|
410
|
+
self.results.add(match.group(1).lower())
|
411
|
+
|
412
|
+
logger.info("subdomain.wayback.found", count=len(self.results))
|
413
|
+
except Exception as e:
|
414
|
+
logger.warning("subdomain.wayback.error", error=str(e))
|
415
|
+
|
416
|
+
async def _commoncrawl(self):
|
417
|
+
"""Busca via CommonCrawl."""
|
418
|
+
try:
|
419
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
420
|
+
# Busca últimos indexes
|
421
|
+
indexes_url = "https://index.commoncrawl.org/collinfo.json"
|
422
|
+
response = await client.get(indexes_url)
|
423
|
+
|
424
|
+
if response.status_code == 200:
|
425
|
+
indexes = response.json()
|
426
|
+
latest_index = indexes[0]["cdx-api"]
|
427
|
+
|
428
|
+
# Busca no index
|
429
|
+
url = f"{latest_index}?url=*.{self.domain}/*&output=json"
|
430
|
+
response = await client.get(url)
|
431
|
+
|
432
|
+
if response.status_code == 200:
|
433
|
+
for line in response.text.split("\n"):
|
434
|
+
if line:
|
435
|
+
try:
|
436
|
+
data = eval(line) # JSON per line
|
437
|
+
url = data.get("url", "")
|
438
|
+
match = re.search(rf'([a-z0-9\-\.]+\.{re.escape(self.domain)})', url, re.IGNORECASE)
|
439
|
+
if match:
|
440
|
+
self.results.add(match.group(1).lower())
|
441
|
+
except:
|
442
|
+
pass
|
443
|
+
except Exception as e:
|
444
|
+
logger.warning("subdomain.commoncrawl.error", error=str(e))
|
445
|
+
|
446
|
+
async def _alienvault(self):
|
447
|
+
"""Busca via AlienVault OTX."""
|
448
|
+
try:
|
449
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
450
|
+
url = f"https://otx.alienvault.com/api/v1/indicators/domain/{self.domain}/passive_dns"
|
451
|
+
response = await client.get(url)
|
452
|
+
|
453
|
+
if response.status_code == 200:
|
454
|
+
data = response.json()
|
455
|
+
for entry in data.get("passive_dns", []):
|
456
|
+
hostname = entry.get("hostname", "")
|
457
|
+
if hostname.endswith(self.domain):
|
458
|
+
self.results.add(hostname.lower())
|
459
|
+
|
460
|
+
logger.info("subdomain.alienvault.found", count=len(self.results))
|
461
|
+
except Exception as e:
|
462
|
+
logger.warning("subdomain.alienvault.error", error=str(e))
|
463
|
+
|
464
|
+
async def _threatcrowd(self):
|
465
|
+
"""Busca via ThreatCrowd."""
|
466
|
+
try:
|
467
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
468
|
+
url = f"https://www.threatcrowd.org/searchApi/v2/domain/report/?domain={self.domain}"
|
469
|
+
response = await client.get(url)
|
470
|
+
|
471
|
+
if response.status_code == 200:
|
472
|
+
data = response.json()
|
473
|
+
for subdomain in data.get("subdomains", []):
|
474
|
+
if subdomain:
|
475
|
+
self.results.add(subdomain.lower())
|
476
|
+
|
477
|
+
logger.info("subdomain.threatcrowd.found", count=len(self.results))
|
478
|
+
except Exception as e:
|
479
|
+
logger.warning("subdomain.threatcrowd.error", error=str(e))
|
480
|
+
|
481
|
+
async def _dns_bruteforce(self):
|
482
|
+
"""DNS Bruteforce usando wordlist."""
|
483
|
+
wordlist = self.custom_wordlist or self.COMMON_SUBDOMAINS
|
484
|
+
|
485
|
+
try:
|
486
|
+
import aiodns
|
487
|
+
resolver = aiodns.DNSResolver(timeout=2.0)
|
488
|
+
|
489
|
+
tasks = []
|
490
|
+
for word in wordlist:
|
491
|
+
subdomain = f"{word}.{self.domain}"
|
492
|
+
tasks.append(self._check_dns(resolver, subdomain))
|
493
|
+
|
494
|
+
# Executa em batches para não sobrecarregar
|
495
|
+
batch_size = 50
|
496
|
+
for i in range(0, len(tasks), batch_size):
|
497
|
+
batch = tasks[i:i+batch_size]
|
498
|
+
await asyncio.gather(*batch, return_exceptions=True)
|
499
|
+
|
500
|
+
logger.info("subdomain.bruteforce.complete", tested=len(wordlist), found=len(self.results))
|
501
|
+
except Exception as e:
|
502
|
+
logger.warning("subdomain.bruteforce.error", error=str(e))
|
503
|
+
|
504
|
+
async def _check_dns(self, resolver, subdomain: str):
|
505
|
+
"""Verifica se subdomain resolve."""
|
506
|
+
try:
|
507
|
+
result = await resolver.query(subdomain, "A")
|
508
|
+
if result:
|
509
|
+
self.results.add(subdomain)
|
510
|
+
except:
|
511
|
+
pass
|
512
|
+
|
513
|
+
async def _permutations(self):
|
514
|
+
"""Gera permutações de subdomínios conhecidos."""
|
515
|
+
# Alterações comuns
|
516
|
+
alterations = ["dev", "staging", "test", "prod", "uat", "qa", "demo", "backup", "old", "new"]
|
517
|
+
|
518
|
+
current_subs = list(self.results)
|
519
|
+
for subdomain in current_subs:
|
520
|
+
# Remove domain principal
|
521
|
+
prefix = subdomain.replace(f".{self.domain}", "")
|
522
|
+
|
523
|
+
for alt in alterations:
|
524
|
+
# Adiciona sufixo
|
525
|
+
new_sub = f"{prefix}-{alt}.{self.domain}"
|
526
|
+
self.results.add(new_sub)
|
527
|
+
|
528
|
+
# Adiciona prefixo
|
529
|
+
new_sub = f"{alt}-{prefix}.{self.domain}"
|
530
|
+
self.results.add(new_sub)
|
531
|
+
|
532
|
+
async def _zone_transfer(self):
|
533
|
+
"""Tenta AXFR (Zone Transfer)."""
|
534
|
+
try:
|
535
|
+
import aiodns
|
536
|
+
resolver = aiodns.DNSResolver(timeout=5.0)
|
537
|
+
|
538
|
+
# Busca NS records
|
539
|
+
ns_records = await resolver.query(self.domain, "NS")
|
540
|
+
|
541
|
+
for ns in ns_records:
|
542
|
+
ns_host = ns.host
|
543
|
+
logger.info("subdomain.zonetransfer.trying", ns=ns_host)
|
544
|
+
|
545
|
+
# AXFR não é suportado por aiodns, precisaria de dnspython
|
546
|
+
# Placeholder para implementação completa
|
547
|
+
pass
|
548
|
+
|
549
|
+
except Exception as e:
|
550
|
+
logger.debug("subdomain.zonetransfer.failed", error=str(e))
|
551
|
+
|
552
|
+
async def _validate_subdomains(self):
|
553
|
+
"""Valida subdomínios encontrados com DNS lookup."""
|
554
|
+
logger.info("subdomain.validation.start", count=len(self.results))
|
555
|
+
|
556
|
+
try:
|
557
|
+
import aiodns
|
558
|
+
resolver = aiodns.DNSResolver(timeout=2.0)
|
559
|
+
|
560
|
+
validated = set()
|
561
|
+
tasks = []
|
562
|
+
|
563
|
+
for subdomain in self.results:
|
564
|
+
tasks.append(self._validate_single(resolver, subdomain))
|
565
|
+
|
566
|
+
results = await asyncio.gather(*tasks, return_exceptions=True)
|
567
|
+
|
568
|
+
for subdomain, is_valid in results:
|
569
|
+
if is_valid and subdomain:
|
570
|
+
validated.add(subdomain)
|
571
|
+
|
572
|
+
self.results = validated
|
573
|
+
logger.info("subdomain.validation.complete", validated=len(validated))
|
574
|
+
|
575
|
+
except Exception as e:
|
576
|
+
logger.warning("subdomain.validation.error", error=str(e))
|
577
|
+
|
578
|
+
async def _validate_single(self, resolver, subdomain: str):
|
579
|
+
"""Valida um único subdomain."""
|
580
|
+
try:
|
581
|
+
result = await resolver.query(subdomain, "A")
|
582
|
+
return (subdomain, True) if result else (subdomain, False)
|
583
|
+
except:
|
584
|
+
return (subdomain, False)
|
585
|
+
|
586
|
+
def export(self, results: List[str], output: str):
|
587
|
+
"""Exporta resultados para arquivo."""
|
588
|
+
with open(output, 'w') as f:
|
589
|
+
for subdomain in sorted(results):
|
590
|
+
f.write(f"{subdomain}\n")
|
591
|
+
|
592
|
+
logger.info("subdomain.export.complete", file=output, count=len(results))
|
593
|
+
|
594
|
+
|
595
|
+
__all__ = ["SubdomainDiscovery", "SubdomainResult"]
|