Nmap Development mailing list archives
Re: Suspect that --host-timeout is not working in 4.50?
From: jah <jah () zadkiel plus com>
Date: Fri, 21 Dec 2007 03:00:00 +0000
On 16/12/2007 04:08, Randolph Reitz wrote:
So there are two issues here. One, the script doesn't obey --host-timeout and Two, there's a bug, I think, in bruteTelnet. Can anyone shed any light on the first? Are NSE scripts supposed to obey --host-timeout? Is there a way for the script to get that information from nmap api?On Dec 15, 2007, at 3:03 PM, jah wrote:On 15/12/2007 00:34, Randolph Reitz wrote:I've got a feeling that one of the scripts running during the above scan you gave as an example is causing a problem for you (either bruteTelnet or anonFTP), would you mind running the following similar scan:[scanner@clouseau ~]$ nmap -d -sS -F --host_timeout 1m -A 131.225.136.140nmap -sS -p21,23 --script=bruteTelnet,anonFTP --script-trace -d3 --log-errors 131.225.136.140I'm not sure whether nse scripts are meant to obey host-timeout rules or not, but neither of these scripts should take very long, certainly not the times you're seeing and using script-trace should help identify what is causing the massive delay.Regards, jahHi, I ran the nmap command for ~11 minutes and the output file is ... [scanner@clouseau ~]$ ls -lt | head total 2231076 -rw-rw-r-- 1 scanner scanner 2207219285 Dec 15 21:52 namp_test.outWow, that's big. Looks like a loop that never ends. Here is the first minute ...-- This email has been verified as Virus free Virus Protection and more available at http://www.plus.netThere is no firewall at the Fermilab border, so you can run the command if you wish.
On the second, some observations from playing with the script.The failure occurs when the 10th user and/or pass has been tried at which point the output from NSOCK goes crazy outputting nearly 160000 lines every second:
NSOCK (212.6570s) nsock_loop() started (timeout=50ms). 0 events pendingIt doesn't take many seconds to have a several gigabyte file when piping nmaps output!
Using Wireshark, I was able to determine that the script opens a new socket for each login attempt (rather than using the available number of login attempts (in this case 2) and reconnecting once the telnet server breaks the connection). The script never closes any (well, maybe just the one) connections that it creates (until script conclusion or a forced abort whereupon RST, ACKs are sent) and I assume that it runs out of the 10 allowed sockets available to the script.
I've attached a patch (and the modified script too for Randys benefit) that hopefully closes each socket after an unsuccessful login attempt, but try as I might, I cannot sort out the business of utilising remaining login attempts in a given connection... perhaps someone with more nouse will have a go.
Just for extra info, in a given connection, Randys server seems to ask for a username and then appears to validate it and doesn't prompt for a password:
login: then responds with the following after an unsuccessful login: Login incorrect\r\n login: and then: Login incorrect\r\nThis script could be much faster if it would utilise that remaining login attempt because it would (in this case) halve the number of times needed to 'negotiate options' - about 14 secs each time. Finally, if these are indeed usernames that are requested, the script ought to be able to move to the next username in the userpass table rather than repeating the username for each user:pass pair. In this case, it tries 'guest' 3 times, 'root' 4 times, 'admin' ...
jah
id='bruteforce' author = 'Eddie Bell <ejlbell () gmail com>' description='brute force telnet login credientials' license = 'See nmaps COPYING for licence' categories = {'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 --]] 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, id .. " " .. 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 soc:close() try(soc:connect(host.ip, port.number, port.protocol)) end status, pair = brute_cred(user, pass) end soc:close() return pair end
Index: bruteTelnet.nse =================================================================== --- bruteTelnet.nse (revision 6616) +++ bruteTelnet.nse (working copy) @@ -9,7 +9,7 @@ require('strbuf') local soc -local catch = function() soc.close() end +local catch = function() soc:close() end local try = nmap.new_try(catch) portrule = shortport.port_or_service(23, 'telnet') @@ -210,6 +210,7 @@ if not user then break end if status == 3 or status == 4 then + soc:close() try(soc:connect(host.ip, port.number, port.protocol)) end
_______________________________________________ Sent through the nmap-dev mailing list http://cgi.insecure.org/mailman/listinfo/nmap-dev Archived at http://SecLists.Org
Current thread:
- Suspect that --host-timeout is not working in 4.50? Randolph Reitz (Dec 14)
- Re: Suspect that --host-timeout is not working in 4.50? jah (Dec 14)
- Re: Suspect that --host-timeout is not working in 4.50? Randolph Reitz (Dec 15)
- Re: Suspect that --host-timeout is not working in 4.50? jah (Dec 15)
- Re: Suspect that --host-timeout is not working in 4.50? Randolph Reitz (Dec 16)
- Re: Suspect that --host-timeout is not working in 4.50? jah (Dec 20)
- Re: Suspect that --host-timeout is not working in 4.50? Fyodor (Dec 20)
- Re: Suspect that --host-timeout is not working in 4.50? doug (Dec 20)
- Re: Suspect that --host-timeout is not working in 4.50? Fyodor (Dec 20)
- Re: Suspect that --host-timeout is not working in 4.50? Fyodor (Dec 20)
- Re: Suspect that --host-timeout is not working in 4.50? doug (Dec 21)
- Re: Suspect that --host-timeout is not working in 4.50? Fyodor (Dec 21)
- Re: Suspect that --host-timeout is not working in 4.50? Randolph Reitz (Dec 15)
- Re: Suspect that --host-timeout is not working in 4.50? doug (Dec 20)
- Re: Suspect that --host-timeout is not working in 4.50? jah (Dec 14)