mirror of
https://github.com/nmap/nmap.git
synced 2026-10-20 19:01:56 +00:00
Improved anonymous ftp detection. Now supports ACCT and has improved parsing of server responses.
This commit is contained in:
parent
3a0aa06db1
commit
565d6a524d
1 changed files with 87 additions and 16 deletions
|
|
@ -4,9 +4,12 @@ Checks if an FTP server allows anonymous logins.
|
|||
|
||||
---
|
||||
-- @output
|
||||
-- |_ ftp-anon: Anonymous FTP login allowed
|
||||
--- Default behavior
|
||||
-- PORT STATE SERVICE
|
||||
-- 21/tcp open ftp
|
||||
-- |_ftp-anon: Anonymous FTP login allowed (FTP code 230)
|
||||
|
||||
author = "Eddie Bell"
|
||||
author = "Eddie Bell, Rob Nicholls, Ange Gutek, David Fifield"
|
||||
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||
categories = {"default", "auth", "safe"}
|
||||
|
||||
|
|
@ -14,35 +17,103 @@ require "shortport"
|
|||
|
||||
portrule = shortport.port_or_service(21, "ftp")
|
||||
|
||||
-- Read an FTP reply and return the numeric code and the message. See RFC 959,
|
||||
-- section 4.2. The buffer argument should have been created with
|
||||
-- stdnse.make_buffer(socket, "\r?\n"). On error, returns nil and an error
|
||||
-- message.
|
||||
local function read_reply(buffer)
|
||||
local readline
|
||||
local line, err
|
||||
local code, message
|
||||
local _, p, tmp
|
||||
|
||||
line, err = buffer()
|
||||
if not line then
|
||||
return line, err
|
||||
end
|
||||
|
||||
-- Single-line response?
|
||||
code, message = string.match(line, "^(%d%d%d) (.*)$")
|
||||
if code then
|
||||
return tonumber(code), message
|
||||
end
|
||||
|
||||
-- Multi-line response?
|
||||
_, p, code, message = string.find(line, "^(%d%d%d)-(.*)$")
|
||||
if p then
|
||||
while true do
|
||||
line, err = buffer()
|
||||
if not line then
|
||||
return line, err
|
||||
end
|
||||
tmp = string.match(line, "^%d%d%d (.*)$")
|
||||
if tmp then
|
||||
message = message .. "\n" .. tmp
|
||||
break
|
||||
end
|
||||
message = message .. "\n" .. line
|
||||
end
|
||||
|
||||
return tonumber(code), message
|
||||
end
|
||||
|
||||
return nil, string.format("Unparseable response: %q", line)
|
||||
end
|
||||
|
||||
|
||||
--- Connects to the FTP server and checks if the server allows anonymous logins.
|
||||
action = function(host, port)
|
||||
local socket = nmap.new_socket()
|
||||
local result
|
||||
local status = true
|
||||
local isAnon = false
|
||||
|
||||
local code, message
|
||||
local err_catch = function()
|
||||
socket:close()
|
||||
end
|
||||
|
||||
local try = nmap.new_try(err_catch)
|
||||
|
||||
socket:set_timeout(5000)
|
||||
try(socket:connect(host.ip, port.number, port.protocol))
|
||||
try(socket:send("USER anonymous\r\n"))
|
||||
try(socket:send("PASS IEUser@\r\n"))
|
||||
buffer = stdnse.make_buffer(socket, "\r?\n")
|
||||
|
||||
while status do
|
||||
status, result = socket:receive_lines(1);
|
||||
if string.match(result, "^230") then
|
||||
isAnon = true
|
||||
break
|
||||
-- Read banner.
|
||||
code, message = read_reply(buffer)
|
||||
if code and code == 220 then
|
||||
try(socket:send("USER anonymous\r\n"))
|
||||
code, message = read_reply(buffer)
|
||||
if code == 331 then
|
||||
-- 331: User name okay, need password.
|
||||
try(socket:send("PASS IEUser@\r\n"))
|
||||
code, message = read_reply(buffer)
|
||||
end
|
||||
|
||||
if code == 332 then
|
||||
-- 332: Need account for login.
|
||||
-- This is rarely seen but may come in response to a
|
||||
-- USER or PASS command. As we're doing this
|
||||
-- anonymously, send back a blank ACCT.
|
||||
try(socket:send("ACCT\r\n"))
|
||||
code, message = read_reply(buffer)
|
||||
if code == 331 then
|
||||
-- 331: User name okay, need password.
|
||||
try(socket:send("PASS IEUser@\r\n"))
|
||||
code, message = read_reply(buffer)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
socket:close()
|
||||
|
||||
if(isAnon) then
|
||||
return "Anonymous FTP login allowed"
|
||||
if code and code >= 200 and code < 300 then
|
||||
-- We are primarily looking for 230: User logged in, proceed.
|
||||
return "Anonymous FTP login allowed (FTP code " .. code .. ")"
|
||||
elseif code == 421 then
|
||||
-- 421: Service not available, closing control connection.
|
||||
elseif code == 530 then
|
||||
-- 530: Not logged in.
|
||||
else
|
||||
if not code then
|
||||
stdnse.print_debug(1, "ftp-anon: got socket error %q.", message)
|
||||
else
|
||||
stdnse.print_debug(1, "ftp-anon: got code %d %q.", code, message)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue