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 >
Text File  |  2009-07-06  |  5KB  |  217 lines

  1. description = [[
  2. Tries to get Telnet login credentials by guessing usernames and passwords.
  3. ]]
  4.  
  5. author = 'Eddie Bell <ejlbell@gmail.com>'
  6. license = 'Same as Nmap--See http://nmap.org/book/man-legal.html'
  7. categories = {'auth', 'intrusive'}
  8.  
  9. require('shortport')
  10. require('stdnse')
  11. require('strbuf')
  12.  
  13. local soc
  14. local catch = function() soc:close() end
  15. local try = nmap.new_try(catch)
  16.  
  17. portrule = shortport.port_or_service(23, 'telnet')
  18.  
  19. local escape_cred = function(cred) 
  20.     if cred == '' then
  21.         return '<blank>'
  22.     else
  23.         return cred 
  24.     end
  25. end
  26.  
  27. ---
  28. -- Returns a function which returns the next user/pass pair each time
  29. -- it is called. When no more pairs are available nil is returned. 
  30. --
  31. -- There are plenty more possible pairs but we need to find
  32. -- a compromise between speed and coverage
  33. --@return iterator Function which will return user and password pairs.
  34. local new_auth_iter = function()
  35.     local userpass = { 
  36.         -- guest
  37.         {'guest', ''}, {'guest', 'guest'}, {'guest', 'visitor'},
  38.  
  39.         -- root
  40.         {'root', ''}, {'root', 'root'}, 
  41.         {'root', 'pass'}, {'root', 'password'},
  42.  
  43.         -- admin
  44.         {'admin', ''}, {'admin', 'admin'},
  45.         {'admin', 'pass'}, {'admin', 'password'},
  46.  
  47.         -- adminstrator
  48.         {'adminstrator', ''}, {'adminstrator', 'adminstrator'},
  49.         {'adminstrator', 'password'}, {'adminstrator', 'pass'},
  50.         
  51.         -- others
  52.         {'visitor', ''}, {'netman', 'netman'}, {'Admin', 'Admin'},
  53.         {'manager', 'manager'}, {'security', 'security'},
  54.         {'username', 'password'}, {'user', 'pass'}, 
  55.  
  56.         -- sentinel 
  57.         {nil, nil}
  58.     }
  59.  
  60.     local i = 1 
  61.     return function(direction)
  62.         if not userpass[i][1] then 
  63.             return
  64.          end
  65.  
  66.         i = i + 1
  67.         stdnse.print_debug(3, "%s %s:%s", filename, userpass[i-1][1], escape_cred(userpass[i-1][2]))
  68.         return userpass[i-1][1], userpass[i-1][2]
  69.     end
  70. end
  71.  
  72. ---
  73. -- Go through telnet's option palaver so we can get to the login prompt.
  74. -- We just deny every options the server asks us about.
  75. local negotiate_options = function(result)
  76.     local index, x, opttype, opt, retbuf
  77.  
  78.     index = 0
  79.     retbuf = strbuf.new()
  80.  
  81.     while true do
  82.  
  83.         -- 255 is IAC (Interpret As Command)
  84.         index, x = string.find(result, '\255', index)
  85.  
  86.         if not index then 
  87.             break 
  88.         end
  89.  
  90.         opttype = string.byte(result, index+1)
  91.         opt = string.byte(result, index+2)
  92.  
  93.         -- don't want it! won't do it! 
  94.         if opttype == 251 or opttype == 252 then
  95.             opttype = 254
  96.         elseif opttype == 253 or opttype == 254 then
  97.             opttype = 252
  98.         end
  99.  
  100.         retbuf = retbuf .. string.char(255)
  101.         retbuf = retbuf .. string.char(opttype)
  102.         retbuf = retbuf .. string.char(opt)
  103.         index = index + 1
  104.     end    
  105.     soc:send(strbuf.dump(retbuf))
  106. end
  107.  
  108. ---
  109. -- A semi-state-machine that takes action based on output from the
  110. -- server. Through pattern matching, it tries to deem if a user/pass
  111. -- pair is valid. Telnet does not have a way of telling the client
  112. -- if it was authenticated....so we have to make an educated guess
  113. local brute_line = function(line, user, pass, usent)
  114.  
  115.     if (line:find 'incorrect' or line:find 'failed' or line:find 'denied' or 
  116.             line:find 'invalid' or line:find 'bad') and usent then
  117.         usent = false
  118.         return 2, nil, usent 
  119.  
  120.     elseif (line:find '[/>%%%$#]+' or line:find "last login%s*:" or
  121.             line:find '%u:\\') and not
  122.            (line:find 'username%s*:' and line:find 'login%s*:') and
  123.            usent then
  124.         return 1, escape_cred(user) .. ' - ' .. escape_cred(pass)  .. '\n', usent
  125.         
  126.     elseif line:find 'username%s*:' or line:find 'login%s*:' then
  127.         try(soc:send(user .. '\r\0'))
  128.         usent = true
  129.  
  130.     elseif line:find 'password%s*:' or line:find 'passcode%s*:' then
  131.         -- fix, add 'password only' support
  132.         if not usent then return 1, nil, usent end
  133.         try(soc:send(pass .. '\r\0'))
  134.     end
  135.  
  136.     return 0, nil, usent
  137. end
  138.  
  139. --[[
  140. Splits the input into lines and passes it to brute_line()
  141. so it can try to login with <user> and <pass>
  142.  
  143. return value: 
  144.     (1, user:pass)     - valid pair
  145.     (2, nil)      - invalid pair
  146.     (3, nil)       - disconnected and invalid pair
  147.     (4, nil)       - disconnected and didn't send pair
  148. --]]
  149.  
  150. local brute_cred = function(user, pass)
  151.     local status, ret, value, usent, results
  152.  
  153.     usent = false ; ret = 0
  154.  
  155.     while true do
  156.         status, results = soc:receive_lines(1)
  157.  
  158.         -- remote host disconnected
  159.         if not status then 
  160.             if usent then return 3 
  161.             else return 4 
  162.             end
  163.         end
  164.  
  165.         if (string.byte(results, 1) == 255) then
  166.             negotiate_options(results)
  167.         end
  168.  
  169.         results = string.lower(results)
  170.  
  171.         for line in results:gmatch '[^\r\n]+' do 
  172.             ret, value, usent = brute_line(line, user, pass, usent)
  173.             if (ret > 0) then
  174.                 return ret, value
  175.             end
  176.         end
  177.     end
  178.     return 1, "error -> this should never happen"
  179. end
  180.  
  181. action = function(host, port)
  182.     local pair, status, auth_iter 
  183.     local user, pass, count, rbuf
  184.     
  185.     pair = nil ; status = 3 ; count = 0
  186.     auth_iter = new_auth_iter(); 
  187.  
  188.     soc = nmap.new_socket()
  189.     soc:set_timeout(4000)
  190.  
  191.     -- continually try user/pass pairs (reconnecting, if we have to)
  192.     -- until we find a valid one or we run out of pairs
  193.     while not (status == 1) do
  194.  
  195.         if status == 2 or status == 3 then
  196.             user, pass = auth_iter() 
  197.         end
  198.  
  199.         -- make sure we don't get stuck in a loop
  200.         if status == 4 then
  201.             count = count + 1
  202.             if count > 3 then return nil end
  203.         else count = 0 end
  204.  
  205.         -- no more users left
  206.         if not user then break end
  207.  
  208.         if status == 3 or status == 4 then
  209.             try(soc:connect(host.ip, port.number, port.protocol))
  210.         end
  211.  
  212.         status, pair = brute_cred(user, pass)
  213.     end
  214.     soc:close()
  215.     return pair
  216. end
  217.