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
moriarty/models/types.py
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from enum import Enum
|
4
|
+
|
5
|
+
|
6
|
+
class EntityKind(str, Enum):
|
7
|
+
EMAIL = "email"
|
8
|
+
USERNAME = "username"
|
9
|
+
PERSON = "person"
|
10
|
+
DOMAIN = "domain"
|
11
|
+
IP_ADDRESS = "ip"
|
12
|
+
ORGANIZATION = "organization"
|
13
|
+
|
14
|
+
|
15
|
+
class EvidenceKind(str, Enum):
|
16
|
+
NETWORK = "network"
|
17
|
+
WEB = "web"
|
18
|
+
FILE = "file"
|
19
|
+
MANUAL = "manual"
|
20
|
+
|
21
|
+
|
22
|
+
class ConfidenceBand(str, Enum):
|
23
|
+
HIGH = "high"
|
24
|
+
MEDIUM = "medium"
|
25
|
+
INDICATIVE = "indicative"
|
26
|
+
|
27
|
+
|
28
|
+
__all__ = ["EntityKind", "EvidenceKind", "ConfidenceBand"]
|
File without changes
|
@@ -0,0 +1,184 @@
|
|
1
|
+
"""Hashing perceptual de avatares para matching."""
|
2
|
+
import hashlib
|
3
|
+
from dataclasses import dataclass
|
4
|
+
from io import BytesIO
|
5
|
+
from typing import Optional
|
6
|
+
|
7
|
+
import httpx
|
8
|
+
import structlog
|
9
|
+
from PIL import Image
|
10
|
+
|
11
|
+
logger = structlog.get_logger(__name__)
|
12
|
+
|
13
|
+
|
14
|
+
@dataclass
|
15
|
+
class AvatarHash:
|
16
|
+
"""Hash perceptual de avatar."""
|
17
|
+
url: str
|
18
|
+
phash: str # Perceptual hash (64 bits hex)
|
19
|
+
ahash: str # Average hash (64 bits hex)
|
20
|
+
dhash: str # Difference hash (64 bits hex)
|
21
|
+
size: tuple # (width, height)
|
22
|
+
format: str # JPEG, PNG, etc.
|
23
|
+
|
24
|
+
|
25
|
+
class AvatarHasher:
|
26
|
+
"""Cria hashes perceptuais de avatares para comparação."""
|
27
|
+
|
28
|
+
def __init__(self, timeout: float = 10.0):
|
29
|
+
self._timeout = timeout
|
30
|
+
|
31
|
+
async def hash_avatar(self, url: str) -> Optional[AvatarHash]:
|
32
|
+
"""
|
33
|
+
Baixa e cria hashes perceptuais de um avatar.
|
34
|
+
|
35
|
+
Hashes perceptuais permitem:
|
36
|
+
- Encontrar avatares similares mesmo com pequenas modificações
|
37
|
+
- Detectar mesma pessoa usando avatares levemente diferentes
|
38
|
+
- Comparar avatares em diferentes resoluções
|
39
|
+
"""
|
40
|
+
logger.info("avatar.hash.start", url=url)
|
41
|
+
|
42
|
+
try:
|
43
|
+
# Baixa imagem
|
44
|
+
async with httpx.AsyncClient(timeout=self._timeout) as client:
|
45
|
+
response = await client.get(url)
|
46
|
+
response.raise_for_status()
|
47
|
+
|
48
|
+
image_data = response.content
|
49
|
+
|
50
|
+
# Abre com PIL
|
51
|
+
image = Image.open(BytesIO(image_data))
|
52
|
+
|
53
|
+
# Redimensiona para processamento
|
54
|
+
image = image.convert("RGB")
|
55
|
+
|
56
|
+
# Calcula hashes
|
57
|
+
phash = self._perceptual_hash(image)
|
58
|
+
ahash = self._average_hash(image)
|
59
|
+
dhash = self._difference_hash(image)
|
60
|
+
|
61
|
+
logger.info("avatar.hash.complete", url=url, phash=phash[:16])
|
62
|
+
|
63
|
+
return AvatarHash(
|
64
|
+
url=url,
|
65
|
+
phash=phash,
|
66
|
+
ahash=ahash,
|
67
|
+
dhash=dhash,
|
68
|
+
size=image.size,
|
69
|
+
format=image.format or "Unknown",
|
70
|
+
)
|
71
|
+
|
72
|
+
except Exception as e:
|
73
|
+
logger.warning("avatar.hash.error", url=url, error=str(e))
|
74
|
+
return None
|
75
|
+
|
76
|
+
def _perceptual_hash(self, image: Image.Image, hash_size: int = 8) -> str:
|
77
|
+
"""
|
78
|
+
Calcula pHash (perceptual hash).
|
79
|
+
|
80
|
+
Algoritmo:
|
81
|
+
1. Redimensiona para hash_size x hash_size
|
82
|
+
2. Converte para grayscale
|
83
|
+
3. Calcula DCT (Discrete Cosine Transform)
|
84
|
+
4. Extrai top-left 8x8 excluindo DC
|
85
|
+
5. Compara com mediana
|
86
|
+
"""
|
87
|
+
# Redimensiona
|
88
|
+
image = image.resize((hash_size * 4, hash_size * 4), Image.LANCZOS)
|
89
|
+
image = image.convert("L") # Grayscale
|
90
|
+
|
91
|
+
# Simplificação: usa average hash como aproximação de pHash
|
92
|
+
# Em produção, implementar DCT real ou usar biblioteca imagehash
|
93
|
+
image = image.resize((hash_size, hash_size), Image.LANCZOS)
|
94
|
+
pixels = list(image.getdata())
|
95
|
+
|
96
|
+
avg = sum(pixels) / len(pixels)
|
97
|
+
|
98
|
+
# Cria hash binário
|
99
|
+
bits = "".join("1" if pixel > avg else "0" for pixel in pixels)
|
100
|
+
|
101
|
+
# Converte para hex
|
102
|
+
hash_hex = hex(int(bits, 2))[2:].zfill(16)
|
103
|
+
|
104
|
+
return hash_hex
|
105
|
+
|
106
|
+
def _average_hash(self, image: Image.Image, hash_size: int = 8) -> str:
|
107
|
+
"""
|
108
|
+
Calcula aHash (average hash).
|
109
|
+
|
110
|
+
Algoritmo:
|
111
|
+
1. Redimensiona para hash_size x hash_size
|
112
|
+
2. Converte para grayscale
|
113
|
+
3. Calcula média dos pixels
|
114
|
+
4. Cada pixel > média = 1, senão 0
|
115
|
+
"""
|
116
|
+
image = image.resize((hash_size, hash_size), Image.LANCZOS)
|
117
|
+
image = image.convert("L")
|
118
|
+
|
119
|
+
pixels = list(image.getdata())
|
120
|
+
avg = sum(pixels) / len(pixels)
|
121
|
+
|
122
|
+
bits = "".join("1" if pixel > avg else "0" for pixel in pixels)
|
123
|
+
hash_hex = hex(int(bits, 2))[2:].zfill(16)
|
124
|
+
|
125
|
+
return hash_hex
|
126
|
+
|
127
|
+
def _difference_hash(self, image: Image.Image, hash_size: int = 8) -> str:
|
128
|
+
"""
|
129
|
+
Calcula dHash (difference hash).
|
130
|
+
|
131
|
+
Algoritmo:
|
132
|
+
1. Redimensiona para (hash_size+1) x hash_size
|
133
|
+
2. Converte para grayscale
|
134
|
+
3. Compara cada pixel com o próximo
|
135
|
+
4. pixel[i] > pixel[i+1] = 1, senão 0
|
136
|
+
"""
|
137
|
+
image = image.resize((hash_size + 1, hash_size), Image.LANCZOS)
|
138
|
+
image = image.convert("L")
|
139
|
+
|
140
|
+
pixels = list(image.getdata())
|
141
|
+
|
142
|
+
bits = ""
|
143
|
+
for row in range(hash_size):
|
144
|
+
for col in range(hash_size):
|
145
|
+
index = row * (hash_size + 1) + col
|
146
|
+
left = pixels[index]
|
147
|
+
right = pixels[index + 1]
|
148
|
+
bits += "1" if left > right else "0"
|
149
|
+
|
150
|
+
hash_hex = hex(int(bits, 2))[2:].zfill(16)
|
151
|
+
|
152
|
+
return hash_hex
|
153
|
+
|
154
|
+
def compare_hashes(self, hash1: str, hash2: str) -> int:
|
155
|
+
"""
|
156
|
+
Compara dois hashes e retorna distância de Hamming.
|
157
|
+
|
158
|
+
Distância 0 = idênticos
|
159
|
+
Distância < 10 = muito similares
|
160
|
+
Distância < 20 = similares
|
161
|
+
Distância > 20 = diferentes
|
162
|
+
"""
|
163
|
+
if len(hash1) != len(hash2):
|
164
|
+
return 64 # Máxima distância
|
165
|
+
|
166
|
+
# Converte para binário
|
167
|
+
bin1 = bin(int(hash1, 16))[2:].zfill(64)
|
168
|
+
bin2 = bin(int(hash2, 16))[2:].zfill(64)
|
169
|
+
|
170
|
+
# Calcula distância de Hamming
|
171
|
+
distance = sum(b1 != b2 for b1, b2 in zip(bin1, bin2))
|
172
|
+
|
173
|
+
return distance
|
174
|
+
|
175
|
+
def is_similar(self, hash1: str, hash2: str, threshold: int = 10) -> bool:
|
176
|
+
"""Verifica se dois avatares são similares."""
|
177
|
+
distance = self.compare_hashes(hash1, hash2)
|
178
|
+
return distance <= threshold
|
179
|
+
|
180
|
+
|
181
|
+
__all__ = [
|
182
|
+
"AvatarHasher",
|
183
|
+
"AvatarHash",
|
184
|
+
]
|
@@ -0,0 +1,322 @@
|
|
1
|
+
"""Directory Fuzzer avançado para descoberta de diretórios e arquivos."""
|
2
|
+
import asyncio
|
3
|
+
from dataclasses import dataclass
|
4
|
+
from pathlib import Path
|
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 FuzzResult:
|
18
|
+
"""Resultado de fuzzing."""
|
19
|
+
url: str
|
20
|
+
status_code: int
|
21
|
+
size: int
|
22
|
+
redirect_url: Optional[str] = None
|
23
|
+
server: Optional[str] = None
|
24
|
+
content_type: Optional[str] = None
|
25
|
+
|
26
|
+
|
27
|
+
class DirectoryFuzzer:
|
28
|
+
"""
|
29
|
+
Directory/File fuzzer avançado.
|
30
|
+
|
31
|
+
Features:
|
32
|
+
- Wordlists (small, medium, large)
|
33
|
+
- Fuzzing de extensões
|
34
|
+
- Recursive fuzzing
|
35
|
+
- Status code filtering
|
36
|
+
- Rate limiting
|
37
|
+
- Stealth mode integration
|
38
|
+
- Smart filtering (tamanho, tipo)
|
39
|
+
"""
|
40
|
+
|
41
|
+
# Wordlists embutidas
|
42
|
+
SMALL_WORDLIST = [
|
43
|
+
'admin', 'administrator', 'login', 'wp-admin', 'dashboard', 'panel',
|
44
|
+
'api', 'v1', 'v2', 'test', 'dev', 'staging', 'backup', 'old',
|
45
|
+
'config', 'conf', 'settings', 'setup', 'install', 'debug',
|
46
|
+
'logs', 'log', 'tmp', 'temp', 'cache', 'uploads', 'upload',
|
47
|
+
'files', 'file', 'download', 'downloads', 'assets', 'static',
|
48
|
+
'images', 'img', 'css', 'js', 'scripts', 'includes', 'inc',
|
49
|
+
'vendor', 'node_modules', 'lib', 'libs', 'bin', 'src', 'source',
|
50
|
+
'public', 'private', 'secure', 'backup', 'backups', 'db', 'database',
|
51
|
+
'sql', 'data', 'users', 'user', 'accounts', 'account', 'profile',
|
52
|
+
'profiles', 'settings', 'preferences', 'config', 'configuration',
|
53
|
+
'admin', 'administrator', 'root', 'superuser', 'sudo', 'manager',
|
54
|
+
'staff', 'employee', 'member', 'members', 'reports', 'report',
|
55
|
+
'analytics', 'stats', 'statistics', 'monitor', 'monitoring',
|
56
|
+
'metrics', 'health', 'status', 'info', 'information', 'about',
|
57
|
+
'contact', 'support', 'help', 'docs', 'documentation', 'api-docs',
|
58
|
+
'swagger', 'graphql', 'rest', 'soap', 'xml-rpc', 'json-rpc'
|
59
|
+
]
|
60
|
+
|
61
|
+
COMMON_EXTENSIONS = [
|
62
|
+
'', '.html', '.php', '.asp', '.aspx', '.jsp', '.jspx',
|
63
|
+
'.txt', '.xml', '.json', '.yml', '.yaml', '.conf', '.config',
|
64
|
+
'.bak', '.backup', '.old', '.orig', '.tmp', '.temp', '.swp',
|
65
|
+
'.log', '.sql', '.db', '.sqlite', '.mdb',
|
66
|
+
'.zip', '.tar', '.gz', '.rar', '.7z',
|
67
|
+
'.env', '.git', '.svn', '.hg', '.DS_Store',
|
68
|
+
]
|
69
|
+
|
70
|
+
INTERESTING_STATUS = [200, 201, 202, 204, 301, 302, 307, 308, 401, 403, 405, 500]
|
71
|
+
|
72
|
+
def __init__(
|
73
|
+
self,
|
74
|
+
base_url: str,
|
75
|
+
wordlist: Optional[List[str]] = None,
|
76
|
+
wordlist_file: Optional[str] = None,
|
77
|
+
extensions: Optional[List[str]] = None,
|
78
|
+
recursive: bool = False,
|
79
|
+
max_depth: int = 2,
|
80
|
+
threads: int = 50,
|
81
|
+
timeout: float = 5.0,
|
82
|
+
status_filter: Optional[List[int]] = None,
|
83
|
+
size_filter: Optional[int] = None,
|
84
|
+
stealth_level: int = 0,
|
85
|
+
):
|
86
|
+
self.base_url = base_url.rstrip('/')
|
87
|
+
self.wordlist = wordlist or self._load_wordlist(wordlist_file)
|
88
|
+
self.extensions = extensions or self.COMMON_EXTENSIONS
|
89
|
+
self.recursive = recursive
|
90
|
+
self.max_depth = max_depth
|
91
|
+
self.threads = threads
|
92
|
+
self.timeout = timeout
|
93
|
+
self.status_filter = status_filter or self.INTERESTING_STATUS
|
94
|
+
self.size_filter = size_filter
|
95
|
+
self.stealth_level = stealth_level
|
96
|
+
|
97
|
+
self.results: List[FuzzResult] = []
|
98
|
+
self.found_dirs: Set[str] = set()
|
99
|
+
self.baseline_sizes: dict = {}
|
100
|
+
|
101
|
+
def _load_wordlist(self, wordlist_file: Optional[str]) -> List[str]:
|
102
|
+
"""Carrega wordlist de arquivo ou usa embutida."""
|
103
|
+
if wordlist_file and Path(wordlist_file).exists():
|
104
|
+
with open(wordlist_file, 'r') as f:
|
105
|
+
return [line.strip() for line in f if line.strip()]
|
106
|
+
|
107
|
+
# Usa wordlist pequena embutida
|
108
|
+
return self.SMALL_WORDLIST
|
109
|
+
|
110
|
+
async def fuzz(self) -> List[FuzzResult]:
|
111
|
+
"""Executa fuzzing."""
|
112
|
+
logger.info("fuzzer.start", url=self.base_url, words=len(self.wordlist))
|
113
|
+
|
114
|
+
# Calibração inicial (baseline)
|
115
|
+
await self._calibrate()
|
116
|
+
|
117
|
+
# Fuzz inicial
|
118
|
+
await self._fuzz_directory(self.base_url, depth=0)
|
119
|
+
|
120
|
+
logger.info("fuzzer.complete", results=len(self.results))
|
121
|
+
return self.results
|
122
|
+
|
123
|
+
async def _calibrate(self):
|
124
|
+
"""Calibra fuzzer com requests de baseline."""
|
125
|
+
console.print("[dim]Calibrating fuzzer...[/dim]")
|
126
|
+
|
127
|
+
baseline_paths = [
|
128
|
+
f"/{self._generate_random_string(10)}",
|
129
|
+
f"/{self._generate_random_string(15)}.{self._generate_random_string(3)}",
|
130
|
+
]
|
131
|
+
|
132
|
+
async with httpx.AsyncClient(timeout=self.timeout, follow_redirects=True) as client:
|
133
|
+
for path in baseline_paths:
|
134
|
+
try:
|
135
|
+
response = await client.get(f"{self.base_url}{path}")
|
136
|
+
self.baseline_sizes[response.status_code] = len(response.content)
|
137
|
+
except:
|
138
|
+
pass
|
139
|
+
|
140
|
+
logger.debug("fuzzer.calibrated", baseline_sizes=self.baseline_sizes)
|
141
|
+
|
142
|
+
async def _fuzz_directory(self, base_url: str, depth: int):
|
143
|
+
"""Fuzz um diretório."""
|
144
|
+
if depth > self.max_depth:
|
145
|
+
return
|
146
|
+
|
147
|
+
# Cria lista de URLs para testar
|
148
|
+
urls_to_test = []
|
149
|
+
for word in self.wordlist:
|
150
|
+
for ext in self.extensions:
|
151
|
+
url = f"{base_url}/{word}{ext}"
|
152
|
+
urls_to_test.append(url)
|
153
|
+
|
154
|
+
# Semaphore para controlar concorrência
|
155
|
+
semaphore = asyncio.Semaphore(self.threads)
|
156
|
+
|
157
|
+
async with httpx.AsyncClient(
|
158
|
+
timeout=self.timeout,
|
159
|
+
follow_redirects=False,
|
160
|
+
verify=False
|
161
|
+
) as client:
|
162
|
+
|
163
|
+
with Progress() as progress:
|
164
|
+
task_id = progress.add_task(
|
165
|
+
f"[cyan]Fuzzing {base_url.split('/')[-1] or 'root'}...",
|
166
|
+
total=len(urls_to_test)
|
167
|
+
)
|
168
|
+
|
169
|
+
tasks = [
|
170
|
+
self._test_url(client, semaphore, url, progress, task_id)
|
171
|
+
for url in urls_to_test
|
172
|
+
]
|
173
|
+
|
174
|
+
await asyncio.gather(*tasks, return_exceptions=True)
|
175
|
+
|
176
|
+
# Recursive fuzzing em diretórios encontrados
|
177
|
+
if self.recursive and depth < self.max_depth:
|
178
|
+
for dir_url in list(self.found_dirs):
|
179
|
+
if dir_url.startswith(base_url):
|
180
|
+
await self._fuzz_directory(dir_url, depth + 1)
|
181
|
+
|
182
|
+
async def _test_url(
|
183
|
+
self,
|
184
|
+
client: httpx.AsyncClient,
|
185
|
+
semaphore: asyncio.Semaphore,
|
186
|
+
url: str,
|
187
|
+
progress: Progress,
|
188
|
+
task_id: int
|
189
|
+
):
|
190
|
+
"""Testa uma URL."""
|
191
|
+
async with semaphore:
|
192
|
+
try:
|
193
|
+
# Stealth delay
|
194
|
+
if self.stealth_level > 0:
|
195
|
+
await asyncio.sleep(self.stealth_level * 0.1)
|
196
|
+
|
197
|
+
headers = self._get_headers()
|
198
|
+
response = await client.get(url, headers=headers)
|
199
|
+
|
200
|
+
progress.update(task_id, advance=1)
|
201
|
+
|
202
|
+
# Filtra por status code
|
203
|
+
if response.status_code not in self.status_filter:
|
204
|
+
return
|
205
|
+
|
206
|
+
# Filtra por tamanho (baseline)
|
207
|
+
content_size = len(response.content)
|
208
|
+
if self._is_baseline_size(response.status_code, content_size):
|
209
|
+
return
|
210
|
+
|
211
|
+
# Filtra por tamanho customizado
|
212
|
+
if self.size_filter and content_size > self.size_filter:
|
213
|
+
return
|
214
|
+
|
215
|
+
# Cria resultado
|
216
|
+
result = FuzzResult(
|
217
|
+
url=url,
|
218
|
+
status_code=response.status_code,
|
219
|
+
size=content_size,
|
220
|
+
redirect_url=response.headers.get('location'),
|
221
|
+
server=response.headers.get('server'),
|
222
|
+
content_type=response.headers.get('content-type'),
|
223
|
+
)
|
224
|
+
|
225
|
+
self.results.append(result)
|
226
|
+
|
227
|
+
# Se é diretório, adiciona para recursive fuzzing
|
228
|
+
if response.status_code in [301, 302, 307, 308]:
|
229
|
+
if result.redirect_url and result.redirect_url.endswith('/'):
|
230
|
+
self.found_dirs.add(result.redirect_url.rstrip('/'))
|
231
|
+
elif url.endswith('/'):
|
232
|
+
self.found_dirs.add(url.rstrip('/'))
|
233
|
+
|
234
|
+
# Log descoberta
|
235
|
+
color = self._get_status_color(response.status_code)
|
236
|
+
console.print(
|
237
|
+
f" [{color}]{response.status_code}[/{color}] "
|
238
|
+
f"[cyan]{url.replace(self.base_url, '')}[/cyan] "
|
239
|
+
f"[dim]({content_size} bytes)[/dim]"
|
240
|
+
)
|
241
|
+
|
242
|
+
logger.info(
|
243
|
+
"fuzzer.found",
|
244
|
+
url=url,
|
245
|
+
status=response.status_code,
|
246
|
+
size=content_size
|
247
|
+
)
|
248
|
+
|
249
|
+
except httpx.TimeoutException:
|
250
|
+
pass
|
251
|
+
except Exception as e:
|
252
|
+
logger.debug("fuzzer.error", url=url, error=str(e))
|
253
|
+
|
254
|
+
def _is_baseline_size(self, status_code: int, size: int) -> bool:
|
255
|
+
"""Verifica se tamanho é baseline (falso positivo)."""
|
256
|
+
baseline = self.baseline_sizes.get(status_code)
|
257
|
+
if baseline is None:
|
258
|
+
return False
|
259
|
+
|
260
|
+
# Permite variação de 5%
|
261
|
+
tolerance = baseline * 0.05
|
262
|
+
return abs(size - baseline) <= tolerance
|
263
|
+
|
264
|
+
def _get_headers(self) -> dict:
|
265
|
+
"""Retorna headers com stealth."""
|
266
|
+
headers = {
|
267
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
268
|
+
'Accept': '*/*',
|
269
|
+
}
|
270
|
+
|
271
|
+
if self.stealth_level > 1:
|
272
|
+
headers.update({
|
273
|
+
'Accept-Language': 'en-US,en;q=0.9',
|
274
|
+
'Accept-Encoding': 'gzip, deflate',
|
275
|
+
'DNT': '1',
|
276
|
+
'Connection': 'keep-alive',
|
277
|
+
})
|
278
|
+
|
279
|
+
return headers
|
280
|
+
|
281
|
+
def _get_status_color(self, status_code: int) -> str:
|
282
|
+
"""Retorna cor baseada no status code."""
|
283
|
+
if status_code < 300:
|
284
|
+
return "green"
|
285
|
+
elif status_code < 400:
|
286
|
+
return "yellow"
|
287
|
+
elif status_code == 401 or status_code == 403:
|
288
|
+
return "red"
|
289
|
+
elif status_code < 500:
|
290
|
+
return "blue"
|
291
|
+
else:
|
292
|
+
return "magenta"
|
293
|
+
|
294
|
+
def _generate_random_string(self, length: int) -> str:
|
295
|
+
"""Gera string aleatória."""
|
296
|
+
import random
|
297
|
+
import string
|
298
|
+
return ''.join(random.choices(string.ascii_lowercase + string.digits, k=length))
|
299
|
+
|
300
|
+
def export(self, output: str):
|
301
|
+
"""Exporta resultados."""
|
302
|
+
import json
|
303
|
+
|
304
|
+
data = [
|
305
|
+
{
|
306
|
+
'url': r.url,
|
307
|
+
'status_code': r.status_code,
|
308
|
+
'size': r.size,
|
309
|
+
'redirect_url': r.redirect_url,
|
310
|
+
'server': r.server,
|
311
|
+
'content_type': r.content_type,
|
312
|
+
}
|
313
|
+
for r in self.results
|
314
|
+
]
|
315
|
+
|
316
|
+
with open(output, 'w') as f:
|
317
|
+
json.dump(data, f, indent=2)
|
318
|
+
|
319
|
+
logger.info("fuzzer.export", file=output, count=len(self.results))
|
320
|
+
|
321
|
+
|
322
|
+
__all__ = ["DirectoryFuzzer", "FuzzResult"]
|
@@ -0,0 +1,40 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from dataclasses import dataclass
|
4
|
+
|
5
|
+
import structlog
|
6
|
+
|
7
|
+
from .orchestrator import Orchestrator, TaskContext
|
8
|
+
from ..net.dns_client import DNSClient, DNSLookupResult
|
9
|
+
|
10
|
+
logger = structlog.get_logger(__name__)
|
11
|
+
|
12
|
+
|
13
|
+
@dataclass(slots=True)
|
14
|
+
class DNSScanResult:
|
15
|
+
domain: str
|
16
|
+
records: DNSLookupResult
|
17
|
+
|
18
|
+
|
19
|
+
class DNSScanService:
|
20
|
+
def __init__(
|
21
|
+
self,
|
22
|
+
domain: str,
|
23
|
+
orchestrator: Orchestrator[DNSLookupResult],
|
24
|
+
dns_client: DNSClient,
|
25
|
+
) -> None:
|
26
|
+
self._domain = domain
|
27
|
+
self._orchestrator = orchestrator
|
28
|
+
self._dns_client = dns_client
|
29
|
+
|
30
|
+
async def run(self) -> DNSScanResult:
|
31
|
+
logger.info("dns.scan.start", domain=self._domain)
|
32
|
+
records = await self._orchestrator.run(
|
33
|
+
TaskContext(name="dns_lookup", metadata={"domain": self._domain}),
|
34
|
+
lambda: self._dns_client.lookup_domain(self._domain),
|
35
|
+
)
|
36
|
+
logger.info("dns.scan.success", domain=self._domain)
|
37
|
+
return DNSScanResult(domain=self._domain, records=records)
|
38
|
+
|
39
|
+
|
40
|
+
__all__ = ["DNSScanResult", "DNSScanService"]
|