Merge branch 'master' into feature/uuid-registration
commit
a8d111ce89
|
@ -75,8 +75,10 @@ module Metasploit
|
|||
def to_s
|
||||
if realm && realm_key == Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN
|
||||
"#{self.realm}\\#{self.public}:#{self.private}"
|
||||
else
|
||||
elsif self.private
|
||||
"#{self.public}:#{self.private}#{at_realm}"
|
||||
else
|
||||
self.public
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -566,7 +566,6 @@ module Auxiliary::AuthBrute
|
|||
else
|
||||
level = opts[:level].to_s.strip
|
||||
end
|
||||
|
||||
host_ip = opts[:ip] || opts[:rhost] || opts[:host] || (rhost rescue nil) || datastore['RHOST']
|
||||
host_port = opts[:port] || opts[:rport] || (rport rescue nil) || datastore['RPORT']
|
||||
msg = opts[:msg] || opts[:message] || opts[:legacy_msg]
|
||||
|
|
|
@ -12,10 +12,19 @@ module Auxiliary::Report
|
|||
|
||||
optionally_include_metasploit_credential_creation
|
||||
|
||||
def db_warning_given?
|
||||
if @warning_issued
|
||||
true
|
||||
else
|
||||
@warning_issued = true
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def create_cracked_credential(opts={})
|
||||
if active_db?
|
||||
super(opts)
|
||||
else
|
||||
elsif !db_warning_given?
|
||||
vprint_warning('No active DB -- Credential data will not be saved!')
|
||||
end
|
||||
end
|
||||
|
@ -23,7 +32,7 @@ module Auxiliary::Report
|
|||
def create_credential(opts={})
|
||||
if active_db?
|
||||
super(opts)
|
||||
else
|
||||
elsif !db_warning_given?
|
||||
vprint_warning('No active DB -- Credential data will not be saved!')
|
||||
end
|
||||
end
|
||||
|
@ -31,7 +40,7 @@ module Auxiliary::Report
|
|||
def create_credential_login(opts={})
|
||||
if active_db?
|
||||
super(opts)
|
||||
else
|
||||
elsif !db_warning_given?
|
||||
vprint_warning('No active DB -- Credential data will not be saved!')
|
||||
end
|
||||
end
|
||||
|
@ -39,7 +48,7 @@ module Auxiliary::Report
|
|||
def invalidate_login(opts={})
|
||||
if active_db?
|
||||
super(opts)
|
||||
else
|
||||
elsif !db_warning_given?
|
||||
vprint_warning('No active DB -- Credential data will not be saved!')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -129,6 +129,8 @@ module Msf::DBManager::Import
|
|||
end
|
||||
end
|
||||
|
||||
# Override REXML's expansion text limit to 50k (default: 10240 bytes)
|
||||
REXML::Security.entity_expansion_text_limit = 51200
|
||||
|
||||
if block
|
||||
import(args.merge(:data => data)) { |type,data| yield type,data }
|
||||
|
|
|
@ -30,6 +30,18 @@ class Console::CommandDispatcher::Stdapi::Fs
|
|||
@@upload_opts = Rex::Parser::Arguments.new(
|
||||
"-h" => [ false, "Help banner." ],
|
||||
"-r" => [ false, "Upload recursively." ])
|
||||
#
|
||||
# Options for the ls command
|
||||
#
|
||||
@@ls_opts = Rex::Parser::Arguments.new(
|
||||
"-h" => [ false, "Help banner." ],
|
||||
"-S" => [ true, "Search string." ],
|
||||
"-t" => [ false, "Sort by time" ],
|
||||
"-s" => [ false, "Sort by size" ],
|
||||
"-r" => [ false, "Reverse sort order" ],
|
||||
"-x" => [ false, "Show short file names" ],
|
||||
"-l" => [ false, "List in long format (default)" ],
|
||||
"-R" => [ false, "Recursively list subdirectories encountered" ])
|
||||
|
||||
#
|
||||
# List of supported commands.
|
||||
|
@ -223,23 +235,35 @@ class Console::CommandDispatcher::Stdapi::Fs
|
|||
|
||||
alias :cmd_del :cmd_rm
|
||||
|
||||
#
|
||||
# Move source to destination
|
||||
#
|
||||
def cmd_mv(*args)
|
||||
if (args.length < 2)
|
||||
print_line("Usage: mv oldfile newfile")
|
||||
return true
|
||||
end
|
||||
#
|
||||
# Move source to destination
|
||||
#
|
||||
def cmd_mv(*args)
|
||||
if (args.length < 2)
|
||||
print_line("Usage: mv oldfile newfile")
|
||||
return true
|
||||
end
|
||||
client.fs.file.mv(args[0],args[1])
|
||||
return true
|
||||
end
|
||||
|
||||
client.fs.file.mv(args[0],args[1])
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
alias :cmd_move :cmd_mv
|
||||
alias :cmd_move :cmd_mv
|
||||
alias :cmd_rename :cmd_mv
|
||||
|
||||
#
|
||||
# Move source to destination
|
||||
#
|
||||
def cmd_cp(*args)
|
||||
if (args.length < 2)
|
||||
print_line("Usage: cp oldfile newfile")
|
||||
return true
|
||||
end
|
||||
client.fs.file.cp(args[0],args[1])
|
||||
return true
|
||||
end
|
||||
|
||||
alias :cmd_copy :cmd_cp
|
||||
|
||||
|
||||
def cmd_download_help
|
||||
print_line("Usage: download [options] src1 src2 src3 ... destination")
|
||||
|
@ -387,7 +411,15 @@ class Console::CommandDispatcher::Stdapi::Fs
|
|||
|
||||
alias cmd_getlwd cmd_lpwd
|
||||
|
||||
def list_path(path, columns, sort, order, short, recursive = false, depth = 0)
|
||||
|
||||
def cmd_ls_help
|
||||
print_line "Usage: ls [options]"
|
||||
print_line
|
||||
print_line "Lists contents of directory or file info, searchable"
|
||||
print_line @@ls_opts.usage
|
||||
end
|
||||
|
||||
def list_path(path, columns, sort, order, short, recursive = false, depth = 0, search_term = nil)
|
||||
|
||||
# avoid infinite recursion
|
||||
if depth > 100
|
||||
|
@ -398,7 +430,8 @@ class Console::CommandDispatcher::Stdapi::Fs
|
|||
'Header' => "Listing: #{path}",
|
||||
'SortIndex' => columns.index(sort),
|
||||
'SortOrder' => order,
|
||||
'Columns' => columns)
|
||||
'Columns' => columns,
|
||||
'SearchTerm' => search_term)
|
||||
|
||||
items = 0
|
||||
|
||||
|
@ -419,8 +452,10 @@ class Console::CommandDispatcher::Stdapi::Fs
|
|||
row.insert(4, p['FileShortName'] || '') if short
|
||||
|
||||
if fname != '.' && fname != '..'
|
||||
tbl << row
|
||||
items += 1
|
||||
if row.join(' ') =~ /#{search_term}/
|
||||
tbl << row
|
||||
items += 1
|
||||
end
|
||||
|
||||
if recursive && ffstat && ffstat.directory?
|
||||
if client.fs.file.is_glob?(path)
|
||||
|
@ -430,7 +465,7 @@ class Console::CommandDispatcher::Stdapi::Fs
|
|||
child_path = path + ::File::SEPARATOR + fname
|
||||
end
|
||||
begin
|
||||
list_path(child_path, columns, sort, order, short, recursive, depth + 1)
|
||||
list_path(child_path, columns, sort, order, short, recursive, depth + 1, search_term)
|
||||
rescue RequestError
|
||||
end
|
||||
end
|
||||
|
@ -448,39 +483,48 @@ class Console::CommandDispatcher::Stdapi::Fs
|
|||
# Lists files
|
||||
#
|
||||
def cmd_ls(*args)
|
||||
# Set defaults
|
||||
path = client.fs.dir.getwd
|
||||
search_term = nil
|
||||
sort = 'Name'
|
||||
short = nil
|
||||
order = :forward
|
||||
recursive = nil
|
||||
|
||||
# Check sort column
|
||||
sort = args.include?('-S') ? 'Size' : 'Name'
|
||||
sort = args.include?('-t') ? 'Last modified' : sort
|
||||
args.delete('-S')
|
||||
args.delete('-t')
|
||||
|
||||
# Check whether to include the short name option
|
||||
short = args.include?('-x')
|
||||
args.delete('-x')
|
||||
|
||||
# Check sort order
|
||||
order = args.include?('-r') ? :reverse : :forward
|
||||
args.delete('-r')
|
||||
|
||||
# Check for recursive mode
|
||||
recursive = !args.delete('-R').nil?
|
||||
|
||||
args.delete('-l')
|
||||
|
||||
# Check for cries of help
|
||||
if args.length > 1 || args.any? { |a| a[0] == '-' }
|
||||
print_line('Usage: ls [dir] [-x] [-S] [-t] [-r]')
|
||||
print_line(' -x Show short file names')
|
||||
print_line(' -S Sort by size')
|
||||
print_line(' -t Sort by time modified')
|
||||
print_line(' -r Reverse sort order')
|
||||
print_line(' -l List in long format (default)')
|
||||
print_line(' -R Recursively list subdirectories encountered.')
|
||||
return true
|
||||
end
|
||||
|
||||
path = args[0] || client.fs.dir.getwd
|
||||
# Parse the args
|
||||
@@ls_opts.parse(args) { |opt, idx, val|
|
||||
case opt
|
||||
# Sort options
|
||||
when '-s'
|
||||
sort = 'Size'
|
||||
when '-t'
|
||||
sort = 'Last modified'
|
||||
# Output options
|
||||
when '-x'
|
||||
short = true
|
||||
when '-l'
|
||||
short = nil
|
||||
when '-r'
|
||||
order = :reverse
|
||||
when '-R'
|
||||
recursive = true
|
||||
# Search
|
||||
when '-S'
|
||||
search_term = val
|
||||
if search_term.nil?
|
||||
print_error("Enter a search term")
|
||||
return true
|
||||
else
|
||||
search_term = /#{search_term}/nmi
|
||||
end
|
||||
# Help and path
|
||||
when "-h"
|
||||
cmd_ls_help
|
||||
return 0
|
||||
when nil
|
||||
path = val
|
||||
end
|
||||
}
|
||||
|
||||
columns = [ 'Mode', 'Size', 'Type', 'Last modified', 'Name' ]
|
||||
columns.insert(4, 'Short Name') if short
|
||||
|
@ -499,7 +543,7 @@ class Console::CommandDispatcher::Stdapi::Fs
|
|||
|
||||
stat = client.fs.file.stat(stat_path)
|
||||
if stat.directory?
|
||||
list_path(path, columns, sort, order, short, recursive)
|
||||
list_path(path, columns, sort, order, short, recursive, 0, search_term)
|
||||
else
|
||||
print_line("#{stat.prettymode} #{stat.size} #{stat.ftype[0,3]} #{stat.mtime} #{path}")
|
||||
end
|
||||
|
|
|
@ -51,6 +51,20 @@ class Console::CommandDispatcher::Stdapi::Net
|
|||
"-p" => [ true, "The remote port to connect to." ],
|
||||
"-L" => [ true, "The local host to listen on (optional)." ])
|
||||
|
||||
#
|
||||
# Options for the netstat command.
|
||||
#
|
||||
@@netstat_opts = Rex::Parser::Arguments.new(
|
||||
"-h" => [ false, "Help banner." ],
|
||||
"-S" => [ true, "Search string." ])
|
||||
|
||||
#
|
||||
# Options for ARP command.
|
||||
#
|
||||
@@arp_opts = Rex::Parser::Arguments.new(
|
||||
"-h" => [ false, "Help banner." ],
|
||||
"-S" => [ true, "Search string." ])
|
||||
|
||||
#
|
||||
# List of supported commands.
|
||||
#
|
||||
|
@ -107,6 +121,23 @@ class Console::CommandDispatcher::Stdapi::Net
|
|||
#
|
||||
def cmd_netstat(*args)
|
||||
connection_table = client.net.config.netstat
|
||||
search_term = nil
|
||||
@@netstat_opts.parse(args) { |opt, idx, val|
|
||||
case opt
|
||||
when '-S'
|
||||
search_term = val
|
||||
if search_term.nil?
|
||||
print_error("Enter a search term")
|
||||
return true
|
||||
else
|
||||
search_term = /#{search_term}/nmi
|
||||
end
|
||||
when "-h"
|
||||
@@netstat_opts.usage
|
||||
return 0
|
||||
|
||||
end
|
||||
}
|
||||
tbl = Rex::Ui::Text::Table.new(
|
||||
'Header' => "Connection list",
|
||||
'Indent' => 4,
|
||||
|
@ -119,7 +150,8 @@ class Console::CommandDispatcher::Stdapi::Net
|
|||
"User",
|
||||
"Inode",
|
||||
"PID/Program name"
|
||||
])
|
||||
],
|
||||
'SearchTerm' => search_term)
|
||||
|
||||
connection_table.each { |connection|
|
||||
tbl << [ connection.protocol, connection.local_addr_str, connection.remote_addr_str,
|
||||
|
@ -138,6 +170,23 @@ class Console::CommandDispatcher::Stdapi::Net
|
|||
#
|
||||
def cmd_arp(*args)
|
||||
arp_table = client.net.config.arp_table
|
||||
search_term = nil
|
||||
@@arp_opts.parse(args) { |opt, idx, val|
|
||||
case opt
|
||||
when '-S'
|
||||
search_term = val
|
||||
if search_term.nil?
|
||||
print_error("Enter a search term")
|
||||
return true
|
||||
else
|
||||
search_term = /#{search_term}/nmi
|
||||
end
|
||||
when "-h"
|
||||
@@arp_opts.usage
|
||||
return 0
|
||||
|
||||
end
|
||||
}
|
||||
tbl = Rex::Ui::Text::Table.new(
|
||||
'Header' => "ARP cache",
|
||||
'Indent' => 4,
|
||||
|
@ -146,7 +195,8 @@ class Console::CommandDispatcher::Stdapi::Net
|
|||
"IP address",
|
||||
"MAC address",
|
||||
"Interface"
|
||||
])
|
||||
],
|
||||
'SearchTerm' => search_term)
|
||||
|
||||
arp_table.each { |arp|
|
||||
tbl << [ arp.ip_addr, arp.mac_addr, arp.interface ]
|
||||
|
|
|
@ -21,61 +21,61 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
# Options used by the 'execute' command.
|
||||
#
|
||||
@@execute_opts = Rex::Parser::Arguments.new(
|
||||
"-a" => [ true, "The arguments to pass to the command." ],
|
||||
"-c" => [ false, "Channelized I/O (required for interaction)." ],
|
||||
"-f" => [ true, "The executable command to run." ],
|
||||
"-h" => [ false, "Help menu." ],
|
||||
"-H" => [ false, "Create the process hidden from view." ],
|
||||
"-i" => [ false, "Interact with the process after creating it." ],
|
||||
"-m" => [ false, "Execute from memory." ],
|
||||
"-d" => [ true, "The 'dummy' executable to launch when using -m." ],
|
||||
"-a" => [ true, "The arguments to pass to the command." ],
|
||||
"-c" => [ false, "Channelized I/O (required for interaction)." ],
|
||||
"-f" => [ true, "The executable command to run." ],
|
||||
"-h" => [ false, "Help menu." ],
|
||||
"-H" => [ false, "Create the process hidden from view." ],
|
||||
"-i" => [ false, "Interact with the process after creating it." ],
|
||||
"-m" => [ false, "Execute from memory." ],
|
||||
"-d" => [ true, "The 'dummy' executable to launch when using -m." ],
|
||||
"-t" => [ false, "Execute process with currently impersonated thread token"],
|
||||
"-k" => [ false, "Execute process on the meterpreters current desktop" ],
|
||||
"-k" => [ false, "Execute process on the meterpreters current desktop" ],
|
||||
"-s" => [ true, "Execute process in a given session as the session user" ])
|
||||
|
||||
#
|
||||
# Options used by the 'reboot' command.
|
||||
#
|
||||
@@reboot_opts = Rex::Parser::Arguments.new(
|
||||
"-h" => [ false, "Help menu." ],
|
||||
"-f" => [ true, "Force a reboot, valid values [1|2]" ])
|
||||
"-h" => [ false, "Help menu." ],
|
||||
"-f" => [ true, "Force a reboot, valid values [1|2]" ])
|
||||
|
||||
#
|
||||
# Options used by the 'shutdown' command.
|
||||
#
|
||||
@@shutdown_opts = Rex::Parser::Arguments.new(
|
||||
"-h" => [ false, "Help menu." ],
|
||||
"-f" => [ true, "Force a shutdown, valid values [1|2]" ])
|
||||
"-h" => [ false, "Help menu." ],
|
||||
"-f" => [ true, "Force a shutdown, valid values [1|2]" ])
|
||||
|
||||
#
|
||||
# Options used by the 'reg' command.
|
||||
#
|
||||
@@reg_opts = Rex::Parser::Arguments.new(
|
||||
"-d" => [ true, "The data to store in the registry value." ],
|
||||
"-h" => [ false, "Help menu." ],
|
||||
"-k" => [ true, "The registry key path (E.g. HKLM\\Software\\Foo)." ],
|
||||
"-t" => [ true, "The registry value type (E.g. REG_SZ)." ],
|
||||
"-v" => [ true, "The registry value name (E.g. Stuff)." ],
|
||||
"-d" => [ true, "The data to store in the registry value." ],
|
||||
"-h" => [ false, "Help menu." ],
|
||||
"-k" => [ true, "The registry key path (E.g. HKLM\\Software\\Foo)." ],
|
||||
"-t" => [ true, "The registry value type (E.g. REG_SZ)." ],
|
||||
"-v" => [ true, "The registry value name (E.g. Stuff)." ],
|
||||
"-r" => [ true, "The remote machine name to connect to (with current process credentials" ],
|
||||
"-w" => [ false, "Set KEY_WOW64 flag, valid values [32|64]." ])
|
||||
"-w" => [ false, "Set KEY_WOW64 flag, valid values [32|64]." ])
|
||||
|
||||
#
|
||||
# Options for the 'ps' command.
|
||||
#
|
||||
@@ps_opts = Rex::Parser::Arguments.new(
|
||||
"-S" => [ true, "String to search for (converts to regex)" ],
|
||||
"-h" => [ false, "Help menu." ],
|
||||
"-S" => [ true, "Filters processes on the process name using the supplied RegEx"],
|
||||
"-A" => [ true, "Filters processes on architecture (x86 or x86_64)" ],
|
||||
"-s" => [ false, "Show only SYSTEM processes" ],
|
||||
"-A" => [ true, "Filters processes on architecture (x86 or x86_64)" ],
|
||||
"-s" => [ false, "Show only SYSTEM processes" ],
|
||||
"-U" => [ true, "Filters processes on the user using the supplied RegEx" ])
|
||||
|
||||
#
|
||||
# Options for the 'suspend' command.
|
||||
#
|
||||
@@suspend_opts = Rex::Parser::Arguments.new(
|
||||
"-h" => [ false, "Help menu." ],
|
||||
"-h" => [ false, "Help menu." ],
|
||||
"-c" => [ false, "Continues suspending or resuming even if an error is encountered"],
|
||||
"-r" => [ false, "Resumes the target processes instead of suspending" ])
|
||||
"-r" => [ false, "Resumes the target processes instead of suspending" ])
|
||||
|
||||
#
|
||||
# List of supported commands.
|
||||
|
@ -93,7 +93,7 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
"kill" => "Terminate a process",
|
||||
"ps" => "List running processes",
|
||||
"reboot" => "Reboots the remote computer",
|
||||
"reg" => "Modify and interact with the remote registry",
|
||||
"reg" => "Modify and interact with the remote registry",
|
||||
"rev2self" => "Calls RevertToSelf() on the remote machine",
|
||||
"shell" => "Drop into a system command shell",
|
||||
"shutdown" => "Shuts down the remote computer",
|
||||
|
@ -105,7 +105,7 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
"clearev" => [ "stdapi_sys_eventlog_open", "stdapi_sys_eventlog_clear" ],
|
||||
"drop_token" => [ "stdapi_sys_config_drop_token" ],
|
||||
"execute" => [ "stdapi_sys_process_execute" ],
|
||||
"getpid" => [ "stdapi_sys_process_getpid" ],
|
||||
"getpid" => [ "stdapi_sys_process_getpid" ],
|
||||
"getprivs" => [ "stdapi_sys_config_getprivs" ],
|
||||
"getuid" => [ "stdapi_sys_config_getuid" ],
|
||||
"getsid" => [ "stdapi_sys_config_getsid" ],
|
||||
|
@ -113,7 +113,7 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
"kill" => [ "stdapi_sys_process_kill" ],
|
||||
"ps" => [ "stdapi_sys_process_get_processes" ],
|
||||
"reboot" => [ "stdapi_sys_power_exitwindows" ],
|
||||
"reg" => [
|
||||
"reg" => [
|
||||
"stdapi_registry_load_key",
|
||||
"stdapi_registry_unload_key",
|
||||
"stdapi_registry_open_key",
|
||||
|
@ -169,7 +169,7 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
interact = false
|
||||
desktop = false
|
||||
channelized = nil
|
||||
hidden = nil
|
||||
hidden = nil
|
||||
from_mem = false
|
||||
dummy_exec = "cmd"
|
||||
cmd_args = nil
|
||||
|
@ -422,23 +422,27 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
# Lists running processes.
|
||||
#
|
||||
def cmd_ps(*args)
|
||||
# Init vars
|
||||
processes = client.sys.process.get_processes
|
||||
@@ps_opts.parse(args) do |opt, idx, val|
|
||||
search_term = nil
|
||||
|
||||
# Parse opts
|
||||
@@ps_opts.parse(args) { |opt, idx, val|
|
||||
case opt
|
||||
when "-h"
|
||||
cmd_ps_help
|
||||
return true
|
||||
when "-S"
|
||||
print_line "Filtering on process name..."
|
||||
searched_procs = Rex::Post::Meterpreter::Extensions::Stdapi::Sys::ProcessList.new
|
||||
processes.each do |proc|
|
||||
if val.nil? or val.empty?
|
||||
print_line "You must supply a search term!"
|
||||
return false
|
||||
when '-S'
|
||||
search_term = val
|
||||
if search_term.nil?
|
||||
print_error("Enter a search term")
|
||||
return true
|
||||
end
|
||||
searched_procs << proc if proc["name"].match(/#{val}/)
|
||||
end
|
||||
processes = searched_procs
|
||||
when '-h'
|
||||
print_line "Usage: ps [ options ]"
|
||||
print_line
|
||||
print_line "OPTIONS:"
|
||||
print_line " -S Search string to filter by"
|
||||
print_line " -h This help menu"
|
||||
print_line
|
||||
return 0
|
||||
when "-A"
|
||||
print_line "Filtering on arch..."
|
||||
searched_procs = Rex::Post::Meterpreter::Extensions::Stdapi::Sys::ProcessList.new
|
||||
|
@ -448,14 +452,14 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
print_line "You must select either x86 or x86_64"
|
||||
return false
|
||||
end
|
||||
searched_procs << proc if proc["arch"] == val
|
||||
searched_procs << proc if proc["arch"] == val
|
||||
end
|
||||
processes = searched_procs
|
||||
when "-s"
|
||||
print_line "Filtering on SYSTEM processes..."
|
||||
searched_procs = Rex::Post::Meterpreter::Extensions::Stdapi::Sys::ProcessList.new
|
||||
processes.each do |proc|
|
||||
searched_procs << proc if proc["user"] == "NT AUTHORITY\\SYSTEM"
|
||||
searched_procs << proc if proc["user"] == "NT AUTHORITY\\SYSTEM"
|
||||
end
|
||||
processes = searched_procs
|
||||
when "-U"
|
||||
|
@ -466,16 +470,48 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
print_line "You must supply a search term!"
|
||||
return false
|
||||
end
|
||||
searched_procs << proc if proc["user"].match(/#{val}/)
|
||||
searched_procs << proc if proc["user"].match(/#{val}/)
|
||||
end
|
||||
processes = searched_procs
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
tbl = Rex::Ui::Text::Table.new(
|
||||
'Header' => "Process list",
|
||||
'Indent' => 1,
|
||||
'Columns' =>
|
||||
[
|
||||
"PID",
|
||||
"Name",
|
||||
"Arch",
|
||||
"Session",
|
||||
"User",
|
||||
"Path"
|
||||
],
|
||||
'SearchTerm' => search_term)
|
||||
|
||||
processes.each { |ent|
|
||||
|
||||
session = ent['session'] == 0xFFFFFFFF ? '' : ent['session'].to_s
|
||||
arch = ent['arch']
|
||||
|
||||
# for display and consistency with payload naming we switch the internal 'x86_64' value to display 'x64'
|
||||
if( arch == ARCH_X86_64 )
|
||||
arch = "x64"
|
||||
end
|
||||
|
||||
row = [ ent['pid'].to_s, ent['name'], arch, session, ent['user'], ent['path'] ]
|
||||
|
||||
tbl << row #if (search_term.nil? or row.join(' ').to_s.match(search_term))
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (processes.length == 0)
|
||||
print_line("No running processes were found.")
|
||||
else
|
||||
print_line
|
||||
print_line(processes.to_table("Indent" => 1).to_s)
|
||||
print("\n" + tbl.to_s + "\n")
|
||||
print_line
|
||||
end
|
||||
return true
|
||||
|
@ -529,12 +565,12 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
end
|
||||
|
||||
# Initiailze vars
|
||||
key = nil
|
||||
value = nil
|
||||
data = nil
|
||||
type = nil
|
||||
key = nil
|
||||
value = nil
|
||||
data = nil
|
||||
type = nil
|
||||
wowflag = 0x0000
|
||||
rem = nil
|
||||
rem = nil
|
||||
|
||||
@@reg_opts.parse(args) { |opt, idx, val|
|
||||
case opt
|
||||
|
@ -544,13 +580,13 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
"Interact with the target machine's registry.\n" +
|
||||
@@reg_opts.usage +
|
||||
"COMMANDS:\n\n" +
|
||||
" enumkey Enumerate the supplied registry key [-k <key>]\n" +
|
||||
" createkey Create the supplied registry key [-k <key>]\n" +
|
||||
" deletekey Delete the supplied registry key [-k <key>]\n" +
|
||||
" enumkey Enumerate the supplied registry key [-k <key>]\n" +
|
||||
" createkey Create the supplied registry key [-k <key>]\n" +
|
||||
" deletekey Delete the supplied registry key [-k <key>]\n" +
|
||||
" queryclass Queries the class of the supplied key [-k <key>]\n" +
|
||||
" setval Set a registry value [-k <key> -v <val> -d <data>]\n" +
|
||||
" deleteval Delete the supplied registry value [-k <key> -v <val>]\n" +
|
||||
" queryval Queries the data contents of a value [-k <key> -v <val>]\n\n")
|
||||
" setval Set a registry value [-k <key> -v <val> -d <data>]\n" +
|
||||
" deleteval Delete the supplied registry value [-k <key> -v <val>]\n" +
|
||||
" queryval Queries the data contents of a value [-k <key> -v <val>]\n\n")
|
||||
return false
|
||||
when "-k"
|
||||
key = val
|
||||
|
@ -672,7 +708,7 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
|
||||
open_key.set_value(value, client.sys.registry.type2str(type), data)
|
||||
|
||||
print_line("Successful set #{value}.")
|
||||
print_line("Successfully set #{value} of #{type}.")
|
||||
|
||||
when "deleteval"
|
||||
if (value == nil)
|
||||
|
@ -859,11 +895,11 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
args.uniq!
|
||||
diff = args - valid_pids.map {|e| e.to_s}
|
||||
if not diff.empty? # then we had an invalid pid
|
||||
print_error("The following pids are not valid: #{diff.join(", ").to_s}.")
|
||||
print_error("The following pids are not valid: #{diff.join(", ").to_s}.")
|
||||
if continue
|
||||
print_status("Continuing. Invalid args have been removed from the list.")
|
||||
else
|
||||
print_error("Quitting. Use -c to continue using only the valid pids.")
|
||||
print_error("Quitting. Use -c to continue using only the valid pids.")
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
@ -912,4 +948,3 @@ end
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@ class Table
|
|||
self.prefix = opts['Prefix'] || ''
|
||||
self.postfix = opts['Postfix'] || ''
|
||||
self.colprops = []
|
||||
self.scterm = /#{opts['SearchTerm']}/mi if opts['SearchTerm']
|
||||
|
||||
self.sort_index = opts['SortIndex'] || 0
|
||||
self.sort_order = opts['SortOrder'] || :forward
|
||||
|
@ -113,7 +114,7 @@ class Table
|
|||
if (is_hr(row))
|
||||
str << hr_to_s
|
||||
else
|
||||
str << row_to_s(row)
|
||||
str << row_to_s(row) if row_visible(row)
|
||||
end
|
||||
}
|
||||
|
||||
|
@ -129,10 +130,9 @@ class Table
|
|||
str = ''
|
||||
str << ( columns.join(",") + "\n" )
|
||||
rows.each { |row|
|
||||
next if is_hr(row)
|
||||
next if is_hr(row) || !row_visible(row)
|
||||
str << ( row.map{|x|
|
||||
x = x.to_s
|
||||
|
||||
x.gsub(/[\r\n]/, ' ').gsub(/\s+/, ' ').gsub('"', '""')
|
||||
}.map{|x| "\"#{x}\"" }.join(",") + "\n" )
|
||||
}
|
||||
|
@ -175,7 +175,10 @@ class Table
|
|||
raise RuntimeError, 'Invalid number of columns!'
|
||||
end
|
||||
fields.each_with_index { |field, idx|
|
||||
# Remove whitespace and ensure String format
|
||||
field = field.to_s.strip
|
||||
if (colprops[idx]['MaxWidth'] < field.to_s.length)
|
||||
old = colprops[idx]['MaxWidth']
|
||||
colprops[idx]['MaxWidth'] = field.to_s.length
|
||||
end
|
||||
}
|
||||
|
@ -217,6 +220,51 @@ class Table
|
|||
#
|
||||
# Returns new sub-table with headers and rows maching column names submitted
|
||||
#
|
||||
#
|
||||
# Flips table 90 degrees left
|
||||
#
|
||||
def drop_left
|
||||
tbl = self.class.new(
|
||||
'Columns' => Array.new(self.rows.count+1,' '),
|
||||
'Header' => self.header,
|
||||
'Indent' => self.indent)
|
||||
(self.columns.count+1).times do |ti|
|
||||
row = self.rows.map {|r| r[ti]}.unshift(self.columns[ti]).flatten
|
||||
# insert our col|row break. kind of hackish
|
||||
row[1] = "| #{row[1]}" unless row.all? {|e| e.nil? || e.empty?}
|
||||
tbl << row
|
||||
end
|
||||
return tbl
|
||||
end
|
||||
|
||||
#
|
||||
# Build table from CSV dump
|
||||
#
|
||||
def self.new_from_csv(csv)
|
||||
# Read in or keep data, get CSV or die
|
||||
if csv.is_a?(String)
|
||||
csv = File.file?(csv) ? CSV.read(csv) : CSV.parse(csv)
|
||||
end
|
||||
# Adjust for skew
|
||||
if csv.first == ["Keys", "Values"]
|
||||
csv.shift # drop marker
|
||||
cols = []
|
||||
rows = []
|
||||
csv.each do |row|
|
||||
cols << row.shift
|
||||
rows << row
|
||||
end
|
||||
tbl = self.new('Columns' => cols)
|
||||
rows.in_groups_of(cols.count) {|r| tbl << r.flatten}
|
||||
else
|
||||
tbl = self.new('Columns' => csv.shift)
|
||||
while !csv.empty? do
|
||||
tbl << csv.shift
|
||||
end
|
||||
end
|
||||
return tbl
|
||||
end
|
||||
|
||||
def [](*col_names)
|
||||
tbl = self.class.new('Indent' => self.indent,
|
||||
'Header' => self.header,
|
||||
|
@ -245,10 +293,18 @@ class Table
|
|||
attr_accessor :columns, :rows, :colprops # :nodoc:
|
||||
attr_accessor :width, :indent, :cellpad # :nodoc:
|
||||
attr_accessor :prefix, :postfix # :nodoc:
|
||||
attr_accessor :sort_index, :sort_order # :nodoc:
|
||||
attr_accessor :sort_index, :sort_order, :scterm # :nodoc:
|
||||
|
||||
protected
|
||||
|
||||
#
|
||||
# Returns if a row should be visible or not
|
||||
#
|
||||
def row_visible(row)
|
||||
return true if self.scterm.nil?
|
||||
row_to_s(row).match(self.scterm)
|
||||
end
|
||||
|
||||
#
|
||||
# Defaults cell widths and alignments.
|
||||
#
|
||||
|
@ -274,14 +330,15 @@ protected
|
|||
last_idx = nil
|
||||
columns.each_with_index { |col,idx|
|
||||
if (last_col)
|
||||
nameline << pad(' ', last_col, last_idx)
|
||||
|
||||
remainder = colprops[last_idx]['MaxWidth'] - last_col.length
|
||||
if (remainder < 0)
|
||||
remainder = 0
|
||||
end
|
||||
# This produces clean to_s output without truncation
|
||||
# Preserves full string in cells for to_csv output
|
||||
padding = pad(' ', last_col, last_idx)
|
||||
nameline << padding
|
||||
remainder = padding.length - cellpad
|
||||
remainder = 0 if remainder < 0
|
||||
barline << (' ' * (cellpad + remainder))
|
||||
end
|
||||
|
||||
nameline << col
|
||||
barline << ('-' * col.length)
|
||||
|
||||
|
@ -310,7 +367,6 @@ protected
|
|||
if (idx != 0)
|
||||
line << pad(' ', last_cell.to_s, last_idx)
|
||||
end
|
||||
# line << pad(' ', cell.to_s, idx)
|
||||
# Limit wide cells
|
||||
if colprops[idx]['MaxChar']
|
||||
last_cell = cell.to_s[0..colprops[idx]['MaxChar'].to_i]
|
||||
|
@ -330,8 +386,12 @@ protected
|
|||
# some text and a column index.
|
||||
#
|
||||
def pad(chr, buf, colidx, use_cell_pad = true) # :nodoc:
|
||||
remainder = colprops[colidx]['MaxWidth'] - buf.length
|
||||
val = chr * remainder;
|
||||
# Ensure we pad the minimum required amount
|
||||
max = colprops[colidx]['MaxChar'] || colprops[colidx]['MaxWidth']
|
||||
max = colprops[colidx]['MaxWidth'] if max.to_i > colprops[colidx]['MaxWidth'].to_i
|
||||
remainder = max - buf.length
|
||||
remainder = 0 if remainder < 0
|
||||
val = chr * remainder
|
||||
|
||||
if (use_cell_pad)
|
||||
val << ' ' * cellpad
|
||||
|
|
|
@ -88,8 +88,8 @@ class Metasploit3 < Msf::Auxiliary
|
|||
rx_title = Rex::Text.html_decode(rx[:title])
|
||||
print_status("[#{target_host}:#{rport}] [C:#{res.code}] [R:#{location_header}] [S:#{server_header}] #{rx_title}") if datastore['SHOW_TITLES'] == true
|
||||
if datastore['STORE_NOTES'] == true
|
||||
notedata = { code: res.code, port: rport, server: server_header, title: rx_title, redirect: location_header }
|
||||
report_note(host: target_host, type: "http.title", data: notedata)
|
||||
notedata = { code: res.code, port: rport, server: server_header, title: rx_title, redirect: location_header, uri: datastore['TARGETURI'] }
|
||||
report_note(host: target_host, port: rport, type: "http.title", data: notedata, update: :unique_data)
|
||||
end
|
||||
else
|
||||
print_error("[#{target_host}:#{rport}] No webpage title") if datastore['SHOW_ERRORS'] == true
|
||||
|
|
|
@ -85,7 +85,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential} (Access level: #{result.access_level})"
|
||||
else
|
||||
invalidate_login(credential_data)
|
||||
vprint_error "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})"
|
||||
print_error "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status})"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -293,13 +293,11 @@ class Metasploit3 < Msf::Auxiliary
|
|||
capturedtime = Time.now.to_s
|
||||
case ntlm_ver
|
||||
when NTLM_CONST::NTLM_V1_RESPONSE
|
||||
smb_db_type_hash = "smb_netv1_hash"
|
||||
capturelogmessage =
|
||||
"#{capturedtime}\nNTLMv1 Response Captured from #{host} \n" +
|
||||
"DOMAIN: #{domain} USER: #{user} \n" +
|
||||
"LMHASH:#{lm_hash_message ? lm_hash_message : "<NULL>"} \nNTHASH:#{nt_hash ? nt_hash : "<NULL>"}\n"
|
||||
when NTLM_CONST::NTLM_V2_RESPONSE
|
||||
smb_db_type_hash = "smb_netv2_hash"
|
||||
capturelogmessage =
|
||||
"#{capturedtime}\nNTLMv2 Response Captured from #{host} \n" +
|
||||
"DOMAIN: #{domain} USER: #{user} \n" +
|
||||
|
@ -310,7 +308,6 @@ class Metasploit3 < Msf::Auxiliary
|
|||
when NTLM_CONST::NTLM_2_SESSION_RESPONSE
|
||||
# we can consider those as netv1 has they have the same size and i cracked the same way by cain/jtr
|
||||
# also 'real' netv1 is almost never seen nowadays except with smbmount or msf server capture
|
||||
smb_db_type_hash = "smb_netv1_hash"
|
||||
capturelogmessage =
|
||||
"#{capturedtime}\nNTLM2_SESSION Response Captured from #{host} \n" +
|
||||
"DOMAIN: #{domain} USER: #{user} \n" +
|
||||
|
@ -326,20 +323,19 @@ class Metasploit3 < Msf::Auxiliary
|
|||
# DB reporting
|
||||
# Rem : one report it as a smb_challenge on port 445 has breaking those hashes
|
||||
# will be mainly use for psexec / smb related exploit
|
||||
report_auth_info(
|
||||
:host => ip,
|
||||
:port => 445,
|
||||
:sname => 'smb_challenge',
|
||||
:user => user,
|
||||
:pass => domain + ":" +
|
||||
( lm_hash + lm_cli_challenge.to_s ? lm_hash + lm_cli_challenge.to_s : "00" * 24 ) + ":" +
|
||||
( nt_hash + nt_cli_challenge.to_s ? nt_hash + nt_cli_challenge.to_s : "00" * 24 ) + ":" +
|
||||
datastore['CHALLENGE'].to_s,
|
||||
:type => smb_db_type_hash,
|
||||
:proof => "DOMAIN=#{domain}",
|
||||
:source_type => "captured",
|
||||
:active => true
|
||||
)
|
||||
opts_report = {
|
||||
ip: ip,
|
||||
user: user,
|
||||
domain: domain,
|
||||
ntlm_ver: ntlm_ver,
|
||||
lm_hash: lm_hash,
|
||||
nt_hash: nt_hash
|
||||
}
|
||||
opts_report.merge!(lm_cli_challenge: lm_cli_challenge) if lm_cli_challenge
|
||||
opts_report.merge!(nt_cli_challenge: nt_cli_challenge) if nt_cli_challenge
|
||||
|
||||
report_creds(opts_report)
|
||||
|
||||
#if(datastore['LOGFILE'])
|
||||
# File.open(datastore['LOGFILE'], "ab") {|fd| fd.puts(capturelogmessage + "\n")}
|
||||
#end
|
||||
|
@ -406,4 +402,81 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
end
|
||||
|
||||
def report_creds(opts)
|
||||
ip = opts[:ip] || rhost
|
||||
user = opts[:user] || nil
|
||||
domain = opts[:domain] || nil
|
||||
ntlm_ver = opts[:ntlm_ver] || nil
|
||||
lm_hash = opts[:lm_hash] || nil
|
||||
nt_hash = opts[:nt_hash] || nil
|
||||
lm_cli_challenge = opts[:lm_cli_challenge] || nil
|
||||
nt_cli_challenge = opts[:nt_cli_challenge] || nil
|
||||
|
||||
case ntlm_ver
|
||||
when NTLM_CONST::NTLM_V1_RESPONSE, NTLM_CONST::NTLM_2_SESSION_RESPONSE
|
||||
hash = [
|
||||
user, '',
|
||||
domain ? domain : 'NULL',
|
||||
lm_hash ? lm_hash : '0' * 48,
|
||||
nt_hash ? nt_hash : '0' * 48,
|
||||
@challenge.unpack('H*')[0]
|
||||
].join(':').gsub(/\n/, '\\n')
|
||||
report_hash(ip, user, 'netntlm', hash)
|
||||
when NTLM_CONST::NTLM_V2_RESPONSE
|
||||
hash = [
|
||||
user, '',
|
||||
domain ? domain : 'NULL',
|
||||
@challenge.unpack('H*')[0],
|
||||
lm_hash ? lm_hash : '0' * 32,
|
||||
lm_cli_challenge ? lm_cli_challenge : '0' * 16
|
||||
].join(':').gsub(/\n/, '\\n')
|
||||
report_hash(ip, user, 'netlmv2', hash)
|
||||
|
||||
hash = [
|
||||
user, '',
|
||||
domain ? domain : 'NULL',
|
||||
@challenge.unpack('H*')[0],
|
||||
nt_hash ? nt_hash : '0' * 32,
|
||||
nt_cli_challenge ? nt_cli_challenge : '0' * 160
|
||||
].join(':').gsub(/\n/, '\\n')
|
||||
report_hash(ip, user, 'netntlmv2', hash)
|
||||
else
|
||||
hash = domain + ':' +
|
||||
( lm_hash + lm_cli_challenge.to_s ? lm_hash + lm_cli_challenge.to_s : '00' * 24 ) + ':' +
|
||||
( nt_hash + nt_cli_challenge.to_s ? nt_hash + nt_cli_challenge.to_s : '00' * 24 ) + ':' +
|
||||
datastore['CHALLENGE'].to_s
|
||||
report_hash(ip, user, nil, hash)
|
||||
end
|
||||
end
|
||||
|
||||
def report_hash(ip, user, type_hash, hash)
|
||||
service_data = {
|
||||
address: ip,
|
||||
port: 445,
|
||||
service_name: 'smb',
|
||||
protocol: 'tcp',
|
||||
workspace_id: myworkspace_id
|
||||
}
|
||||
|
||||
credential_data = {
|
||||
module_fullname: self.fullname,
|
||||
origin_type: :service,
|
||||
private_data: hash,
|
||||
private_type: :nonreplayable_hash,
|
||||
username: user
|
||||
}.merge(service_data)
|
||||
|
||||
unless type_hash.nil?
|
||||
credential_data.merge!(jtr_format: type_hash)
|
||||
end
|
||||
|
||||
login_data = {
|
||||
core: create_credential(credential_data),
|
||||
status: Metasploit::Model::Login::Status::UNTRIED
|
||||
}.merge(service_data)
|
||||
|
||||
create_credential_login(login_data)
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue