1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-27 01:49:03 +00:00

Added command line support to the creds library

Changed getCredentials to allow a bitmask filter
Changed getCredentials to return an iterator instead of a table
Modified the brute library to support the changes
[Patrik]
This commit is contained in:
patrik
2011-07-06 12:16:43 +00:00
parent b209bfbdfe
commit 3a3ae7ede1
2 changed files with 114 additions and 60 deletions

View File

@@ -256,13 +256,13 @@ Account =
--
-- @return string representation of object
toString = function( self )
local creds
local c
if ( #self.username > 0 ) then
creds = ("%s:%s"):format( self.username, #self.password > 0 and self.password or "<empty>" )
c = ("%s:%s"):format( self.username, #self.password > 0 and self.password or "<empty>" )
else
creds = ("%s"):format( ( self.password and #self.password > 0 ) and self.password or "<empty>" )
c = ("%s"):format( ( self.password and #self.password > 0 ) and self.password or "<empty>" )
end
return ( "%s => %s"):format(creds, self.state.msg )
return ( "%s => %s"):format(c, creds.StateMsg[self.state] )
end,
}
@@ -460,16 +460,16 @@ Engine =
return false
end
local creds
local c
-- Do we have a username or not?
if ( username and #username > 0 ) then
creds = ("%s/%s"):format(username, #password > 0 and password or "<empty>")
c = ("%s/%s"):format(username, #password > 0 and password or "<empty>")
else
creds = ("%s"):format(#password > 0 and password or "<empty>")
c = ("%s"):format(#password > 0 and password or "<empty>")
end
local msg = ( retries ~= self.options.max_retries ) and "Re-trying" or "Trying"
stdnse.print_debug(2, "%s %s against %s:%d", msg, creds, self.host.ip, self.port.number )
stdnse.print_debug(2, "%s %s against %s:%d", msg, c, self.host.ip, self.port.number )
status, response = driver:login( username, password )
driver:disconnect()
@@ -591,15 +591,15 @@ Engine =
if ( not(f) ) then
return false, ("Failed to open credfile (%s)"):format(credfile)
end
local creds = {}
local c = {}
for line in f:lines() do
local trim = function(s) return s:match('^()%s*$') and '' or s:match('^%s*(.*%S)') end
line = trim(line)
local user, pass = line:match("^([^%/]*)%/(.*)$")
table.insert(creds, { [user]=pass } )
table.insert(c, { [user]=pass } )
end
table.insert( self.iterators, Iterators.credential_iterator( creds ) )
table.insert( self.iterators, Iterators.credential_iterator( c ) )
elseif ( mode and mode == 'user' ) then
table.insert( self.iterators, Iterators.user_pw_iterator( usernames, passwords ) )
elseif( mode and mode == 'pass' ) then

View File

@@ -24,8 +24,8 @@
-- credentials:
-- <code>
-- local c = creds.Credentials:new(creds.ALL_DATA, host, port)
-- for _, cred in pairs(c:getCredentials(creds.State.VALID)) do
-- chowContentForUser(cred.user, cred.pass)
-- for cred in c:getCredentials(creds.State.VALID) do
-- showContentForUser(cred.user, cred.pass)
-- end
-- </code>
--
@@ -34,25 +34,39 @@
-- @author "Patrik Karlsson <patrik@cqure.net>"
-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html
-- Version 0.1
-- Version 0.3
-- Created 2011/02/06 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- Revised 2011/27/06 - v0.2 - revised by Patrik Karlsson <patrik@cqure.net>
-- added documentation
-- added getCredentials function
-- * added documentation
-- * added getCredentials function
--
-- Revised 2011/05/07 - v0.3 - revised by Patrik Karlsson <patrik@cqure.net>
-- * modified getCredentials to return an iterator
-- * added support for adding credentials as
-- script arguments
--
module(... or "creds", package.seeall)
require('ipOps')
require('bit')
-- Table containing the different account states
State = {
LOCKED = { msg = 'Account is locked' },
VALID = { msg = 'Account is valid' },
DISABLED = { msg = 'Account is disabled' },
CHANGEPW = { msg = 'Password needs to be changed at next logon' },
LOCKED = 1,
VALID = 2,
DISABLED = 4,
CHANGEPW = 8,
PARAM = 16,
}
StateMsg = {
[State.LOCKED] = 'Account is locked',
[State.VALID] = 'Account is valid',
[State.DISABLED] = 'Account is disabled',
[State.CHANGEPW] = 'Password needs to be changed at next logon',
}
ALL_DATA = "all_script_data"
-- The RegStorage class
@@ -103,37 +117,37 @@ RegStorage = {
self.filter.state = state
end,
--- Retrieves the table containing all credential records
--- Returns a credential iterator matching the selected filters
--
-- @return table containing all credential records
-- @return a credential iterator
getAll = function( self )
local tbl = nmap.registry.creds
local new_tbl = {}
local host, port = self.filter.host, self.filter.port
local function get_next()
local host, port = self.filter.host, self.filter.port
if ( not(tbl) ) then return end
if ( not(nmap.registry.creds) ) then return end
for _, v in pairs(tbl) do
local h = ( v.host.ip or v.host )
if ( not(host) and not(port) ) then
if ( not(self.filter.state) or ( v.state == self.filter.state ) ) then
table.insert(new_tbl, v)
end
elseif ( not(host) and ( port == v.port ) ) then
if ( not(self.filter.state) or ( v.state == self.filter.state ) ) then
table.insert(new_tbl, v)
end
elseif ( ( host and ( h == host or h == host.ip ) ) and not(port) ) then
if ( not(self.filter.state) or ( v.state == self.filter.state ) ) then
table.insert(new_tbl, v)
end
elseif ( ( host and ( h == host or h == host.ip ) ) and port.number == v.port ) then
if ( not(self.filter.state) or ( v.state == self.filter.state ) ) then
table.insert(new_tbl, v)
for _, v in pairs(nmap.registry.creds) do
local h = ( v.host.ip or v.host )
if ( not(host) and not(port) ) then
if ( not(self.filter.state) or ( v.state == self.filter.state ) ) then
coroutine.yield(v)
end
elseif ( not(host) and ( port == v.port ) ) then
if ( not(self.filter.state) or ( v.state == self.filter.state ) ) then
coroutine.yield(v)
end
elseif ( ( host and ( h == host or h == host.ip ) ) and not(port) ) then
if ( not(self.filter.state) or ( v.state == self.filter.state ) ) then
coroutine.yield(v)
end
elseif ( ( host and ( h == host or h == host.ip ) ) and port.number == v.port ) then
if ( not(self.filter.state) or ( v.state == bit.band(self.filter.state, v.state) ) ) then
coroutine.yield(v)
end
end
end
end
return new_tbl
return coroutine.wrap(get_next)
end,
}
@@ -160,9 +174,6 @@ Credentials = {
--- Add a discovered credential
--
-- @param host host table, name or ip
-- @param port number containing the port of the service
-- @param service the name of the service
-- @param user the name of the user
-- @param pass the password of the user
-- @param state of the account
@@ -180,24 +191,67 @@ Credentials = {
end
end,
--- Returns all accounts for a given state, or all states if no filter is set
--- Returns a credential iterator
--
-- @param state table containing a value from the <Code>State</code> table
-- @return table containing accounts matching the state, or all accounts if
-- no state was given. Accounts have the following fields:
-- @param state mask containing values from the <Code>State</code> table
-- @return credential iterator, returning a credential each time it's
-- called. Unless filtered by the state mask all credentials
-- for the host, port match are iterated over.
-- The credential table has the following fields:
-- <code>host</code> - table as received by the action function
-- <code>port</code> - number containing the port number
-- <code>user</code> - string containing the user name
-- <code>pass</code> - string containing the user password
-- <code>state</code> - a state table @see <code>State</code>
-- <code>state</code> - a state number @see <code>State</code>
-- <code>service</code> - string containing the name of the service
-- <code>scriptname</code> - string containing the name of the
-- script that added the credential
getCredentials = function(self, state)
if ( state ) then
self.storage:setFilter(self.host, { number=self.port, service = self.service }, state)
local function next_credential()
if ( state ) then
self.storage:setFilter(self.host, { number=self.port, service = self.service }, state)
end
for cred in self.storage:getAll() do
if ( ( self.scriptname == ALL_DATA ) or
( cred.scriptname == self.scriptname ) ) then
coroutine.yield(cred)
end
end
if ( state and State.PARAM == bit.band(state, State.PARAM) ) then
local creds_global = stdnse.get_script_args('creds.global')
local creds_service= stdnse.get_script_args('creds.' .. self.service )
local creds_params
if ( creds_service ) then creds_params = creds_service end
if ( creds_global and creds_service ) then
creds_params = creds_params .. ',' .. creds_global
elseif ( creds_global ) then
creds_params = creds_global
end
if ( not(creds_params) ) then return end
for _, cred in ipairs(stdnse.strsplit(",", creds_params)) do
-- if the credential contains a ':' we have a user + pass pair
-- if not, we only have a user with an empty password
local user, pass
if ( cred:match(":") ) then
user, pass = cred:match("^(.-):(.-)$")
else
user = cred:match("^(.*)$")
end
coroutine.yield( { host = self.host,
port = self.port,
user = user,
pass = pass,
state = State.PARAM,
service = self.service } )
end
end
end
return self.storage:getAll()
return coroutine.wrap( next_credential )
end,
--- Returns a table of credentials
@@ -206,14 +260,14 @@ Credentials = {
getTable = function(self)
local result = {}
for _, v in pairs(self.storage:getAll()) do
for v in self.storage:getAll() do
local h = ( v.host.ip or v.host )
local svc = ("%s/%s"):format(v.port,v.service)
local c
if ( v.user and #v.user > 0 ) then
c = ("%s:%s - %s"):format(v.user, v.pass, v.state.msg)
c = ("%s:%s - %s"):format(v.user, v.pass, StateMsg[v.state])
else
c = ("%s - %s"):format(v.pass, v.state.msg)
c = ("%s - %s"):format(v.pass, StateMsg[v.state])
end
local script = v.scriptname
assert(type(h)=="string", "Could not determine a valid host")
@@ -255,7 +309,7 @@ Credentials = {
output = output[1]
output.name = nil
end
return output
return (#output > 0 ) and output
end,
--- Get credentials with optional host and port filter