mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 12:41:29 +00:00
Update ftp-bounce to use new ftp functions
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
local coroutine = require "coroutine"
|
|
||||||
local nmap = require "nmap"
|
local nmap = require "nmap"
|
||||||
local shortport = require "shortport"
|
local shortport = require "shortport"
|
||||||
local stdnse = require "stdnse"
|
local stdnse = require "stdnse"
|
||||||
local string = require "string"
|
local string = require "string"
|
||||||
|
local ftp = require "ftp"
|
||||||
|
|
||||||
description=[[
|
description=[[
|
||||||
Checks to see if an FTP server allows port scanning using the FTP bounce method.
|
Checks to see if an FTP server allows port scanning using the FTP bounce method.
|
||||||
@@ -12,9 +12,9 @@ license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
|
|||||||
|
|
||||||
---
|
---
|
||||||
-- @args ftp-bounce.username Username to log in with. Default
|
-- @args ftp-bounce.username Username to log in with. Default
|
||||||
-- <code>"anonymous"</code>.
|
-- <code>anonymous</code>.
|
||||||
-- @args ftp-bounce.password Password to log in with. Default
|
-- @args ftp-bounce.password Password to log in with. Default
|
||||||
-- <code>"IEUser@"</code>.
|
-- <code>IEUser@</code>.
|
||||||
-- @args ftp-bounce.checkhost Host to try connecting to with the PORT command.
|
-- @args ftp-bounce.checkhost Host to try connecting to with the PORT command.
|
||||||
-- Default: scanme.nmap.org
|
-- Default: scanme.nmap.org
|
||||||
--
|
--
|
||||||
@@ -26,217 +26,88 @@ license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
|
|||||||
-- PORT STATE SERVICE
|
-- PORT STATE SERVICE
|
||||||
-- 21/tcp open ftp
|
-- 21/tcp open ftp
|
||||||
-- |_ftp-bounce: server forbids bouncing to low ports <1025
|
-- |_ftp-bounce: server forbids bouncing to low ports <1025
|
||||||
--
|
|
||||||
-- PORT STATE SERVICE
|
|
||||||
-- 21/tcp open ftp
|
|
||||||
-- |_ftp-bounce: no banner
|
|
||||||
|
|
||||||
categories = {"default", "safe"}
|
categories = {"default", "safe"}
|
||||||
|
|
||||||
|
portrule = shortport.port_or_service({21, 990}, {"ftp", "ftps"})
|
||||||
|
|
||||||
portrule = shortport.service("ftp")
|
|
||||||
|
|
||||||
line_iterate = function(s)
|
|
||||||
local line
|
|
||||||
for line in string.gmatch(s, "([^\n$]*)") do
|
|
||||||
if #line > 0 then
|
|
||||||
coroutine.yield(line)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- returns last ftp code read, or 000 on timeout
|
|
||||||
get_ftp_code = function(socket)
|
|
||||||
local fcode = 000
|
|
||||||
local code = 0
|
|
||||||
local status
|
|
||||||
local result
|
|
||||||
local co
|
|
||||||
local line
|
|
||||||
local err
|
|
||||||
|
|
||||||
while true do
|
|
||||||
status, result = socket:receive()
|
|
||||||
if not status then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
-- read okay!
|
|
||||||
co = coroutine.create(line_iterate)
|
|
||||||
while coroutine.status(co) ~= 'dead' do
|
|
||||||
err, line = coroutine.resume(co, result)
|
|
||||||
if line then
|
|
||||||
code = string.match(line, "^(%d%d%d) ")
|
|
||||||
if not code then
|
|
||||||
code = "-1"
|
|
||||||
end
|
|
||||||
-- io.write(">" .. code .. ":".. line .. "<\n")
|
|
||||||
if tonumber(code) > 0 then
|
|
||||||
fcode = tonumber(code)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- not received good ftp code, try again
|
|
||||||
if fcode ~= 0 then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- io.write("## " .. fcode .. "\n");
|
|
||||||
return fcode
|
|
||||||
end
|
|
||||||
|
|
||||||
local get_login = function()
|
|
||||||
local user, pass
|
|
||||||
local k
|
|
||||||
|
|
||||||
for _, k in ipairs({"ftp-bounce.username", "username"}) do
|
|
||||||
if nmap.registry.args[k] then
|
|
||||||
user = nmap.registry.args[k]
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, k in ipairs({"ftp-bounce.password", "password"}) do
|
|
||||||
if nmap.registry.args[k] then
|
|
||||||
pass = nmap.registry.args[k]
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return user or "anonymous", pass or "IEUser@"
|
|
||||||
end
|
|
||||||
|
|
||||||
local portfmt_cached
|
|
||||||
local function get_portfmt()
|
local function get_portfmt()
|
||||||
if portfmt_cached then return portfmt_cached end
|
|
||||||
local arghost = stdnse.get_script_args(SCRIPT_NAME .. ".checkhost") or "scanme.nmap.org"
|
local arghost = stdnse.get_script_args(SCRIPT_NAME .. ".checkhost") or "scanme.nmap.org"
|
||||||
local status, addrs = nmap.resolve(arghost, "inet")
|
local reg = nmap.registry[SCRIPT_NAME] or {}
|
||||||
if not status or #addrs < 1 then
|
local addr = reg[arghost]
|
||||||
stdnse.verbose1("Couldn't resolve %s, scanning 10.0.0.1 instead.", arghost)
|
if not addr then
|
||||||
addrs = {"10.0.0.1"}
|
local status, addrs = nmap.resolve(arghost, "inet")
|
||||||
|
if not status or #addrs < 1 then
|
||||||
|
stdnse.verbose1("Couldn't resolve %s, scanning 10.0.0.1 instead.", arghost)
|
||||||
|
addr = "10.0.0.1"
|
||||||
|
else
|
||||||
|
addr = addrs[1]
|
||||||
|
end
|
||||||
|
reg[arghost] = addr
|
||||||
end
|
end
|
||||||
portfmt_cached = string.format("PORT %s,%%s\r\n", (string.gsub(addrs[1], "%.", ",")))
|
nmap.registry[SCRIPT_NAME] = reg
|
||||||
return portfmt_cached
|
return string.format("PORT %s,%%s\r\n", (string.gsub(addr, "%.", ",")))
|
||||||
end
|
end
|
||||||
|
|
||||||
action = function(host, port)
|
action = function(host, port)
|
||||||
local socket = nmap.new_socket()
|
local user = stdnse.get_script_args(SCRIPT_NAME .. ".username") or "anonymous"
|
||||||
local result;
|
local pass = stdnse.get_script_args(SCRIPT_NAME .. ".password") or "IEUser@"
|
||||||
local status = true
|
|
||||||
local isAnon = false
|
|
||||||
local isOk = false
|
|
||||||
local sendPass = true
|
|
||||||
local user, pass = get_login()
|
|
||||||
local fc
|
|
||||||
|
|
||||||
socket:set_timeout(10000)
|
|
||||||
socket:connect(host, port)
|
|
||||||
|
|
||||||
-- BANNER
|
-- BANNER
|
||||||
fc = get_ftp_code(socket)
|
local socket, code, message, buffer = ftp.connect(host, port, {request_timeout=10000})
|
||||||
if fc == 0 then
|
if not socket then
|
||||||
socket:close()
|
return nil
|
||||||
-- no banner
|
|
||||||
return "no banner"
|
|
||||||
end
|
end
|
||||||
if fc == 421 or (fc >= 500 and fc <= 599) then
|
if code < 200 or code > 299 then
|
||||||
socket:close()
|
socket:close()
|
||||||
-- return "server says you are not allowed to create connection"
|
return nil
|
||||||
return
|
|
||||||
end
|
|
||||||
if fc < 200 or fc > 299 then
|
|
||||||
socket:close()
|
|
||||||
-- bad code
|
|
||||||
-- return "bad banner (code " .. fc .. ")"
|
|
||||||
return
|
|
||||||
end
|
end
|
||||||
|
|
||||||
socket:set_timeout(5000)
|
socket:set_timeout(5000)
|
||||||
-- USER
|
-- USER
|
||||||
socket:send("USER " .. user .. "\r\n")
|
local status, code, message = ftp.auth(socket, buffer, user, pass)
|
||||||
fc = get_ftp_code(socket)
|
if not status then
|
||||||
if (fc >= 400 and fc <= 499) or (fc >= 500 and fc <= 599) then
|
stdnse.debug1("Authentication rejected: %s %s", code or "socket", message)
|
||||||
socket:close()
|
ftp.close(socket)
|
||||||
-- bad code
|
return nil
|
||||||
--return "anonymous user not allowed"
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if fc == 0 then
|
|
||||||
socket:close()
|
|
||||||
-- return "anonymous user timeouted"
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if fc ~= 230 and fc ~= 331 then
|
|
||||||
socket:close()
|
|
||||||
-- bad code
|
|
||||||
-- return "bad response for anonymous user (code " .. fc .. ")"
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if fc == 230 then
|
|
||||||
sendPass = false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- PASS
|
-- PORT highport
|
||||||
if sendPass then
|
|
||||||
socket:send("PASS " .. pass .. "\r\n")
|
|
||||||
fc = get_ftp_code(socket)
|
|
||||||
if (fc >= 500 and fc <= 599) or (fc >= 400 and fc <= 499) then
|
|
||||||
socket:close()
|
|
||||||
-- bad code
|
|
||||||
-- return "anonymous user/pass rejected"
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if fc == 0 then
|
|
||||||
socket:close()
|
|
||||||
-- return "anonymous pass timeouted"
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if fc ~= 230 and fc ~= 200 then
|
|
||||||
socket:close()
|
|
||||||
-- return "answer to PASS not understood (code " .. fc .. ")"
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- PORT scanme.nmap.com:highport
|
|
||||||
local portfmt = get_portfmt()
|
local portfmt = get_portfmt()
|
||||||
-- This is actually port 256*80 + 80 = 20560
|
-- This is actually port 256*80 + 80 = 20560
|
||||||
socket:send(string.format(portfmt, "80,80"))
|
if not socket:send(string.format(portfmt, "80,80")) then
|
||||||
fc = get_ftp_code(socket)
|
stdnse.debug1("Can't send PORT")
|
||||||
if (fc >= 500 and fc <= 599) then
|
return nil
|
||||||
socket:close()
|
end
|
||||||
|
code, message = ftp.read_reply(buffer)
|
||||||
|
if not code then
|
||||||
|
stdnse.debug1("Error after PORT: %s", message)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if code < 200 or code > 299 then
|
||||||
|
stdnse.verbose1("PORT response: %d %s", code, message)
|
||||||
|
ftp.close(socket)
|
||||||
-- return "server forbids bouncing"
|
-- return "server forbids bouncing"
|
||||||
return
|
return nil
|
||||||
end
|
|
||||||
if fc == 0 then
|
|
||||||
socket:close()
|
|
||||||
-- return "PORT command timeouted"
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if not (fc >= 200 and fc<=299) then
|
|
||||||
socket:close()
|
|
||||||
-- return "PORT response not understood (code " .. fc .. ")"
|
|
||||||
return
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- PORT scanme.nmap.com:lowport
|
-- PORT lowport
|
||||||
socket:send(string.format(portfmt, "0,80"))
|
if not socket:send(string.format(portfmt, "0,80")) then
|
||||||
fc = get_ftp_code(socket)
|
stdnse.debug1("Can't send PORT")
|
||||||
if (fc >= 500 and fc <= 599) then
|
return nil
|
||||||
socket:close()
|
end
|
||||||
|
code, message = ftp.read_reply(buffer)
|
||||||
|
if not code then
|
||||||
|
stdnse.debug1("Error after PORT: %s", message)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if code < 200 or code > 299 then
|
||||||
|
stdnse.verbose1("PORT (low port) response: %d %s", code, message)
|
||||||
|
ftp.close(socket)
|
||||||
return "server forbids bouncing to low ports <1025"
|
return "server forbids bouncing to low ports <1025"
|
||||||
end
|
end
|
||||||
if fc == 0 then
|
|
||||||
socket:close()
|
|
||||||
-- return "PORT command timeouted for low port"
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if not (fc >= 200 and fc<=299) then
|
|
||||||
socket:close()
|
|
||||||
-- return "PORT response not understood for low port (code " .. fc .. ")"
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
socket:close()
|
ftp.close(socket)
|
||||||
return "bounce working!"
|
return "bounce working!"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user