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.
Files changed (416) hide show
  1. moriarty/__init__.py +5 -0
  2. moriarty/adapters/__init__.py +0 -0
  3. moriarty/agent/__init__.py +0 -0
  4. moriarty/assets/modules/.gitkeep +0 -0
  5. moriarty/assets/modules/asia/douban.yaml +19 -0
  6. moriarty/assets/modules/asia/kakao.yaml +19 -0
  7. moriarty/assets/modules/asia/line.yaml +19 -0
  8. moriarty/assets/modules/asia/mixi.yaml +19 -0
  9. moriarty/assets/modules/asia/naver.yaml +19 -0
  10. moriarty/assets/modules/asia/qq.yaml +19 -0
  11. moriarty/assets/modules/asia/vk.yaml +19 -0
  12. moriarty/assets/modules/asia/wechat.yaml +19 -0
  13. moriarty/assets/modules/asia/weibo.yaml +19 -0
  14. moriarty/assets/modules/asia/xiaohongshu.yaml +19 -0
  15. moriarty/assets/modules/behance.yaml +47 -0
  16. moriarty/assets/modules/business/crunchbase.yaml +27 -0
  17. moriarty/assets/modules/business/fiverr.yaml +32 -0
  18. moriarty/assets/modules/business/freelancer.yaml +27 -0
  19. moriarty/assets/modules/business/glassdoor.yaml +27 -0
  20. moriarty/assets/modules/business/guru.yaml +26 -0
  21. moriarty/assets/modules/business/indeed.yaml +25 -0
  22. moriarty/assets/modules/business/monster.yaml +25 -0
  23. moriarty/assets/modules/business/peopleperhour.yaml +26 -0
  24. moriarty/assets/modules/business/toptal.yaml +28 -0
  25. moriarty/assets/modules/business/upwork.yaml +27 -0
  26. moriarty/assets/modules/business/ziprecruiter.yaml +25 -0
  27. moriarty/assets/modules/content/buymeacoffee.yaml +27 -0
  28. moriarty/assets/modules/content/gumroad.yaml +27 -0
  29. moriarty/assets/modules/content/ko-fi.yaml +32 -0
  30. moriarty/assets/modules/content/onlyfans.yaml +27 -0
  31. moriarty/assets/modules/content/patreon.yaml +33 -0
  32. moriarty/assets/modules/content/substack.yaml +32 -0
  33. moriarty/assets/modules/creative/500px.yaml +31 -0
  34. moriarty/assets/modules/creative/artstation.yaml +33 -0
  35. moriarty/assets/modules/creative/deviantart.yaml +32 -0
  36. moriarty/assets/modules/creative/flickr.yaml +31 -0
  37. moriarty/assets/modules/creative/pexels.yaml +26 -0
  38. moriarty/assets/modules/creative/unsplash.yaml +26 -0
  39. moriarty/assets/modules/creative/vimeo.yaml +31 -0
  40. moriarty/assets/modules/crypto/binance.yaml +27 -0
  41. moriarty/assets/modules/crypto/bitcointalk.yaml +33 -0
  42. moriarty/assets/modules/crypto/coinbase.yaml +26 -0
  43. moriarty/assets/modules/crypto/etherscan.yaml +32 -0
  44. moriarty/assets/modules/crypto/foundation.yaml +28 -0
  45. moriarty/assets/modules/crypto/kraken.yaml +27 -0
  46. moriarty/assets/modules/crypto/mirror.yaml +27 -0
  47. moriarty/assets/modules/crypto/niftygateway.yaml +26 -0
  48. moriarty/assets/modules/crypto/opensea.yaml +32 -0
  49. moriarty/assets/modules/crypto/rarible.yaml +27 -0
  50. moriarty/assets/modules/crypto/superrare.yaml +29 -0
  51. moriarty/assets/modules/dating/bumble.yaml +25 -0
  52. moriarty/assets/modules/dating/grindr.yaml +27 -0
  53. moriarty/assets/modules/dating/happn.yaml +25 -0
  54. moriarty/assets/modules/dating/her.yaml +27 -0
  55. moriarty/assets/modules/dating/hinge.yaml +25 -0
  56. moriarty/assets/modules/dating/match.yaml +25 -0
  57. moriarty/assets/modules/dating/meetme.yaml +27 -0
  58. moriarty/assets/modules/dating/okcupid.yaml +25 -0
  59. moriarty/assets/modules/dating/pof.yaml +25 -0
  60. moriarty/assets/modules/dating/tinder.yaml +25 -0
  61. moriarty/assets/modules/dating-nsfw/adultfriendfinder.yaml +28 -0
  62. moriarty/assets/modules/dating-nsfw/ashley-madison.yaml +26 -0
  63. moriarty/assets/modules/design/adobe-portfolio.yaml +27 -0
  64. moriarty/assets/modules/design/carbonmade.yaml +27 -0
  65. moriarty/assets/modules/design/cgsociety.yaml +27 -0
  66. moriarty/assets/modules/design/coroflot.yaml +27 -0
  67. moriarty/assets/modules/design/figma.yaml +27 -0
  68. moriarty/assets/modules/design/sketch.yaml +26 -0
  69. moriarty/assets/modules/dev/bitbucket.yaml +35 -0
  70. moriarty/assets/modules/dev/codeforces.yaml +32 -0
  71. moriarty/assets/modules/dev/codepen.yaml +34 -0
  72. moriarty/assets/modules/dev/hackerone.yaml +32 -0
  73. moriarty/assets/modules/dev/hackthebox.yaml +27 -0
  74. moriarty/assets/modules/dev/huggingface.yaml +27 -0
  75. moriarty/assets/modules/dev/kaggle.yaml +32 -0
  76. moriarty/assets/modules/dev/leetcode.yaml +32 -0
  77. moriarty/assets/modules/dev/replit.yaml +31 -0
  78. moriarty/assets/modules/dribbble.yaml +53 -0
  79. moriarty/assets/modules/ecommerce/etsy.yaml +32 -0
  80. moriarty/assets/modules/education/duolingo.yaml +32 -0
  81. moriarty/assets/modules/education/edx.yaml +26 -0
  82. moriarty/assets/modules/education/khanacademy.yaml +26 -0
  83. moriarty/assets/modules/education/lynda.yaml +27 -0
  84. moriarty/assets/modules/education/memrise.yaml +27 -0
  85. moriarty/assets/modules/education/pluralsight.yaml +27 -0
  86. moriarty/assets/modules/education/skillshare.yaml +27 -0
  87. moriarty/assets/modules/education/udacity.yaml +27 -0
  88. moriarty/assets/modules/email/github_email.yaml +40 -0
  89. moriarty/assets/modules/email/gravatar.yaml +23 -0
  90. moriarty/assets/modules/europe/badoo.yaml +19 -0
  91. moriarty/assets/modules/europe/lovoo.yaml +19 -0
  92. moriarty/assets/modules/europe/myspace.yaml +19 -0
  93. moriarty/assets/modules/europe/netlog.yaml +19 -0
  94. moriarty/assets/modules/europe/ok.yaml +19 -0
  95. moriarty/assets/modules/europe/skyrock.yaml +19 -0
  96. moriarty/assets/modules/europe/studivz.yaml +19 -0
  97. moriarty/assets/modules/europe/tuenti.yaml +19 -0
  98. moriarty/assets/modules/europe/viadeo.yaml +19 -0
  99. moriarty/assets/modules/europe/xing.yaml +19 -0
  100. moriarty/assets/modules/fitness/fitbit.yaml +27 -0
  101. moriarty/assets/modules/fitness/garmin.yaml +27 -0
  102. moriarty/assets/modules/fitness/myfitnesspal.yaml +27 -0
  103. moriarty/assets/modules/fitness/strava.yaml +33 -0
  104. moriarty/assets/modules/fitness/zwift.yaml +28 -0
  105. moriarty/assets/modules/food/allrecipes.yaml +27 -0
  106. moriarty/assets/modules/food/tasty.yaml +27 -0
  107. moriarty/assets/modules/food/yelp.yaml +32 -0
  108. moriarty/assets/modules/food/zomato.yaml +28 -0
  109. moriarty/assets/modules/forums/4chan.yaml +26 -0
  110. moriarty/assets/modules/forums/8kun.yaml +26 -0
  111. moriarty/assets/modules/forums/9gag.yaml +26 -0
  112. moriarty/assets/modules/forums/discourse.yaml +26 -0
  113. moriarty/assets/modules/forums/disqus.yaml +31 -0
  114. moriarty/assets/modules/forums/hackernews.yaml +32 -0
  115. moriarty/assets/modules/forums/launchpad.yaml +27 -0
  116. moriarty/assets/modules/forums/phpbb.yaml +25 -0
  117. moriarty/assets/modules/forums/quora.yaml +32 -0
  118. moriarty/assets/modules/forums/serverfault.yaml +27 -0
  119. moriarty/assets/modules/forums/slashdot.yaml +28 -0
  120. moriarty/assets/modules/forums/stackexchange.yaml +32 -0
  121. moriarty/assets/modules/forums/superuser.yaml +27 -0
  122. moriarty/assets/modules/forums/vbulletin.yaml +25 -0
  123. moriarty/assets/modules/forums/xenforo.yaml +25 -0
  124. moriarty/assets/modules/forums-nsfw/kiwifarms.yaml +25 -0
  125. moriarty/assets/modules/forums-nsfw/lolcow.yaml +26 -0
  126. moriarty/assets/modules/gaming/apextracker.yaml +27 -0
  127. moriarty/assets/modules/gaming/battlenet.yaml +26 -0
  128. moriarty/assets/modules/gaming/chess.yaml +30 -0
  129. moriarty/assets/modules/gaming/discord-public.yaml +27 -0
  130. moriarty/assets/modules/gaming/dotabuff.yaml +32 -0
  131. moriarty/assets/modules/gaming/epicgames.yaml +25 -0
  132. moriarty/assets/modules/gaming/faceit.yaml +33 -0
  133. moriarty/assets/modules/gaming/fortnitetracker.yaml +32 -0
  134. moriarty/assets/modules/gaming/gog.yaml +26 -0
  135. moriarty/assets/modules/gaming/itch.yaml +32 -0
  136. moriarty/assets/modules/gaming/kongregate.yaml +25 -0
  137. moriarty/assets/modules/gaming/minecraft.yaml +31 -0
  138. moriarty/assets/modules/gaming/opgg.yaml +32 -0
  139. moriarty/assets/modules/gaming/origin.yaml +26 -0
  140. moriarty/assets/modules/gaming/playstation.yaml +30 -0
  141. moriarty/assets/modules/gaming/roblox.yaml +31 -0
  142. moriarty/assets/modules/gaming/xbox.yaml +25 -0
  143. moriarty/assets/modules/github.yaml +68 -0
  144. moriarty/assets/modules/gitlab.yaml +60 -0
  145. moriarty/assets/modules/instagram.yaml +48 -0
  146. moriarty/assets/modules/latam/fotolog.yaml +27 -0
  147. moriarty/assets/modules/latam/orkut.yaml +26 -0
  148. moriarty/assets/modules/latam/taringa.yaml +27 -0
  149. moriarty/assets/modules/learning/coursera.yaml +26 -0
  150. moriarty/assets/modules/learning/udemy.yaml +26 -0
  151. moriarty/assets/modules/linkedin.yaml +40 -0
  152. moriarty/assets/modules/marketplaces/depop.yaml +28 -0
  153. moriarty/assets/modules/marketplaces/ebay.yaml +32 -0
  154. moriarty/assets/modules/marketplaces/grailed.yaml +27 -0
  155. moriarty/assets/modules/marketplaces/mercari.yaml +26 -0
  156. moriarty/assets/modules/marketplaces/poshmark.yaml +27 -0
  157. moriarty/assets/modules/marketplaces/reverb.yaml +27 -0
  158. moriarty/assets/modules/marketplaces/vinted.yaml +28 -0
  159. moriarty/assets/modules/medium.yaml +44 -0
  160. moriarty/assets/modules/music/audiomack.yaml +26 -0
  161. moriarty/assets/modules/music/bandcamp.yaml +30 -0
  162. moriarty/assets/modules/music/beatport.yaml +28 -0
  163. moriarty/assets/modules/music/deezer.yaml +26 -0
  164. moriarty/assets/modules/music/discogs.yaml +32 -0
  165. moriarty/assets/modules/music/genius.yaml +26 -0
  166. moriarty/assets/modules/music/lastfm.yaml +30 -0
  167. moriarty/assets/modules/music/mixcloud.yaml +26 -0
  168. moriarty/assets/modules/music/reverbnation.yaml +31 -0
  169. moriarty/assets/modules/music/soundcloud.yaml +31 -0
  170. moriarty/assets/modules/music/spotify.yaml +26 -0
  171. moriarty/assets/modules/music/tidal.yaml +26 -0
  172. moriarty/assets/modules/nsfw/adultwork.yaml +27 -0
  173. moriarty/assets/modules/nsfw/bongacams.yaml +28 -0
  174. moriarty/assets/modules/nsfw/cam4.yaml +28 -0
  175. moriarty/assets/modules/nsfw/chaturbate.yaml +28 -0
  176. moriarty/assets/modules/nsfw/clips4sale.yaml +27 -0
  177. moriarty/assets/modules/nsfw/extralunchmoney.yaml +27 -0
  178. moriarty/assets/modules/nsfw/fansly.yaml +28 -0
  179. moriarty/assets/modules/nsfw/fetlife.yaml +28 -0
  180. moriarty/assets/modules/nsfw/iwantclips.yaml +27 -0
  181. moriarty/assets/modules/nsfw/justforfans.yaml +28 -0
  182. moriarty/assets/modules/nsfw/loyalfans.yaml +28 -0
  183. moriarty/assets/modules/nsfw/manyvids.yaml +27 -0
  184. moriarty/assets/modules/nsfw/myfreecams.yaml +28 -0
  185. moriarty/assets/modules/nsfw/niteflirt.yaml +26 -0
  186. moriarty/assets/modules/nsfw/pornhub.yaml +32 -0
  187. moriarty/assets/modules/nsfw/redtube.yaml +27 -0
  188. moriarty/assets/modules/nsfw/stripchat.yaml +28 -0
  189. moriarty/assets/modules/nsfw/xhamster.yaml +27 -0
  190. moriarty/assets/modules/nsfw/xvideos.yaml +27 -0
  191. moriarty/assets/modules/nsfw/youporn.yaml +27 -0
  192. moriarty/assets/modules/photography/eyeem.yaml +25 -0
  193. moriarty/assets/modules/photography/fotki.yaml +25 -0
  194. moriarty/assets/modules/photography/photobucket.yaml +26 -0
  195. moriarty/assets/modules/photography/smugmug.yaml +25 -0
  196. moriarty/assets/modules/photography/vsco.yaml +27 -0
  197. moriarty/assets/modules/pinterest.yaml +40 -0
  198. moriarty/assets/modules/podcasts/anchor.yaml +26 -0
  199. moriarty/assets/modules/podcasts/castbox.yaml +26 -0
  200. moriarty/assets/modules/podcasts/podbean.yaml +26 -0
  201. moriarty/assets/modules/professional/about.yaml +31 -0
  202. moriarty/assets/modules/professional/academia.yaml +27 -0
  203. moriarty/assets/modules/professional/angellist.yaml +27 -0
  204. moriarty/assets/modules/professional/calendly.yaml +26 -0
  205. moriarty/assets/modules/professional/issuu.yaml +27 -0
  206. moriarty/assets/modules/professional/mendeley.yaml +27 -0
  207. moriarty/assets/modules/professional/notion.yaml +27 -0
  208. moriarty/assets/modules/professional/orcid.yaml +27 -0
  209. moriarty/assets/modules/professional/producthunt.yaml +31 -0
  210. moriarty/assets/modules/professional/researchgate.yaml +32 -0
  211. moriarty/assets/modules/professional/scribd.yaml +27 -0
  212. moriarty/assets/modules/professional/slideshare.yaml +31 -0
  213. moriarty/assets/modules/professional/trello.yaml +26 -0
  214. moriarty/assets/modules/professional/typeform.yaml +27 -0
  215. moriarty/assets/modules/reddit.yaml +46 -0
  216. moriarty/assets/modules/regional/amino.yaml +27 -0
  217. moriarty/assets/modules/regional/ask-fm.yaml +32 -0
  218. moriarty/assets/modules/regional/babycenter.yaml +26 -0
  219. moriarty/assets/modules/regional/cafemom.yaml +27 -0
  220. moriarty/assets/modules/regional/care2.yaml +27 -0
  221. moriarty/assets/modules/regional/diaspora.yaml +26 -0
  222. moriarty/assets/modules/regional/ello.yaml +27 -0
  223. moriarty/assets/modules/regional/gaia.yaml +27 -0
  224. moriarty/assets/modules/regional/habbo.yaml +27 -0
  225. moriarty/assets/modules/regional/imvu.yaml +27 -0
  226. moriarty/assets/modules/regional/lemmy.yaml +27 -0
  227. moriarty/assets/modules/regional/peertube.yaml +26 -0
  228. moriarty/assets/modules/regional/pixelfed.yaml +27 -0
  229. moriarty/assets/modules/regional/plurk.yaml +26 -0
  230. moriarty/assets/modules/regional/recroom.yaml +27 -0
  231. moriarty/assets/modules/regional/secondlife.yaml +26 -0
  232. moriarty/assets/modules/regional/vine-archive.yaml +27 -0
  233. moriarty/assets/modules/regional/vrchat.yaml +27 -0
  234. moriarty/assets/modules/regional/weheartit.yaml +27 -0
  235. moriarty/assets/modules/social/anilist.yaml +27 -0
  236. moriarty/assets/modules/social/beacons.yaml +26 -0
  237. moriarty/assets/modules/social/blogger.yaml +27 -0
  238. moriarty/assets/modules/social/crunchyroll.yaml +27 -0
  239. moriarty/assets/modules/social/discord.yaml +27 -0
  240. moriarty/assets/modules/social/dreamwidth.yaml +26 -0
  241. moriarty/assets/modules/social/facebook.yaml +34 -0
  242. moriarty/assets/modules/social/goodreads.yaml +32 -0
  243. moriarty/assets/modules/social/imdb.yaml +27 -0
  244. moriarty/assets/modules/social/kitsu.yaml +27 -0
  245. moriarty/assets/modules/social/letterboxd.yaml +32 -0
  246. moriarty/assets/modules/social/linktree.yaml +26 -0
  247. moriarty/assets/modules/social/livejournal.yaml +27 -0
  248. moriarty/assets/modules/social/mastodon.yaml +30 -0
  249. moriarty/assets/modules/social/minds.yaml +25 -0
  250. moriarty/assets/modules/social/myanimelist.yaml +32 -0
  251. moriarty/assets/modules/social/ravelry.yaml +27 -0
  252. moriarty/assets/modules/social/snapchat.yaml +25 -0
  253. moriarty/assets/modules/social/telegram.yaml +35 -0
  254. moriarty/assets/modules/social/tiktok.yaml +35 -0
  255. moriarty/assets/modules/social/trakt.yaml +28 -0
  256. moriarty/assets/modules/social/wattpad.yaml +32 -0
  257. moriarty/assets/modules/social/wordpress-com.yaml +26 -0
  258. moriarty/assets/modules/sports/espn.yaml +26 -0
  259. moriarty/assets/modules/sports/untappd.yaml +32 -0
  260. moriarty/assets/modules/stackoverflow.yaml +47 -0
  261. moriarty/assets/modules/steam.yaml +47 -0
  262. moriarty/assets/modules/streaming/caffeine.yaml +25 -0
  263. moriarty/assets/modules/streaming/dlive.yaml +27 -0
  264. moriarty/assets/modules/streaming/trovo.yaml +25 -0
  265. moriarty/assets/modules/travel/airbnb.yaml +26 -0
  266. moriarty/assets/modules/travel/booking.yaml +26 -0
  267. moriarty/assets/modules/travel/couchsurfing.yaml +27 -0
  268. moriarty/assets/modules/travel/tripadvisor.yaml +32 -0
  269. moriarty/assets/modules/tumblr.yaml +40 -0
  270. moriarty/assets/modules/twitch.yaml +48 -0
  271. moriarty/assets/modules/twitter.yaml +39 -0
  272. moriarty/assets/modules/youtube.yaml +42 -0
  273. moriarty/assets/templates/cves/CVE-2017-5638.yaml +27 -0
  274. moriarty/assets/templates/cves/CVE-2018-7600.yaml +30 -0
  275. moriarty/assets/templates/cves/CVE-2019-11510.yaml +27 -0
  276. moriarty/assets/templates/cves/CVE-2019-19781.yaml +28 -0
  277. moriarty/assets/templates/cves/CVE-2020-14882.yaml +28 -0
  278. moriarty/assets/templates/cves/CVE-2020-14883.yaml +29 -0
  279. moriarty/assets/templates/cves/CVE-2020-3452.yaml +28 -0
  280. moriarty/assets/templates/cves/CVE-2020-5902.yaml +28 -0
  281. moriarty/assets/templates/cves/CVE-2021-21972.yaml +31 -0
  282. moriarty/assets/templates/cves/CVE-2021-21985.yaml +28 -0
  283. moriarty/assets/templates/cves/CVE-2021-26084.yaml +30 -0
  284. moriarty/assets/templates/cves/CVE-2021-41773.yaml +25 -0
  285. moriarty/assets/templates/cves/CVE-2021-42013.yaml +28 -0
  286. moriarty/assets/templates/cves/CVE-2021-44228.yaml +27 -0
  287. moriarty/assets/templates/cves/CVE-2022-0185.yaml +21 -0
  288. moriarty/assets/templates/cves/CVE-2022-1388.yaml +36 -0
  289. moriarty/assets/templates/cves/CVE-2022-22954.yaml +28 -0
  290. moriarty/assets/templates/cves/CVE-2022-22965.yaml +31 -0
  291. moriarty/assets/templates/cves/CVE-2022-26134.yaml +27 -0
  292. moriarty/assets/templates/cves/CVE-2023-22515.yaml +27 -0
  293. moriarty/assets/templates/cves/CVE-2023-22527.yaml +29 -0
  294. moriarty/assets/templates/cves/CVE-2023-23752.yaml +33 -0
  295. moriarty/assets/templates/cves/CVE-2023-27350.yaml +27 -0
  296. moriarty/assets/templates/cves/CVE-2023-2868.yaml +27 -0
  297. moriarty/assets/templates/cves/CVE-2023-34362.yaml +27 -0
  298. moriarty/assets/templates/cves/CVE-2023-3519.yaml +28 -0
  299. moriarty/assets/templates/cves/CVE-2023-4966.yaml +27 -0
  300. moriarty/assets/templates/default-logins/admin-weak.yaml +40 -0
  301. moriarty/assets/templates/default-logins/wordpress-default.yaml +38 -0
  302. moriarty/assets/templates/exposures/aws-credentials.yaml +35 -0
  303. moriarty/assets/templates/exposures/backup-files.yaml +36 -0
  304. moriarty/assets/templates/exposures/database-files.yaml +34 -0
  305. moriarty/assets/templates/exposures/docker-exposed.yaml +31 -0
  306. moriarty/assets/templates/exposures/env-exposed.yaml +41 -0
  307. moriarty/assets/templates/exposures/git-exposed.yaml +41 -0
  308. moriarty/assets/templates/exposures/phpinfo.yaml +36 -0
  309. moriarty/assets/templates/exposures/svn-exposed.yaml +28 -0
  310. moriarty/assets/templates/fuzzing/api-endpoints.yaml +39 -0
  311. moriarty/assets/templates/fuzzing/common-files.yaml +37 -0
  312. moriarty/assets/templates/fuzzing/open-redirect-fuzz.yaml +35 -0
  313. moriarty/assets/templates/fuzzing/xss-search-fuzz.yaml +29 -0
  314. moriarty/assets/templates/git-config.yaml +18 -0
  315. moriarty/assets/templates/misconfigurations/cors-misconfiguration.yaml +30 -0
  316. moriarty/assets/templates/misconfigurations/debug-enabled.yaml +29 -0
  317. moriarty/assets/templates/misconfigurations/directory-listing.yaml +33 -0
  318. moriarty/assets/templates/misconfigurations/jwt-none-algo.yaml +30 -0
  319. moriarty/assets/templates/misconfigurations/ssl-tls-weak.yaml +23 -0
  320. moriarty/assets/templates/vulnerabilities/lfi-basic.yaml +31 -0
  321. moriarty/assets/templates/vulnerabilities/open-redirect.yaml +31 -0
  322. moriarty/assets/templates/vulnerabilities/rce-basic.yaml +34 -0
  323. moriarty/assets/templates/vulnerabilities/sqli-error.yaml +39 -0
  324. moriarty/assets/templates/vulnerabilities/ssrf-basic.yaml +31 -0
  325. moriarty/assets/templates/vulnerabilities/xss-reflected.yaml +38 -0
  326. moriarty/assets/templates/vulnerabilities/xxe-basic.yaml +30 -0
  327. moriarty/assets/wordlists/subdomains-1000.txt +1063 -0
  328. moriarty/cli/__init__.py +3 -0
  329. moriarty/cli/app.py +120 -0
  330. moriarty/cli/async_utils.py +19 -0
  331. moriarty/cli/dns.py +83 -0
  332. moriarty/cli/domain_cmd.py +572 -0
  333. moriarty/cli/email.py +383 -0
  334. moriarty/cli/email_investigate.py +224 -0
  335. moriarty/cli/intelligence.py +329 -0
  336. moriarty/cli/output.py +62 -0
  337. moriarty/cli/rdap.py +94 -0
  338. moriarty/cli/state.py +38 -0
  339. moriarty/cli/tls.py +91 -0
  340. moriarty/cli/user.py +227 -0
  341. moriarty/core/cache_backend.py +223 -0
  342. moriarty/core/config_manager.py +303 -0
  343. moriarty/correlator/__init__.py +0 -0
  344. moriarty/data/__init__.py +81 -0
  345. moriarty/data/ioc/__init__.py +142 -0
  346. moriarty/data/ioc/matcher.py +254 -0
  347. moriarty/data/ioc/types.py +267 -0
  348. moriarty/data/local_intelligence.py +507 -0
  349. moriarty/data/signature_loaders/__init__.py +103 -0
  350. moriarty/data/signature_loaders/base.py +54 -0
  351. moriarty/data/signature_loaders/ioc_feed.py +356 -0
  352. moriarty/data/signature_loaders/wappalyzer.py +112 -0
  353. moriarty/dsl/__init__.py +0 -0
  354. moriarty/dsl/loader.py +99 -0
  355. moriarty/dsl/schema.py +47 -0
  356. moriarty/export/__init__.py +0 -0
  357. moriarty/intelligence/__init__.py +27 -0
  358. moriarty/intelligence/__main__.py +150 -0
  359. moriarty/intelligence/config.py +395 -0
  360. moriarty/intelligence/ioc.py +267 -0
  361. moriarty/intelligence/signatures.py +550 -0
  362. moriarty/intelligence/storage.py +501 -0
  363. moriarty/interop/__init__.py +0 -0
  364. moriarty/logging/__init__.py +0 -0
  365. moriarty/logging/config.py +47 -0
  366. moriarty/models/__init__.py +16 -0
  367. moriarty/models/assertion.py +24 -0
  368. moriarty/models/entity.py +22 -0
  369. moriarty/models/evidence.py +37 -0
  370. moriarty/models/relation.py +24 -0
  371. moriarty/models/types.py +28 -0
  372. moriarty/modules/__init__.py +0 -0
  373. moriarty/modules/avatar_hash.py +184 -0
  374. moriarty/modules/directory_fuzzer.py +322 -0
  375. moriarty/modules/dns_scan.py +40 -0
  376. moriarty/modules/domain_scanner.py +620 -0
  377. moriarty/modules/email_check.py +98 -0
  378. moriarty/modules/email_investigate.py +267 -0
  379. moriarty/modules/email_security.py +274 -0
  380. moriarty/modules/googlemaps_lookup.py +106 -0
  381. moriarty/modules/headless_executor.py +201 -0
  382. moriarty/modules/orchestrator.py +60 -0
  383. moriarty/modules/passive_recon.py +444 -0
  384. moriarty/modules/phone_extractor.py +151 -0
  385. moriarty/modules/pipeline_orchestrator.py +726 -0
  386. moriarty/modules/port_scanner.py +129 -0
  387. moriarty/modules/rdap.py +61 -0
  388. moriarty/modules/rdap_extended.py +188 -0
  389. moriarty/modules/stealth_mode.py +610 -0
  390. moriarty/modules/subdomain_discovery.py +595 -0
  391. moriarty/modules/technology_profiler.py +361 -0
  392. moriarty/modules/template_executor.py +239 -0
  393. moriarty/modules/template_scanner.py +1048 -0
  394. moriarty/modules/tls_scan.py +46 -0
  395. moriarty/modules/tls_validator.py +188 -0
  396. moriarty/modules/vuln_scanner.py +483 -0
  397. moriarty/modules/waf_detector.py +585 -0
  398. moriarty/modules/wayback_discovery.py +234 -0
  399. moriarty/modules/web_crawler.py +163 -0
  400. moriarty/net/__init__.py +0 -0
  401. moriarty/net/dns_cache.py +175 -0
  402. moriarty/net/dns_client.py +188 -0
  403. moriarty/net/rdap_client.py +52 -0
  404. moriarty/net/smtp_client.py +114 -0
  405. moriarty/net/tls_client.py +111 -0
  406. moriarty/parsers/__init__.py +0 -0
  407. moriarty/parsers/html_parser.py +136 -0
  408. moriarty/tests/__init__.py +0 -0
  409. moriarty/tests/test_email_service.py +17 -0
  410. moriarty/tests/test_models.py +46 -0
  411. moriarty/tests/test_orchestrator.py +30 -0
  412. moriarty/tests/test_tls_client.py +18 -0
  413. moriarty_project-0.1.6.dist-info/METADATA +388 -0
  414. moriarty_project-0.1.6.dist-info/RECORD +418 -0
  415. moriarty_project-0.1.6.dist-info/WHEEL +4 -0
  416. moriarty_project-0.1.6.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,98 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import List, Optional
5
+
6
+ from email_validator import EmailNotValidError, validate_email
7
+
8
+ from ..net.dns_client import DNSClient, DNSLookupResult
9
+ from ..net.smtp_client import SMTPClient, SMTPProbeResult
10
+
11
+
12
+ @dataclass(slots=True)
13
+ class EmailCheckOptions:
14
+ check_dns: bool = True
15
+ check_smtp: bool = False
16
+ from_address: str = "postmaster@localhost"
17
+ retries: int = 1
18
+ wait: float = 1.0
19
+
20
+
21
+ @dataclass(slots=True)
22
+ class EmailCheckResult:
23
+ input_email: str
24
+ normalized_email: str
25
+ local_part: str
26
+ domain: str
27
+ dns: Optional[DNSLookupResult]
28
+ smtp: Optional[SMTPProbeResult]
29
+ warnings: List[str]
30
+
31
+
32
+ class EmailCheckService:
33
+ """Run DNS and SMTP probes for an email address."""
34
+
35
+ def __init__(self, email: str, options: EmailCheckOptions, timeout: float = 8.0) -> None:
36
+ self._raw_email = email
37
+ self._options = options
38
+ self._timeout = timeout
39
+
40
+ async def run(self) -> EmailCheckResult:
41
+ normalized = self._normalize_email(self._raw_email)
42
+ domain = normalized["domain"]
43
+ local_part = normalized["local_part"]
44
+ warnings: List[str] = []
45
+
46
+ dns_result: Optional[DNSLookupResult] = None
47
+ if self._options.check_dns:
48
+ dns_client = DNSClient(timeout=self._timeout)
49
+ dns_result = await dns_client.lookup_domain(domain)
50
+ if not dns_result.mx:
51
+ warnings.append("Domain has no MX records; falling back to A/AAAA for SMTP.")
52
+
53
+ smtp_result: Optional[SMTPProbeResult] = None
54
+ if self._options.check_smtp:
55
+ smtp_client = SMTPClient(timeout=self._timeout, wait=self._options.wait, retries=self._options.retries)
56
+ hosts: List[str] = []
57
+ if dns_result and dns_result.mx:
58
+ hosts = [record.exchange.rstrip('.') for record in dns_result.mx]
59
+ elif dns_result and (dns_result.a or dns_result.aaaa):
60
+ hosts = [domain]
61
+ else:
62
+ hosts = [domain]
63
+ warnings.append("No DNS information available; SMTP probe will target the domain directly.")
64
+
65
+ smtp_result = await smtp_client.probe(
66
+ email=normalized["email"],
67
+ from_address=self._options.from_address,
68
+ hosts=hosts,
69
+ )
70
+
71
+ return EmailCheckResult(
72
+ input_email=self._raw_email,
73
+ normalized_email=normalized["email"],
74
+ local_part=local_part,
75
+ domain=domain,
76
+ dns=dns_result,
77
+ smtp=smtp_result,
78
+ warnings=warnings,
79
+ )
80
+
81
+ @staticmethod
82
+ def _normalize_email(raw_email: str) -> dict[str, str]:
83
+ try:
84
+ validated = validate_email(raw_email, check_deliverability=False)
85
+ except EmailNotValidError as exc:
86
+ raise ValueError(f"Invalid email address: {exc}") from exc
87
+
88
+ normalized_attr = getattr(validated, "normalized", None)
89
+ normalized_email = (normalized_attr or validated.email).lower()
90
+ local_part, domain = normalized_email.split("@", 1)
91
+ return {
92
+ "email": normalized_email,
93
+ "local_part": local_part,
94
+ "domain": domain,
95
+ }
96
+
97
+
98
+ __all__ = ["EmailCheckOptions", "EmailCheckResult", "EmailCheckService"]
@@ -0,0 +1,267 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import hashlib
5
+ from dataclasses import dataclass
6
+ from typing import Any, Dict, List, Optional
7
+
8
+ import httpx
9
+ import structlog
10
+
11
+ from ..models.entity import Entity
12
+ from ..models.types import EntityKind
13
+
14
+ logger = structlog.get_logger(__name__)
15
+
16
+
17
+ @dataclass(slots=True)
18
+ class SocialProfile:
19
+ """Perfil encontrado em uma plataforma."""
20
+
21
+ platform: str
22
+ url: str
23
+ username: Optional[str] = None
24
+ user_id: Optional[str] = None
25
+ display_name: Optional[str] = None
26
+ avatar_url: Optional[str] = None
27
+ bio: Optional[str] = None
28
+ verified: bool = False
29
+ confidence: float = 0.5
30
+ metadata: Dict[str, Any] = None
31
+
32
+ def __post_init__(self) -> None:
33
+ if self.metadata is None:
34
+ self.metadata = {}
35
+
36
+
37
+ @dataclass(slots=True)
38
+ class EmailInvestigationResult:
39
+ """Resultado de uma investigação profunda de email."""
40
+
41
+ email: str
42
+ normalized_email: str
43
+ domain: str
44
+ local_part: str
45
+
46
+ # Gravatar
47
+ gravatar_hash: str
48
+ gravatar_profile: Optional[Dict[str, Any]] = None
49
+ gravatar_avatar: Optional[str] = None
50
+
51
+ # Social profiles
52
+ social_profiles: List[SocialProfile] = None
53
+
54
+ # Breaches
55
+ breached: bool = False
56
+ breach_count: int = 0
57
+ breaches: List[Dict[str, Any]] = None
58
+
59
+ # Linked data
60
+ phone_numbers: List[str] = None
61
+ websites: List[str] = None
62
+ usernames: List[str] = None
63
+
64
+ # Metadata
65
+ total_platforms_found: int = 0
66
+ search_timestamp: str = ""
67
+
68
+ def __post_init__(self) -> None:
69
+ if self.social_profiles is None:
70
+ self.social_profiles = []
71
+ if self.breaches is None:
72
+ self.breaches = []
73
+ if self.phone_numbers is None:
74
+ self.phone_numbers = []
75
+ if self.websites is None:
76
+ self.websites = []
77
+ if self.usernames is None:
78
+ self.usernames = []
79
+
80
+
81
+ class EmailInvestigator:
82
+ """Investiga email em múltiplas fontes."""
83
+
84
+ def __init__(self, timeout: float = 8.0, user_agent: Optional[str] = None) -> None:
85
+ self._timeout = timeout
86
+ self._user_agent = user_agent or "Moriarty/0.1.0 (OSINT Client)"
87
+
88
+ async def investigate(self, email: str) -> EmailInvestigationResult:
89
+ """Executa investigação completa."""
90
+ from datetime import datetime, timezone
91
+ from email_validator import validate_email
92
+
93
+ # Normaliza
94
+ validated = validate_email(email, check_deliverability=False)
95
+ normalized = validated.normalized or validated.email
96
+ local_part, domain = normalized.lower().split("@", 1)
97
+
98
+ # Gera hash Gravatar
99
+ gravatar_hash = hashlib.md5(normalized.encode("utf-8")).hexdigest()
100
+
101
+ # Executa investigações em paralelo
102
+ tasks = [
103
+ self._check_gravatar(gravatar_hash),
104
+ self._check_social_profiles_smart(email, local_part),
105
+ self._check_breaches_anon(email),
106
+ ]
107
+
108
+ gravatar_data, social_profiles, breach_data = await asyncio.gather(*tasks, return_exceptions=True)
109
+
110
+ # Processa Gravatar
111
+ gravatar_profile = None
112
+ gravatar_avatar = None
113
+ if isinstance(gravatar_data, dict):
114
+ gravatar_profile = gravatar_data
115
+ gravatar_avatar = f"https://www.gravatar.com/avatar/{gravatar_hash}?s=200&d=404"
116
+
117
+ # Processa social
118
+ profiles: List[SocialProfile] = []
119
+ if isinstance(social_profiles, list):
120
+ profiles = social_profiles
121
+
122
+ # Processa breaches
123
+ breached = False
124
+ breach_count = 0
125
+ breaches = []
126
+ if isinstance(breach_data, dict):
127
+ breached = breach_data.get("breached", False)
128
+ breach_count = breach_data.get("count", 0)
129
+ breaches = breach_data.get("breaches", [])
130
+
131
+ # Extrai dados agregados
132
+ usernames = list(set(p.username for p in profiles if p.username))
133
+ websites = list(set(p.metadata.get("website") for p in profiles if p.metadata.get("website")))
134
+
135
+ result = EmailInvestigationResult(
136
+ email=email,
137
+ normalized_email=normalized,
138
+ domain=domain,
139
+ local_part=local_part,
140
+ gravatar_hash=gravatar_hash,
141
+ gravatar_profile=gravatar_profile,
142
+ gravatar_avatar=gravatar_avatar,
143
+ social_profiles=profiles,
144
+ breached=breached,
145
+ breach_count=breach_count,
146
+ breaches=breaches,
147
+ phone_numbers=[],
148
+ websites=websites,
149
+ usernames=usernames,
150
+ total_platforms_found=len(profiles),
151
+ search_timestamp=datetime.now(timezone.utc).isoformat(),
152
+ )
153
+
154
+ return result
155
+
156
+ async def _check_gravatar(self, gravatar_hash: str) -> Optional[Dict[str, Any]]:
157
+ """Verifica perfil Gravatar."""
158
+ url = f"https://www.gravatar.com/{gravatar_hash}.json"
159
+
160
+ try:
161
+ async with httpx.AsyncClient(timeout=self._timeout, follow_redirects=False) as client:
162
+ response = await client.get(url)
163
+
164
+ if response.status_code == 200:
165
+ data = response.json()
166
+ return data.get("entry", [{}])[0] if data.get("entry") else None
167
+ except Exception:
168
+ pass
169
+
170
+ return None
171
+
172
+ async def _check_social_profiles_smart(
173
+ self, email: str, local_part: str
174
+ ) -> List[SocialProfile]:
175
+ """Busca inteligente em redes sociais usando templates."""
176
+ from ..dsl.loader import TemplateLoader
177
+ from ..modules.template_executor import TemplateExecutor
178
+
179
+ profiles: List[SocialProfile] = []
180
+
181
+ # Carrega templates
182
+ loader = TemplateLoader()
183
+ loader.load_builtin()
184
+
185
+ # Filtra apenas templates habilitados
186
+ templates = [t for t in loader.list_templates() if t.enabled and not t.require_headless]
187
+
188
+ if not templates:
189
+ return profiles
190
+
191
+ # Executa templates usando local_part como username
192
+ executor = TemplateExecutor(timeout=self._timeout, user_agent=self._user_agent)
193
+
194
+ # Limita a 20 sites mais relevantes para não demorar muito
195
+ relevant_templates = templates[:20]
196
+
197
+ semaphore = asyncio.Semaphore(10) # Max 10 paralelas
198
+
199
+ async def check_site(template: Any) -> Optional[SocialProfile]:
200
+ async with semaphore:
201
+ try:
202
+ result = await executor.execute(template, {"username": local_part})
203
+
204
+ if result.exists and result.confidence > 0.5:
205
+ # Extrai dados relevantes
206
+ profile = SocialProfile(
207
+ platform=template.site,
208
+ url=result.url,
209
+ username=local_part,
210
+ display_name=result.extracted.get("name"),
211
+ bio=result.extracted.get("bio"),
212
+ avatar_url=result.extracted.get("avatar"),
213
+ confidence=result.confidence,
214
+ metadata={
215
+ "website": result.extracted.get("website"),
216
+ "location": result.extracted.get("location"),
217
+ "followers": result.extracted.get("followers"),
218
+ },
219
+ )
220
+ return profile
221
+ except Exception:
222
+ pass
223
+
224
+ return None
225
+
226
+ tasks = [check_site(t) for t in relevant_templates]
227
+ results = await asyncio.gather(*tasks, return_exceptions=True)
228
+
229
+ # Filtra resultados válidos
230
+ for result in results:
231
+ if isinstance(result, SocialProfile):
232
+ profiles.append(result)
233
+
234
+ return profiles
235
+
236
+ async def _check_breaches_anon(self, email: str) -> Dict[str, Any]:
237
+ """Verifica breaches usando HIBP k-anonymity."""
238
+ # HIBP k-anonymity: hash SHA-1, envia apenas primeiros 5 chars
239
+ sha1_hash = hashlib.sha1(email.encode("utf-8")).hexdigest().upper()
240
+ prefix = sha1_hash[:5]
241
+ suffix = sha1_hash[5:]
242
+
243
+ url = f"https://api.pwnedpasswords.com/range/{prefix}"
244
+
245
+ try:
246
+ async with httpx.AsyncClient(timeout=self._timeout) as client:
247
+ response = await client.get(url, headers={"User-Agent": self._user_agent})
248
+
249
+ if response.status_code == 200:
250
+ # Procura pelo suffix na resposta
251
+ lines = response.text.split("\n")
252
+ for line in lines:
253
+ if line.startswith(suffix):
254
+ count = int(line.split(":")[1])
255
+ logger.warning("breach.found", email=email, count=count)
256
+ return {
257
+ "breached": True,
258
+ "count": count,
259
+ "breaches": [{"source": "HIBP", "occurrences": count}],
260
+ }
261
+ except Exception as exc:
262
+ logger.debug("breach.check.error", error=str(exc))
263
+
264
+ return {"breached": False, "count": 0, "breaches": []}
265
+
266
+
267
+ __all__ = ["EmailInvestigator", "EmailInvestigationResult", "SocialProfile"]
@@ -0,0 +1,274 @@
1
+ """Validações avançadas de segurança de email."""
2
+ import asyncio
3
+ import hashlib
4
+ import ssl
5
+ from dataclasses import dataclass
6
+ from typing import List, Optional
7
+
8
+ import aiodns
9
+ import httpx
10
+ import structlog
11
+
12
+ logger = structlog.get_logger(__name__)
13
+
14
+
15
+ @dataclass
16
+ class TLSARecord:
17
+ """Registro TLSA (DANE)."""
18
+ usage: int
19
+ selector: int
20
+ matching_type: int
21
+ certificate_data: str
22
+
23
+
24
+ @dataclass
25
+ class ARCResult:
26
+ """Resultado da validação ARC."""
27
+ present: bool
28
+ chain_valid: bool
29
+ instances: int
30
+ sealer: Optional[str] = None
31
+
32
+
33
+ @dataclass
34
+ class TLSGrade:
35
+ """Avaliação TLS do servidor."""
36
+ protocol: str # TLSv1.2, TLSv1.3
37
+ cipher: str
38
+ grade: str # A+, A, B, C, D, F
39
+ supports_tls13: bool
40
+ forward_secrecy: bool
41
+ vulnerabilities: List[str]
42
+
43
+
44
+ @dataclass
45
+ class GreylistingStatus:
46
+ """Status de greylisting."""
47
+ detected: bool
48
+ retry_after: Optional[int] = None # segundos
49
+ temp_fail_code: Optional[int] = None
50
+
51
+
52
+ class EmailSecurityChecker:
53
+ """Verifica recursos avançados de segurança de email."""
54
+
55
+ def __init__(self, timeout: float = 10.0):
56
+ self._timeout = timeout
57
+ self._resolver = aiodns.DNSResolver(timeout=timeout)
58
+
59
+ async def check_tlsa(self, domain: str, port: int = 25) -> List[TLSARecord]:
60
+ """
61
+ Verifica registros TLSA (DANE - DNS-based Authentication of Named Entities).
62
+
63
+ Ex: _25._tcp.mail.example.com
64
+ """
65
+ tlsa_domain = f"_{port}._tcp.{domain}"
66
+
67
+ try:
68
+ logger.info("email.security.tlsa.check", domain=tlsa_domain)
69
+ result = await self._resolver.query(tlsa_domain, "TLSA")
70
+
71
+ if not isinstance(result, list):
72
+ return []
73
+
74
+ records = []
75
+ for record in result:
76
+ # Formato TLSA: usage selector matching_type certificate_data
77
+ try:
78
+ usage = getattr(record, 'usage', 0)
79
+ selector = getattr(record, 'selector', 0)
80
+ matching_type = getattr(record, 'matching_type', 0)
81
+ cert_data = getattr(record, 'cert', '')
82
+
83
+ records.append(TLSARecord(
84
+ usage=usage,
85
+ selector=selector,
86
+ matching_type=matching_type,
87
+ certificate_data=cert_data,
88
+ ))
89
+ except Exception as e:
90
+ logger.warning("email.security.tlsa.parse_error", error=str(e))
91
+
92
+ logger.info("email.security.tlsa.found", domain=tlsa_domain, count=len(records))
93
+ return records
94
+
95
+ except aiodns.error.DNSError:
96
+ logger.debug("email.security.tlsa.not_found", domain=tlsa_domain)
97
+ return []
98
+
99
+ async def check_arc(self, mx_host: str) -> ARCResult:
100
+ """
101
+ Verifica suporte a ARC (Authenticated Received Chain).
102
+
103
+ ARC é usado para preservar autenticação através de intermediários.
104
+ Checamos via headers SMTP ou via consulta ao servidor.
105
+ """
106
+ # Simulação - em produção, faria uma conexão SMTP real
107
+ # e verificaria os headers de uma mensagem test
108
+ logger.info("email.security.arc.check", mx_host=mx_host)
109
+
110
+ # Por agora, retorna placeholder
111
+ # TODO: Implementar verificação real via SMTP
112
+ return ARCResult(
113
+ present=False,
114
+ chain_valid=False,
115
+ instances=0,
116
+ sealer=None,
117
+ )
118
+
119
+ async def grade_tls(self, mx_host: str, port: int = 25) -> TLSGrade:
120
+ """
121
+ Avalia a qualidade da configuração TLS do servidor SMTP.
122
+
123
+ Verifica:
124
+ - Versão do protocolo (TLS 1.2, 1.3)
125
+ - Cipher suites
126
+ - Forward secrecy
127
+ - Vulnerabilidades conhecidas
128
+ """
129
+ logger.info("email.security.tls_grade.start", mx_host=mx_host, port=port)
130
+
131
+ vulnerabilities = []
132
+
133
+ try:
134
+ # Cria contexto SSL
135
+ context = ssl.create_default_context()
136
+
137
+ # Tenta conexão TLS
138
+ reader, writer = await asyncio.wait_for(
139
+ asyncio.open_connection(mx_host, port, ssl=context),
140
+ timeout=self._timeout
141
+ )
142
+
143
+ # Obtém informações SSL
144
+ ssl_object = writer.get_extra_info('ssl_object')
145
+ if ssl_object:
146
+ protocol = ssl_object.version()
147
+ cipher = ssl_object.cipher()
148
+
149
+ supports_tls13 = protocol == 'TLSv1.3'
150
+
151
+ # Verifica forward secrecy (PFS)
152
+ cipher_name = cipher[0] if cipher else ""
153
+ forward_secrecy = any(fs in cipher_name for fs in ['ECDHE', 'DHE'])
154
+
155
+ # Determina grade
156
+ if supports_tls13 and forward_secrecy:
157
+ grade = "A+"
158
+ elif protocol == 'TLSv1.2' and forward_secrecy:
159
+ grade = "A"
160
+ elif protocol == 'TLSv1.2':
161
+ grade = "B"
162
+ elif protocol == 'TLSv1.1':
163
+ grade = "C"
164
+ vulnerabilities.append("TLS 1.1 deprecated")
165
+ else:
166
+ grade = "F"
167
+ vulnerabilities.append("Insecure TLS version")
168
+
169
+ # Verifica cipher fraco
170
+ if cipher_name and ('RC4' in cipher_name or 'DES' in cipher_name):
171
+ vulnerabilities.append("Weak cipher detected")
172
+ grade = "F"
173
+
174
+ writer.close()
175
+ await writer.wait_closed()
176
+
177
+ logger.info("email.security.tls_grade.complete", mx_host=mx_host, grade=grade, protocol=protocol)
178
+
179
+ return TLSGrade(
180
+ protocol=protocol,
181
+ cipher=cipher_name,
182
+ grade=grade,
183
+ supports_tls13=supports_tls13,
184
+ forward_secrecy=forward_secrecy,
185
+ vulnerabilities=vulnerabilities,
186
+ )
187
+
188
+ writer.close()
189
+ await writer.wait_closed()
190
+
191
+ except Exception as e:
192
+ logger.warning("email.security.tls_grade.error", mx_host=mx_host, error=str(e))
193
+
194
+ # Fallback: sem TLS
195
+ return TLSGrade(
196
+ protocol="None",
197
+ cipher="",
198
+ grade="F",
199
+ supports_tls13=False,
200
+ forward_secrecy=False,
201
+ vulnerabilities=["No TLS support detected"],
202
+ )
203
+
204
+ async def detect_greylisting(self, mx_host: str, sender: str, recipient: str) -> GreylistingStatus:
205
+ """
206
+ Detecta se o servidor usa greylisting.
207
+
208
+ Greylisting temporariamente rejeita emails desconhecidos
209
+ com código 4xx, esperando retry.
210
+ """
211
+ logger.info("email.security.greylisting.check", mx_host=mx_host)
212
+
213
+ try:
214
+ # Faz tentativa SMTP inicial
215
+ reader, writer = await asyncio.wait_for(
216
+ asyncio.open_connection(mx_host, 25),
217
+ timeout=self._timeout
218
+ )
219
+
220
+ # Lê banner
221
+ banner = await reader.read(1024)
222
+
223
+ # EHLO
224
+ writer.write(b"EHLO moriarty.local\r\n")
225
+ await writer.drain()
226
+ ehlo_response = await reader.read(1024)
227
+
228
+ # MAIL FROM
229
+ writer.write(f"MAIL FROM:<{sender}>\r\n".encode())
230
+ await writer.drain()
231
+ mail_response = await reader.read(1024)
232
+
233
+ # RCPT TO
234
+ writer.write(f"RCPT TO:<{recipient}>\r\n".encode())
235
+ await writer.drain()
236
+ rcpt_response = await reader.read(1024)
237
+
238
+ writer.write(b"QUIT\r\n")
239
+ await writer.drain()
240
+ writer.close()
241
+ await writer.wait_closed()
242
+
243
+ # Analisa resposta
244
+ rcpt_str = rcpt_response.decode('utf-8', errors='ignore')
245
+
246
+ # Códigos 4xx indicam erro temporário (greylisting comum)
247
+ if rcpt_str.startswith('4'):
248
+ # Extrai código
249
+ parts = rcpt_str.split()
250
+ code = int(parts[0]) if parts else 450
251
+
252
+ # Greylisting detectado
253
+ logger.info("email.security.greylisting.detected", mx_host=mx_host, code=code)
254
+ return GreylistingStatus(
255
+ detected=True,
256
+ temp_fail_code=code,
257
+ retry_after=300, # Típico: 5 minutos
258
+ )
259
+
260
+ logger.info("email.security.greylisting.not_detected", mx_host=mx_host)
261
+ return GreylistingStatus(detected=False)
262
+
263
+ except Exception as e:
264
+ logger.warning("email.security.greylisting.error", mx_host=mx_host, error=str(e))
265
+ return GreylistingStatus(detected=False)
266
+
267
+
268
+ __all__ = [
269
+ "EmailSecurityChecker",
270
+ "TLSARecord",
271
+ "ARCResult",
272
+ "TLSGrade",
273
+ "GreylistingStatus",
274
+ ]