home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Hackers Magazine 57
/
CdHackersMagazineNr57.iso
/
Software
/
Networking
/
nmap-5.00-setup.exe
/
scripts
/
telnet-brute.nse
< prev
next >
Wrap
Text File
|
2009-07-06
|
5KB
|
217 lines
description = [[
Tries to get Telnet login credentials by guessing usernames and passwords.
]]
author = 'Eddie Bell <ejlbell@gmail.com>'
license = 'Same as Nmap--See http://nmap.org/book/man-legal.html'
categories = {'auth', 'intrusive'}
require('shortport')
require('stdnse')
require('strbuf')
local soc
local catch = function() soc:close() end
local try = nmap.new_try(catch)
portrule = shortport.port_or_service(23, 'telnet')
local escape_cred = function(cred)
if cred == '' then
return '<blank>'
else
return cred
end
end
---
-- Returns a function which returns the next user/pass pair each time
-- it is called. When no more pairs are available nil is returned.
--
-- There are plenty more possible pairs but we need to find
-- a compromise between speed and coverage
--@return iterator Function which will return user and password pairs.
local new_auth_iter = function()
local userpass = {
-- guest
{'guest', ''}, {'guest', 'guest'}, {'guest', 'visitor'},
-- root
{'root', ''}, {'root', 'root'},
{'root', 'pass'}, {'root', 'password'},
-- admin
{'admin', ''}, {'admin', 'admin'},
{'admin', 'pass'}, {'admin', 'password'},
-- adminstrator
{'adminstrator', ''}, {'adminstrator', 'adminstrator'},
{'adminstrator', 'password'}, {'adminstrator', 'pass'},
-- others
{'visitor', ''}, {'netman', 'netman'}, {'Admin', 'Admin'},
{'manager', 'manager'}, {'security', 'security'},
{'username', 'password'}, {'user', 'pass'},
-- sentinel
{nil, nil}
}
local i = 1
return function(direction)
if not userpass[i][1] then
return
end
i = i + 1
stdnse.print_debug(3, "%s %s:%s", filename, userpass[i-1][1], escape_cred(userpass[i-1][2]))
return userpass[i-1][1], userpass[i-1][2]
end
end
---
-- Go through telnet's option palaver so we can get to the login prompt.
-- We just deny every options the server asks us about.
local negotiate_options = function(result)
local index, x, opttype, opt, retbuf
index = 0
retbuf = strbuf.new()
while true do
-- 255 is IAC (Interpret As Command)
index, x = string.find(result, '\255', index)
if not index then
break
end
opttype = string.byte(result, index+1)
opt = string.byte(result, index+2)
-- don't want it! won't do it!
if opttype == 251 or opttype == 252 then
opttype = 254
elseif opttype == 253 or opttype == 254 then
opttype = 252
end
retbuf = retbuf .. string.char(255)
retbuf = retbuf .. string.char(opttype)
retbuf = retbuf .. string.char(opt)
index = index + 1
end
soc:send(strbuf.dump(retbuf))
end
---
-- A semi-state-machine that takes action based on output from the
-- server. Through pattern matching, it tries to deem if a user/pass
-- pair is valid. Telnet does not have a way of telling the client
-- if it was authenticated....so we have to make an educated guess
local brute_line = function(line, user, pass, usent)
if (line:find 'incorrect' or line:find 'failed' or line:find 'denied' or
line:find 'invalid' or line:find 'bad') and usent then
usent = false
return 2, nil, usent
elseif (line:find '[/>%%%$#]+' or line:find "last login%s*:" or
line:find '%u:\\') and not
(line:find 'username%s*:' and line:find 'login%s*:') and
usent then
return 1, escape_cred(user) .. ' - ' .. escape_cred(pass) .. '\n', usent
elseif line:find 'username%s*:' or line:find 'login%s*:' then
try(soc:send(user .. '\r\0'))
usent = true
elseif line:find 'password%s*:' or line:find 'passcode%s*:' then
-- fix, add 'password only' support
if not usent then return 1, nil, usent end
try(soc:send(pass .. '\r\0'))
end
return 0, nil, usent
end
--[[
Splits the input into lines and passes it to brute_line()
so it can try to login with <user> and <pass>
return value:
(1, user:pass) - valid pair
(2, nil) - invalid pair
(3, nil) - disconnected and invalid pair
(4, nil) - disconnected and didn't send pair
--]]
local brute_cred = function(user, pass)
local status, ret, value, usent, results
usent = false ; ret = 0
while true do
status, results = soc:receive_lines(1)
-- remote host disconnected
if not status then
if usent then return 3
else return 4
end
end
if (string.byte(results, 1) == 255) then
negotiate_options(results)
end
results = string.lower(results)
for line in results:gmatch '[^\r\n]+' do
ret, value, usent = brute_line(line, user, pass, usent)
if (ret > 0) then
return ret, value
end
end
end
return 1, "error -> this should never happen"
end
action = function(host, port)
local pair, status, auth_iter
local user, pass, count, rbuf
pair = nil ; status = 3 ; count = 0
auth_iter = new_auth_iter();
soc = nmap.new_socket()
soc:set_timeout(4000)
-- continually try user/pass pairs (reconnecting, if we have to)
-- until we find a valid one or we run out of pairs
while not (status == 1) do
if status == 2 or status == 3 then
user, pass = auth_iter()
end
-- make sure we don't get stuck in a loop
if status == 4 then
count = count + 1
if count > 3 then return nil end
else count = 0 end
-- no more users left
if not user then break end
if status == 3 or status == 4 then
try(soc:connect(host.ip, port.number, port.protocol))
end
status, pair = brute_cred(user, pass)
end
soc:close()
return pair
end