Merge branch 'master' into feature/uuid-registration

bug/bundler_fix
HD Moore 2015-05-20 19:48:39 -05:00
commit a8d111ce89
11 changed files with 429 additions and 155 deletions

View File

@ -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

View File

@ -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]

View File

@ -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

View File

@ -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 }

View File

@ -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

View File

@ -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 ]

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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