Lucene search
K

http-vhosts NSE Script

🗓️ 06 Dec 2010 05:19:35Reported by Carlos PantelidesType 
nmap
 nmap
🔗 nmap.org👁 636 Views

Searches for web virtual hostnames using a large number of requests with common hostnames. Identifies document returns and redirection locations

Related
Code
ReporterTitlePublishedViews
Family
GithubExploit
Exploit for Code Injection in Samba
2 Dec 202509:55
githubexploit
GithubExploit
Exploit for Code Injection in Samba
25 May 201713:20
githubexploit
GithubExploit
Exploit for Code Injection in Samba
15 May 202106:52
githubexploit
GithubExploit
Exploit for Code Injection in Samba
30 May 201715:08
githubexploit
GithubExploit
Exploit for Code Injection in Samba
25 May 201713:20
githubexploit
GithubExploit
Exploit for CVE-2017-0143
16 May 201719:34
githubexploit
GithubExploit
Exploit for Code Injection in Samba
9 May 202102:32
githubexploit
GithubExploit
Exploit for Code Injection in Samba
5 Jun 201716:25
githubexploit
GithubExploit
Exploit for Code Injection in Samba
26 May 201700:58
githubexploit
GithubExploit
Exploit for Code Injection in Samba
1 Nov 202223:17
githubexploit
Rows per page
local coroutine = require "coroutine"
local http = require "http"
local io = require "io"
local nmap = require "nmap"
local shortport = require "shortport"
local stdnse = require "stdnse"
local string = require "string"
local table = require "table"
local datafiles = require "datafiles"

description = [[
Searches for web virtual hostnames by making a large number of HEAD requests against http servers using common hostnames.

Each HEAD request provides a different
<code>Host</code> header. The hostnames come from a built-in default
list. Shows the names that return a document. Also shows the location of
redirections.

The domain can be given as the <code>http-vhosts.domain</code> argument or
deduced from the target's name. For example when scanning www.example.com,
various names of the form <name>.example.com are tried.
]]

---
-- @usage
-- nmap --script http-vhosts -p 80,8080,443 <target>
--
-- @arg http-vhosts.domain The domain that hostnames will be prepended to, for
-- example <code>example.com</code> yields www.example.com, www2.example.com,
-- etc. If not provided, a guess is made based on the hostname.
-- @arg http-vhosts.path The path to try to retrieve. Default <code>/</code>.
-- @arg http-vhosts.collapse The limit to start collapsing results by status code. Default <code>20</code>
-- @arg http-vhosts.filelist file with the vhosts to try. Default <code>nselib/data/vhosts-default.lst</code>
--
-- @output
-- PORT   STATE SERVICE REASON
-- 80/tcp open  http    syn-ack
-- | http-vhosts:
-- | example.com: 301 -> http://www.example.com/
-- | www.example.com: 200
-- | docs.example.com: 302 -> https://www.example.com/docs/
-- |_images.example.com: 200
--
-- @internal: see http://seclists.org/nmap-dev/2010/q4/401 and http://seclists.org/nmap-dev/2010/q4/445
--
--
-- @todo feature: add option report and implement it
-- @internal after stripping sensitive info like ip, domain names, hostnames
--           and redirection targets from the result, append it to a file
--           that can then be uploaded. If enough info is gathered, the names
--           will be weighted. It can be shared with metasploit
--
-- @todo feature: fill nsedoc
--
-- @todo feature: register results for other scripts (external help needed)
--
-- @todo feature: grow names list (external help needed)
--

author = "Carlos Pantelides"

license = "Same as Nmap--See https://nmap.org/book/man-legal.html"

categories = { "discovery", "intrusive" }

local arg_domain = stdnse.get_script_args(SCRIPT_NAME..".domain")
local arg_path = stdnse.get_script_args(SCRIPT_NAME..".path") or "/"
local arg_filelist = stdnse.get_script_args(SCRIPT_NAME..'.filelist')
local arg_collapse = tonumber(stdnse.get_script_args(SCRIPT_NAME..".collapse")) or 10

-- Defines domain to use, first from user and then from host
local defineDomain = function(host)
  local name = stdnse.get_hostname(host)
  if name and name ~= host.ip then
    local pos = string.find (name, ".",1,true)
    if not pos then return name end
    return string.sub (name, pos + 1)
  end
end

---
-- Makes a target name with a name and a domain
-- @param name string
-- @param domain string
-- @return string
local makeTargetName = function(name,domain)
  if name and name ~= "" then
    if domain and domain ~= "" then
      return name .. "." .. domain
    else
      return name
    end
  elseif domain and domain ~= "" then
    return domain
  end
end


---
-- Collapses a result
-- key -> table
-- @param result table
-- @return string
local collapse = function(result)
  local collapsed = {""}
  for code, group in next, result do
    if  #group > arg_collapse then
      table.insert(collapsed, ("%d names had status %s"):format(#group, code))
    else
      for _,name in ipairs(group) do
        table.insert(collapsed, name)
      end
    end
  end
  return table.concat(collapsed,"\n")
end

local testThread = function(result, host, port, name)
  local condvar = nmap.condvar(result)
  local targetname = makeTargetName(name , arg_domain)
  if targetname ~= nil then
    local http_response = http.generic_request(host, port, "HEAD", arg_path, {header={Host=targetname}})

    if not http_response.status  then
      result["ERROR"] = result["ERROR"] or {}
      table.insert(result["ERROR"], targetname)
    else
      local status = tostring(http_response.status)
      result[status] = result[status] or {}
      if ( 300 <= http_response.status and http_response.status < 400 ) then
        table.insert(result[status], ("%s : %s -> %s"):format(targetname, status, (http_response.header.location or "(no Location provided)")))
      else
        table.insert(result[status], ("%s : %s"):format(targetname, status))
      end
    end
  end
  condvar "signal"
end

local readFromFile = function(filename)
    local database = {}
    for l in io.lines(filename) do
        table.insert(database, l)
    end
    return database
end

portrule = shortport.http

---
-- Script action
-- @param host table
-- @param port table
action = function(host, port)
  local result, threads, hostnames = {}, {}, {}
  local condvar = nmap.condvar(result)
  local status

  if arg_filelist then
    hostnames = readFromFile(arg_filelist)
  else
    status, hostnames = datafiles.parse_file("nselib/data/vhosts-default.lst" , {})
    if not status then
      stdnse.debug1("Can not open file with vhosts file names list")
      return
    end
  end

  arg_domain = arg_domain or defineDomain(host)
  for _,name in ipairs(hostnames) do
    local co = stdnse.new_thread(testThread, result, host, port, name)
    threads[co] = true
  end

  while(next(threads)) do
    for t in pairs(threads) do
      threads[t] = ( coroutine.status(t) ~= "dead" ) and true or nil
    end
    if ( next(threads) ) then
      condvar "wait"
    end
  end

  return collapse(result)
end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation