Overview
Performs brute force password auditing against FTP servers. Based on old ftp-brute.nse script by Diman Todorov, Vlatko Kosturjak and Ron Bowes.
Performs brute force password auditing against FTP servers.
Ports
Any
Protocols
n/a
Attribution
Nmap Project
Copy the command and adjust the target or script arguments as needed.
nmap --script ftp-brute -p 21 <host>
This script uses brute library to perform password
guessing. The full script source is stored with this entry and is hidden by default to keep the page easier to scan.
local brute = require "brute"
local creds = require "creds"
local shortport = require "shortport"
local stdnse = require "stdnse"
local ftp = require "ftp"
description = [[
Performs brute force password auditing against FTP servers.
Based on old ftp-brute.nse script by Diman Todorov, Vlatko Kosturjak and Ron Bowes.
]]
---
-- @see ftp-anon.nse
--
-- @usage
-- nmap --script ftp-brute -p 21 <host>
--
-- This script uses brute library to perform password
-- guessing.
--
-- @output
-- PORT STATE SERVICE
-- 21/tcp open ftp
-- | ftp-brute:
-- | Accounts
-- | root:root - Valid credentials
-- | Statistics
-- |_ Performed 510 guesses in 610 seconds, average tps: 0
--
-- @args ftp-brute.timeout the amount of time to wait for a response on the socket.
-- Lowering this value may result in a higher throughput for servers
-- having a delayed response on incorrect login attempts. (default: 5s)
-- 06.08.16 - Modified by Sergey Khegay to support new brute.lua adaptability mechanism.
author = "Aleksandar Nikolic"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"intrusive", "brute"}
portrule = shortport.port_or_service(21, "ftp")
local arg_timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME .. ".timeout"))
arg_timeout = (arg_timeout or 5) * 1000
Driver = {
new = function(self, host, port)
local o = {}
setmetatable(o, self)
self.__index = self
o.host = host
o.port = port
return o
end,
connect = function( self )
self.socket = brute.new_socket()
-- discard buffer, we'll create a new one over the BruteSocket later
local realsocket, code, message, buffer = ftp.connect(self.host, self.port, {request_timeout=arg_timeout})
if not realsocket then
return false, brute.Error:new( "Couldn't connect to host: " .. (code or message) )
end
if not code then
realsocket:close()
return false, brute.Error:new( "Invalid response from host: " .. message)
end
self.socket.socket = realsocket
if not (code >= 200 and code < 400) then
ftp.close(self.socket)
return false, brute.Error:new( "Error response from host: " .. code)
end
return true
end,
login = function (self, user, pass)
local buffer = stdnse.make_buffer(self.socket, "\r?\n")
local status, code, message = ftp.auth(self.socket, buffer, user, pass)
if not status then
if not code then
return false, brute.Error:new("socket error during login: " .. message)
elseif code == 530 then
return false, brute.Error:new( "Incorrect password" )
elseif code == 421 then
local err = brute.Error:new("Too many connections")
err:setReduce(true)
return false, err
else
stdnse.debug1("WARNING: Unhandled response: %d %s", code, message)
local err = brute.Error:new("Unhandled response")
err:setRetry(true)
return false, err
end
end
stdnse.debug1("Successful login: %s/%s", user, pass)
return true, creds.Account:new( user, pass, creds.State.VALID)
end,
disconnect = function( self )
ftp.close(self.socket)
return true
end
}
action = function( host, port )
local status, result
local engine = brute.Engine:new(Driver, host, port)
engine.options.script_name = SCRIPT_NAME
status, result = engine:start()
return result
end
Performs brute force password auditing against FTP servers. Based on old ftp-brute.nse script by Diman Todorov, Vlatko Kosturjak and Ron Bowes.