description = [[ Extracts a list of valid email accounts found in the web server. http-email-harvest use the "httpspider" library to crawl a web server and then parses all the URIs found looking for email accounts. To remove email accounts belonging to external domains use http-email-harvest.localOnly ]] --- --@usage --nmap -sV --script http-email-harvest --nmap -sV --script http-email-harvest --script-args http.useragent=Mozilla,httpspider.ignoreParams -- --@output --PORT STATE SERVICE --80/tcp open http --| http-email-harvest: --| fyodor@insecure.org --|_nmap-hackers-subscribe@insecure.org -- --@args http-email-harvest.localOnly Shows only email accounts belonging to the scanned host. Default: false -- --Other useful args: --http.useragent - User Agent used in HTTP requests --- author = "Paulino Calderon" license = "Same as Nmap--See http://nmap.org/book/man-legal.html" categories = {"discovery"} require "http" require "shortport" require "httpspider" portrule = shortport.http --Returns table of emails found in the given text --@param text Haystack local function find_emails(text) local emails = {} for email in string.gfind(text, '[A-Za-z0-9%.%%%+%-]+@[A-Za-z0-9%.%%%+%-]+%.%w%w%w?%w?') do table.insert(emails, email) end return emails end --Returns true if email account belongs to host --@param email Email string local function is_email_local(host, email) local _, _, user, domain = string.find(email, '(.*)@(.*)') if host.targetname and host.targetname == domain then return true end return false end --Main --Iterates through sitemap to find email accounts action = function(host, port) local local_only = stdnse.get_script_args(SCRIPT_NAME..".localOnly") or false local emails_found = {} local valid_emails = {} httpspider.crawl(host, port) local uris = httpspider.get_sitemap() for _, uri in pairs(uris) do local page = http.get(host, port, uri) local emails = find_emails(page.body) for _, email in pairs(emails) do if emails_found[email] == nil then if not(local_only) or (local_only and is_email_local(host,email)) then emails_found[email] = true valid_emails[#valid_emails+1] = email end end end end return #valid_emails > 1 and stdnse.strjoin("\n", valid_emails) or nil end