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