mirror of
https://github.com/nmap/nmap.git
synced 2026-08-04 14:49:29 +00:00
Brute and unpwdb lib improvements that allow more flexible iterator specifications. Merge from my dev branch.
This commit is contained in:
parent
6dd99f410b
commit
c6ed7023c4
5 changed files with 114 additions and 58 deletions
|
|
@ -1,5 +1,8 @@
|
|||
# Nmap Changelog ($Id$); -*-text-*-
|
||||
|
||||
o [NSE] Added changes to brute and unpwdb libraries to allow more flexible iterator
|
||||
specification and control. [Aleksandar Nikolic]
|
||||
|
||||
o [NSE] Added ms-sql-dac script which queries the Microsoft SQL Browser service
|
||||
for the DAC (Dedicated Admin Connection) port. [Patrik Karlsson]
|
||||
|
||||
|
|
|
|||
112
nselib/brute.lua
112
nselib/brute.lua
|
|
@ -409,7 +409,9 @@ Engine =
|
|||
counter = 0,
|
||||
threads = {},
|
||||
tps = {},
|
||||
iterators = {},
|
||||
iterator = nil ,
|
||||
usernames = usernames_iterator(),
|
||||
passwords = passwords_iterator(),
|
||||
found_accounts = {},
|
||||
account_guesses = {},
|
||||
options = Options:new(),
|
||||
|
|
@ -420,11 +422,18 @@ Engine =
|
|||
return o
|
||||
end,
|
||||
|
||||
--- Adds an iterator to the list
|
||||
--
|
||||
-- @param iterator function to add to the list
|
||||
addIterator = function( self, iterator )
|
||||
table.insert( self.iterators, iterator )
|
||||
--- Sets the username iterator
|
||||
--
|
||||
-- @param usernameIterator function to set as a username iterator
|
||||
setUsernameIterator = function(self,usernameIterator)
|
||||
self.usernames = usernameIterator
|
||||
end,
|
||||
|
||||
--- Sets the password iterator
|
||||
--
|
||||
-- @param passwordIterator function to set as a password iterator
|
||||
setPasswordIterator = function(self,passwordIterator)
|
||||
self.passwords = passwordIterator
|
||||
end,
|
||||
|
||||
--- Limit the number of worker threads
|
||||
|
|
@ -464,15 +473,12 @@ Engine =
|
|||
-- @return iterator function
|
||||
get_next_credential = function( self )
|
||||
local function next_credential ()
|
||||
-- iterate over all credential iterators
|
||||
for _, iter in ipairs( self.iterators ) do
|
||||
for user, pass in iter do
|
||||
-- makes sure the credentials have not been tested before
|
||||
self.used_creds = self.used_creds or {}
|
||||
if ( not(self.used_creds[user..pass]) ) then
|
||||
self.used_creds[user..pass] = true
|
||||
coroutine.yield( user, pass )
|
||||
end
|
||||
for user, pass in self.iterator do
|
||||
-- makes sure the credentials have not been tested before
|
||||
self.used_creds = self.used_creds or {}
|
||||
if ( not(self.used_creds[user..pass]) ) then
|
||||
self.used_creds[user..pass] = true
|
||||
coroutine.yield( user, pass )
|
||||
end
|
||||
end
|
||||
while true do coroutine.yield(nil, nil) end
|
||||
|
|
@ -641,13 +647,9 @@ Engine =
|
|||
if( not(status) ) then return false, response end
|
||||
end
|
||||
|
||||
local status, usernames = unpwdb.usernames()
|
||||
if ( not(status) ) then return false, "Failed to load usernames" end
|
||||
local usernames = self.usernames
|
||||
local passwords = self.passwords
|
||||
|
||||
-- make sure we have a valid pw file
|
||||
local status, passwords = unpwdb.passwords()
|
||||
if ( not(status) ) then return false, "Failed to load passwords" end
|
||||
|
||||
local mode = self.options.mode or stdnse.get_script_args("brute.mode")
|
||||
|
||||
-- if no mode was given, but a credfile is present, assume creds mode
|
||||
|
|
@ -666,8 +668,8 @@ Engine =
|
|||
return coroutine.wrap(next_user)
|
||||
end
|
||||
-- only add this iterator if no other iterator was specified
|
||||
if ( #self.iterators == 0 ) then
|
||||
table.insert( self.iterators, Iterators.user_pw_iterator( single_user_iter(), passwords ) )
|
||||
if self.iterator == nil then
|
||||
self.iterator = Iterators.user_pw_iterator( single_user_iter(), passwords )
|
||||
end
|
||||
elseif ( mode == 'creds' ) then
|
||||
local credfile = stdnse.get_script_args("brute.credfile")
|
||||
|
|
@ -680,22 +682,22 @@ Engine =
|
|||
return false, ("Failed to open credfile (%s)"):format(credfile)
|
||||
end
|
||||
|
||||
table.insert( self.iterators, Iterators.credential_iterator( f ) )
|
||||
self.iterator = Iterators.credential_iterator( f )
|
||||
elseif ( mode and mode == 'user' ) then
|
||||
table.insert( self.iterators, Iterators.user_pw_iterator( usernames, passwords ) )
|
||||
self.iterator = Iterators.user_pw_iterator( usernames, passwords )
|
||||
elseif( mode and mode == 'pass' ) then
|
||||
table.insert( self.iterators, Iterators.pw_user_iterator( usernames, passwords ) )
|
||||
self.iterator = Iterators.pw_user_iterator( usernames, passwords )
|
||||
elseif ( mode ) then
|
||||
return false, ("Unsupported mode: %s"):format(mode)
|
||||
-- Default to the pw_user_iterator in case no iterator was specified
|
||||
elseif ( 0 == #self.iterators ) then
|
||||
table.insert( self.iterators, Iterators.pw_user_iterator( usernames, passwords ) )
|
||||
elseif ( self.iterator == nil ) then
|
||||
self.iterator = Iterators.pw_user_iterator( usernames, passwords )
|
||||
end
|
||||
|
||||
if ( ( not(mode) or mode == 'user' or mode == 'pass' ) and self.options.useraspass ) then
|
||||
-- if we're only guessing passwords, this doesn't make sense
|
||||
if ( not(self.options.passonly) ) then
|
||||
table.insert( self.iterators, 1, Iterators.pw_same_as_user_iterator(usernames, "lower"))
|
||||
self.iterator = unpwdb.concat_iterators(Iterators.pw_same_as_user_iterator(usernames, "lower"),self.iterator)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -706,7 +708,7 @@ Engine =
|
|||
end
|
||||
return coroutine.wrap(next_pass)
|
||||
end
|
||||
table.insert( self.iterators, 1, Iterators.account_iterator(usernames, empty_pass_iter(), mode or "pass"))
|
||||
self.iterator = Iterators.account_iterator(usernames, empty_pass_iter(), mode or "pass")
|
||||
end
|
||||
|
||||
|
||||
|
|
@ -775,6 +777,22 @@ Engine =
|
|||
|
||||
}
|
||||
|
||||
--- Default username iterator that uses unpwdb
|
||||
--
|
||||
usernames_iterator = function()
|
||||
local status, usernames = unpwdb.usernames()
|
||||
if ( not(status) ) then return "Failed to load usernames" end
|
||||
return usernames
|
||||
end
|
||||
|
||||
--- Default password iterator that uses unpwdb
|
||||
--
|
||||
passwords_iterator = function()
|
||||
local status, passwords = unpwdb.passwords()
|
||||
if ( not(status) ) then return "Failed to load passwords" end
|
||||
return passwords
|
||||
end
|
||||
|
||||
Iterators = {
|
||||
|
||||
--- Iterates over each user and password
|
||||
|
|
@ -787,7 +805,13 @@ Iterators = {
|
|||
account_iterator = function(users, pass, mode)
|
||||
local function next_credential ()
|
||||
local outer, inner
|
||||
|
||||
if "table" == type(users) then
|
||||
users = unpwdb.table_iterator(users)
|
||||
end
|
||||
if "table" == type(pass) then
|
||||
pass = unpwdb.table_iterator(pass)
|
||||
end
|
||||
|
||||
if ( mode == 'pass' ) then
|
||||
outer, inner = pass, users
|
||||
elseif ( mode == 'user' ) then
|
||||
|
|
@ -796,27 +820,15 @@ Iterators = {
|
|||
return
|
||||
end
|
||||
|
||||
if ( 'table' == type(users) and 'table' == type(pass) ) then
|
||||
for _, o in ipairs(outer) do
|
||||
for _, i in ipairs(inner) do
|
||||
if ( mode == 'pass' ) then
|
||||
coroutine.yield( i, o )
|
||||
else
|
||||
coroutine.yield( o, i )
|
||||
end
|
||||
for o in outer do
|
||||
for i in inner do
|
||||
if ( mode == 'pass' ) then
|
||||
coroutine.yield( i, o )
|
||||
else
|
||||
coroutine.yield( o, i )
|
||||
end
|
||||
end
|
||||
elseif ( 'function' == type(users) and 'function' == type(pass) ) then
|
||||
for o in outer do
|
||||
for i in inner do
|
||||
if ( mode == 'pass' ) then
|
||||
coroutine.yield( i, o )
|
||||
else
|
||||
coroutine.yield( o, i )
|
||||
end
|
||||
end
|
||||
inner("reset")
|
||||
end
|
||||
inner("reset")
|
||||
end
|
||||
while true do coroutine.yield(nil, nil) end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ local filltable = function(filename, table)
|
|||
return true
|
||||
end
|
||||
|
||||
local closure = function(table)
|
||||
table_iterator = function(table)
|
||||
local i = 1
|
||||
|
||||
return function(cmd)
|
||||
|
|
@ -187,7 +187,7 @@ local usernames_raw = function()
|
|||
return false, "Error parsing username list"
|
||||
end
|
||||
|
||||
return true, closure(usertable)
|
||||
return true, table_iterator(usertable)
|
||||
end
|
||||
|
||||
--- Returns a function closure which returns a new password with every call
|
||||
|
|
@ -206,7 +206,7 @@ local passwords_raw = function()
|
|||
return false, "Error parsing password list"
|
||||
end
|
||||
|
||||
return true, closure(passtable)
|
||||
return true, table_iterator(passtable)
|
||||
end
|
||||
|
||||
--- Wraps time and count limits around an iterator. When either limit expires,
|
||||
|
|
@ -286,4 +286,41 @@ passwords = function(time_limit, count_limit)
|
|||
return true, limited_iterator(iterator, time_limit, count_limit)
|
||||
end
|
||||
|
||||
--- Returns a new iterator that iterates trough it's consecutive iterators,
|
||||
-- basically concatenating them.
|
||||
-- @param iter1 First iterator to concatenate.
|
||||
-- @param iter2 Second iterator to concatenate.
|
||||
-- @return function The concatenated iterators.
|
||||
concat_iterators = function(iter1, iter2)
|
||||
s return function(cmd)
|
||||
if cmd == "reset" then
|
||||
iter1("reset")
|
||||
iter2("reset")
|
||||
return
|
||||
end
|
||||
local v1 = {iter1(cmd)}
|
||||
if not (next(v1) == nil) then
|
||||
return table.unpack(v1)
|
||||
end
|
||||
local v2 = {iter2(cmd)}
|
||||
if not (next(v2) == nil) then
|
||||
return table.unpack(v2)
|
||||
end
|
||||
return iter1(cmd)
|
||||
end
|
||||
end
|
||||
|
||||
--- Returns a new iterator that filters it's results based on the filter.
|
||||
-- @param iterator Iterator that needs to be filtered
|
||||
-- @param filter Function that returns bool, which serves as a filter
|
||||
-- @return function The filtered iterator.
|
||||
filter_iterator = function(iterator, filter)
|
||||
return function(cmd)
|
||||
local result = {iterator(cmd)}
|
||||
if filter(table.unpack(result)) then
|
||||
return result
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return _ENV;
|
||||
|
|
|
|||
|
|
@ -31,8 +31,10 @@ With knowledge of the correct repository name, usernames and passwords can be gu
|
|||
-- @args cvs-brute-repository.repofile a file containing a list of repositories
|
||||
-- to guess
|
||||
|
||||
-- Version 0.1
|
||||
-- Version 0.2
|
||||
-- Created 07/13/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
|
||||
-- Revised 08/07/2012 - v0.2 - revised to suit the changes in brute
|
||||
-- library [Aleksandar Nikolic]
|
||||
|
||||
author = "Patrik Karlsson"
|
||||
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||
|
|
@ -102,7 +104,7 @@ action = function(host, port)
|
|||
end
|
||||
end
|
||||
|
||||
local repository_iterator = function()
|
||||
repository_iterator = function()
|
||||
local function next_repo()
|
||||
for line in f:lines() do
|
||||
if ( not(line:match("#!comment")) ) then
|
||||
|
|
@ -119,8 +121,8 @@ action = function(host, port)
|
|||
engine.options.passonly = true
|
||||
engine.options.firstonly = false
|
||||
engine.options.nostore = true
|
||||
engine:addIterator(brute.Iterators.account_iterator({""}, repos, "user"))
|
||||
if ( repofile ) then engine:addIterator(repository_iterator()) end
|
||||
engine.iterator = brute.Iterators.account_iterator({""}, repos, "user")
|
||||
if ( repofile ) then engine.iterator = unpwdb.concat_iterators(engine.iterator,repository_iterator()) end
|
||||
status, result = engine:start()
|
||||
|
||||
return result
|
||||
|
|
|
|||
|
|
@ -57,6 +57,8 @@ result in a large number of accounts being locked out on the database server.
|
|||
-- changed code to use ConnectionPool
|
||||
-- Revised 03/13/2012 - v0.4 - revised by László Tóth
|
||||
-- added support for SYSDBA accounts
|
||||
-- Revised 08/07/2012 - v0.5 - revised to suit the changes in brute
|
||||
-- library [Aleksandar Nikolic]
|
||||
|
||||
--
|
||||
-- Summary
|
||||
|
|
@ -213,7 +215,7 @@ action = function(host, port)
|
|||
return ("\n ERROR: Failed to open %s"):format(DEFAULT_ACCOUNTS)
|
||||
end
|
||||
|
||||
engine:addIterator(brute.Iterators.credential_iterator(f))
|
||||
engine.iterator = brute.Iterators.credential_iterator(f)
|
||||
end
|
||||
|
||||
engine.options.script_name = SCRIPT_NAME
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue