/usr/share/nmap/scripts/telnet-brute.nse is in nmap 5.21-1.1ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | description = [[
Tries to get Telnet login credentials by guessing usernames and passwords.
Update (Ron Bowes, November, 2009): Now uses unpwdb database.
]]
author = 'Eddie Bell, Ron Bowes'
license = 'Same as Nmap--See http://nmap.org/book/man-legal.html'
categories = {'auth', 'intrusive'}
require('shortport')
require('stdnse')
require('strbuf')
require('comm')
require('unpwdb')
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
---
-- 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, soc)
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, soc)
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, soc)
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, soc)
end
results = string.lower(results)
for line in results:gmatch '[^\r\n]+' do
ret, value, usent = brute_line(line, user, pass, usent, soc)
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
local user, pass, count, rbuf
local usernames, passwords
status, usernames = unpwdb.usernames()
if(not(status)) then
stdnse.format_output(false, usernames)
end
status, passwords = unpwdb.passwords()
if(not(status)) then
return stdnse.format_output(false, passwords)
end
pair = nil
status = 3
count = 0
local opts = {timeout=4000}
local soc, line, best_opt = comm.tryssl(host, port, "\n",opts)
if not soc then
return stdnse.format_output(false, "Unable to open connection")
end
-- continually try user/pass pairs (reconnecting, if we have to)
-- until we find a valid one or we run out of pairs
pass = passwords()
while not (status == 1) do
if status == 2 or status == 3 then
user = usernames()
if(not(user)) then
usernames('reset')
user = usernames()
pass = passwords()
if(not(pass)) then
return stdnse.format_output(true, "No accounts found")
end
end
stdnse.print_debug(2, "telnet-brute: Trying %s/%s", user, pass)
end
-- make sure we don't get stuck in a loop
if status == 4 then
count = count + 1
if count > 3 then
return false, nil
end
else
count = 0
end
if status == 3 or status == 4 then
try(soc:connect(host.ip, port.number, best_opt))
end
status, pair = brute_cred(user, pass, soc)
end
soc:close()
return pair
end
|