| 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144. 145. 146. 147. 148. 149. 150. 151. 152. 153. 154. 155. 156. 157. 158. 159. 160. 161. 162. 163. 164. 165. 166. 167. 168. 169. 170. 171. 172. 173. 174. 175. 176. 177. 178. 179. 180. 181. 182. 183. 184. 185. 186. 187. 188. 189. 190. 191. 192. 193. 194. 195. 196. 197. 198. 199. 200. 201. 202. 203. 204. 205. 206. 207. 208. 209. 210. 211. 212. 213. 214. 215. 216. 217. 218. 219. 220. 221. 222. 223. 224. 225. 226. 227. 228. 229. 230. | #!/usr/bin/env python # -*- coding: utf-8 -*- # # sex.py # # Version: 2.0 # # Copyright (C) 2009 novacane novacane[at]dandies[dot]org # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # # Thanks to regular-expressions.info for your regex pattern! # DO NOT FORGET TO INSTALL DNSPYTHON - http://www.dnspython.org/ # import os import sys import re import smtplib import dns.resolver from optparse import OptionParser def main(source, destination, verbose, sort, remove_duplicates, exclude_ext): #email_pattern = re.compile( #r"""[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z #0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?""") email_pattern = re.compile( r"\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b", re.I) matches = [] try: file_dst = open(destination, "w") except IOError: print "!> ERROR: %s" % destination sys.exit(1) if os.path.isfile(source): try: file_src = open(source) if verbose == 2: print ">> FILE: %s" % source except IOError: print "!> ERROR: %s" % source sys.exit(1) for line in file_src: for match in email_pattern.findall(line): matches.append(match) if verbose == 1: print match elif verbose == 2: print ">> FOUND: %s" % match elif os.path.isdir(source): for root, dirs, files in os.walk(source, topdown=False): for name in files: fpath = os.path.join(root, name) if name.find(".") != -1: if name.split(".")[1] in exclude_ext: if verbose == 2: print "!> EXCLUDE: %s" % fpath continue try: file_src = open(fpath) if verbose == 2: print ">> FILE: %s" % fpath except IOError: print "!> ERROR: %s" % fpath continue for line in file_src: for match in email_pattern.findall(line): matches.append(match) if verbose == 1: print match elif verbose == 2: print ">> FOUND: %s" % match file_src.close() else: print "!> ERROR: %s" % source sys.exit(1) if remove_duplicates == 1: matches = list(set(matches)) if verbose == 2: print ">> Extraced email addresses: " + str(len(matches)) if sort == 1: matches.sort() for i in matches: file_dst.write(i + "\n") file_src.close() file_dst.close() def verify_email_address(email_addresses): """ Get SMTP return code Verify emails by checking the "RCPT TO" return code from the SMTP server. NOTE: dropped vrfy command because provider disabled it to prevent attacks """ failed_domains = [] try: # Open the Source-File. file_emails = open(email_addresses) except IOError: print "!> ERROR: %s" % email_addresses sys.exit(1) # Loop through addresses. Each line represents an email-address. for line in file_emails: # Remove Linefeed. line = line.replace("\n", "") # The actual domain. domain = line.split("@")[1] # Do nothing if domain is already in the failed_domain list. if not domain in failed_domains: try: # Make a MX DNS query. answers = dns.resolver.query(domain, "MX") # OR: mx = str(answers[1].exchange)[:-1] for rdata in answers: # Remove the dot from rdata.exchange. mx = str(rdata.exchange)[:-1] try: # Connect to SMTP server. smtp = smtplib.SMTP(mx) # Polite people say hello first. smtp.docmd("HELO microsoft.com") # Indicates who is sending the mail. smtp.docmd("MAIL FROM:", "<[email protected]>") # Indicates who is recieving the mail. rcpt = smtp.docmd("RCPT TO:", "<" + line + ">") # Print output. print line + "," + mx + "," + \ str(rcpt[0]) + "," + str(rcpt[1]) # Close SMTP connection. smtp.quit() except smtplib.SMTPServerDisconnected: # Add domain to list. failed_domains.append(domain) # Use only the first server-address. break # Raise exception. except dns.resolver.NXDOMAIN: # Add domain to list. failed_domains.append(domain) except dns.resolver.NoAnswer: # Add domain to list. failed_domains.append(domain) except: pass # Close the Source-File. file_emails.close() # Output failed domains. if failed_domains: for item in failed_domains: print "!> FAILED: %s" % item sys.exit() if __name__ == '__main__': help_message = "\n\t[*] Smashing Email eXtractor 2.0 [*] \ \n\t[*] by dandies.org [*] \ \n\n\tTry: sex.py --help\n" usage = "\n %prog [options] <source> <destination> \ \n %prog [-lqsr] [-e ext1,ext2] <source> <destination> \ \n %prog -y <file>" parser = OptionParser(usage=usage, version="%prog 2.0") parser.add_option("-l", "--list", action="store_true", dest="list", help="display email addresses only") parser.add_option("-q", "--quiet", action="store_true", dest="quiet", help="silent output mode") parser.add_option("-s", "--sort", action="store_true", dest="sort", help="sort addresses in alphabetical order") parser.add_option("-r", "--remove-duplicates", action="store_true", dest="remove_duplicates", help="remove duplicated emails") parser.add_option("-e", "--exclude-extension", metavar="EXTENSION", dest="exclude_ext", help="exclude files by extension") parser.add_option("-y", metavar="FILE", dest="email_addresses", help="verify emails from file") (options, args) = parser.parse_args() if options.email_addresses and len(args) == 0: verify_email_address(options.email_addresses) elif options.email_addresses and len(args) != 0: print help_message sys.exit(2) elif len(args) != 2: print help_message sys.exit(2) if options.list and options.quiet: parser.error("options -l and -q are mutually exclusive") # Set default values here. verbose = 2 sort = 0 remove_duplicates = 0 exclude_ext = [] if options.exclude_ext: exclude_ext = options.exclude_ext.split(",") if options.list: verbose = 1 if options.quiet: verbose = 0 if options.sort: sort = 1 if options.remove_duplicates: remove_duplicates = 1 main(args[0], args[1], verbose, sort, remove_duplicates, exclude_ext) |