Merge branch 'master' of git://github.com/rapid7/metasploit-framework
commit
4890882beb
|
@ -124,7 +124,7 @@ GEM
|
|||
activesupport (>= 4.0.9, < 4.1.0)
|
||||
railties (>= 4.0.9, < 4.1.0)
|
||||
metasploit-payloads (0.0.7)
|
||||
metasploit_data_models (1.0.1)
|
||||
metasploit_data_models (1.1.0)
|
||||
activerecord (>= 4.0.9, < 4.1.0)
|
||||
activesupport (>= 4.0.9, < 4.1.0)
|
||||
arel-helpers
|
||||
|
@ -146,7 +146,7 @@ GEM
|
|||
mini_portile (~> 0.6.0)
|
||||
packetfu (1.1.9)
|
||||
pcaprub (0.12.0)
|
||||
pg (0.18.1)
|
||||
pg (0.18.2)
|
||||
pg_array_parser (0.0.9)
|
||||
postgres_ext (2.4.1)
|
||||
activerecord (>= 4.0.0)
|
||||
|
@ -156,7 +156,7 @@ GEM
|
|||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.8.1)
|
||||
slop (~> 3.4)
|
||||
rack (1.5.2)
|
||||
rack (1.5.3)
|
||||
rack-test (0.6.3)
|
||||
rack (>= 1.0)
|
||||
rails (4.0.13)
|
||||
|
@ -222,7 +222,7 @@ GEM
|
|||
thread_safe (0.3.5)
|
||||
tilt (1.4.1)
|
||||
timecop (0.7.3)
|
||||
tzinfo (0.3.43)
|
||||
tzinfo (0.3.44)
|
||||
xpath (2.0.0)
|
||||
nokogiri (~> 1.3)
|
||||
yard (0.8.7.6)
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20150421211719) do
|
||||
ActiveRecord::Schema.define(version: 20150514182921) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -684,9 +684,12 @@ ActiveRecord::Schema.define(version: 20150421211719) do
|
|||
t.datetime "exploited_at"
|
||||
t.integer "vuln_detail_count", default: 0
|
||||
t.integer "vuln_attempt_count", default: 0
|
||||
t.integer "origin_id"
|
||||
t.string "origin_type"
|
||||
end
|
||||
|
||||
add_index "vulns", ["name"], name: "index_vulns_on_name", using: :btree
|
||||
add_index "vulns", ["origin_id"], name: "index_vulns_on_origin_id", using: :btree
|
||||
|
||||
create_table "vulns_refs", force: true do |t|
|
||||
t.integer "ref_id"
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -61,6 +61,9 @@ module Msf
|
|||
# @!attribute platform
|
||||
# @return [String] The platform to build the payload for
|
||||
attr_accessor :platform
|
||||
# @!attribute smallest
|
||||
# @return [Boolean] Whether or not to find the smallest possible output
|
||||
attr_accessor :smallest
|
||||
# @!attribute space
|
||||
# @return [Fixnum] The maximum size in bytes of the payload
|
||||
attr_accessor :space
|
||||
|
@ -95,6 +98,7 @@ module Msf
|
|||
# @option opts [Hash] :datastore (see #datastore)
|
||||
# @option opts [Msf::Framework] :framework (see #framework)
|
||||
# @option opts [Boolean] :cli (see #cli)
|
||||
# @option opts [Boolean] :smallest (see #smallest)
|
||||
# @raise [KeyError] if framework is not provided in the options hash
|
||||
def initialize(opts={})
|
||||
@add_code = opts.fetch(:add_code, '')
|
||||
|
@ -113,12 +117,20 @@ module Msf
|
|||
@stdin = opts.fetch(:stdin, nil)
|
||||
@template = opts.fetch(:template, '')
|
||||
@var_name = opts.fetch(:var_name, 'buf')
|
||||
@smallest = opts.fetch(:smallest, false)
|
||||
@encoder_space = opts.fetch(:encoder_space, @space)
|
||||
|
||||
@framework = opts.fetch(:framework)
|
||||
|
||||
raise ArgumentError, "Invalid Payload Selected" unless payload_is_valid?
|
||||
raise ArgumentError, "Invalid Format Selected" unless format_is_valid?
|
||||
|
||||
# In smallest mode, override the payload @space & @encoder_space settings
|
||||
if @smallest
|
||||
@space = 0
|
||||
@encoder_space = 1.gigabyte
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# This method takes the shellcode generated so far and adds shellcode from
|
||||
|
@ -199,24 +211,36 @@ module Msf
|
|||
encoder_list = get_encoders
|
||||
if encoder_list.empty?
|
||||
cli_print "No encoder or badchars specified, outputting raw payload"
|
||||
shellcode
|
||||
else
|
||||
cli_print "Found #{encoder_list.count} compatible encoders"
|
||||
encoder_list.each do |encoder_mod|
|
||||
cli_print "Attempting to encode payload with #{iterations} iterations of #{encoder_mod.refname}"
|
||||
begin
|
||||
encoder_mod.available_space = @encoder_space
|
||||
return run_encoder(encoder_mod, shellcode.dup)
|
||||
rescue ::Msf::EncoderSpaceViolation => e
|
||||
cli_print "#{encoder_mod.refname} failed with #{e.message}"
|
||||
next
|
||||
rescue ::Msf::EncodingError => e
|
||||
cli_print "#{encoder_mod.refname} failed with #{e.message}"
|
||||
next
|
||||
end
|
||||
return shellcode
|
||||
end
|
||||
|
||||
results = {}
|
||||
|
||||
cli_print "Found #{encoder_list.count} compatible encoders"
|
||||
encoder_list.each do |encoder_mod|
|
||||
cli_print "Attempting to encode payload with #{iterations} iterations of #{encoder_mod.refname}"
|
||||
begin
|
||||
encoder_mod.available_space = @encoder_space unless @smallest
|
||||
results[encoder_mod.refname] = run_encoder(encoder_mod, shellcode.dup)
|
||||
break unless @smallest
|
||||
rescue ::Msf::EncoderSpaceViolation => e
|
||||
cli_print "#{encoder_mod.refname} failed with #{e.message}"
|
||||
next
|
||||
rescue ::Msf::EncodingError => e
|
||||
cli_print "#{encoder_mod.refname} failed with #{e.message}"
|
||||
next
|
||||
end
|
||||
end
|
||||
|
||||
if results.keys.length == 0
|
||||
raise ::Msf::EncodingError, "No Encoder Succeeded"
|
||||
end
|
||||
|
||||
# Return the shortest encoding of the payload
|
||||
chosen_encoder = results.keys.sort{|a,b| results[a].length <=> results[b].length}.first
|
||||
cli_print "#{chosen_encoder} chosen with final size #{results[chosen_encoder].length}"
|
||||
|
||||
results[chosen_encoder]
|
||||
end
|
||||
|
||||
# This returns a hash for the exe format generation of payloads
|
||||
|
@ -351,7 +375,7 @@ module Msf
|
|||
e.datastore.import_options_from_hash(datastore)
|
||||
encoders << e if e
|
||||
end
|
||||
encoders.sort_by { |my_encoder| my_encoder.rank }.reverse
|
||||
encoders.select{ |my_encoder| my_encoder.rank != ManualRanking }.sort_by { |my_encoder| my_encoder.rank }.reverse
|
||||
else
|
||||
encoders
|
||||
end
|
||||
|
|
|
@ -1270,8 +1270,8 @@ class Db
|
|||
end
|
||||
end
|
||||
if search_term
|
||||
note_list.delete_if do |n|
|
||||
!n.attribute_names.any? { |a| n[a.intern].to_s.match(search_term) }
|
||||
note_list = note_list.select do |n|
|
||||
n.attribute_names.any? { |a| n[a.intern].to_s.match(search_term) }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -34,12 +34,12 @@ class Metasploit3 < Msf::Encoder
|
|||
end
|
||||
|
||||
if state.badchars.include?("-")
|
||||
raise RuntimeError
|
||||
raise EncodingError
|
||||
else
|
||||
# Without an escape character we can't escape anything, so echo
|
||||
# won't work.
|
||||
if state.badchars.include?("\\")
|
||||
raise RuntimeError
|
||||
raise EncodingError
|
||||
else
|
||||
buf = encode_block_bash_echo(state,buf)
|
||||
end
|
||||
|
@ -68,7 +68,7 @@ class Metasploit3 < Msf::Encoder
|
|||
if state.badchars.include?("`")
|
||||
# Last ditch effort, dollar paren
|
||||
if state.badchars.include?("$") or state.badchars.include?("(")
|
||||
raise RuntimeError
|
||||
raise EncodingError
|
||||
else
|
||||
buf = "$(/bin/echo -ne #{hex})"
|
||||
end
|
||||
|
|
|
@ -68,7 +68,7 @@ class Metasploit3 < Msf::Encoder
|
|||
state.badchars.unpack('C*') { |c| qot.delete(c.chr) }
|
||||
|
||||
# Throw an error if we ran out of quotes
|
||||
raise RuntimeError if qot.length == 0
|
||||
raise EncodingError if qot.length == 0
|
||||
|
||||
sep = qot[0].chr
|
||||
|
||||
|
@ -83,7 +83,7 @@ class Metasploit3 < Msf::Encoder
|
|||
if (state.badchars.match(/\(|\)/))
|
||||
|
||||
# No paranthesis...
|
||||
raise RuntimeError
|
||||
raise EncodingError
|
||||
end
|
||||
|
||||
cmd << "system\\(pack\\(qq#{sep}H\\*#{sep},qq#{sep}#{hex}#{sep}\\)\\)"
|
||||
|
@ -92,7 +92,7 @@ class Metasploit3 < Msf::Encoder
|
|||
if (state.badchars.match(/\(|\)/))
|
||||
if (state.badchars.include?(" "))
|
||||
# No spaces allowed, no paranthesis, give up...
|
||||
raise RuntimeError
|
||||
raise EncodingError
|
||||
end
|
||||
|
||||
cmd << "'system pack qq#{sep}H*#{sep},qq#{sep}#{hex}#{sep}'"
|
||||
|
@ -124,7 +124,7 @@ class Metasploit3 < Msf::Encoder
|
|||
if (state.badchars.include?("`"))
|
||||
# Last ditch effort, dollar paren
|
||||
if (state.badchars.include?("$") or state.badchars.include?("("))
|
||||
raise RuntimeError
|
||||
raise EncodingError
|
||||
else
|
||||
buf = "$(/bin/echo -ne #{hex})"
|
||||
end
|
||||
|
|
|
@ -35,7 +35,7 @@ class Metasploit3 < Msf::Encoder
|
|||
end
|
||||
|
||||
if state.badchars.include?("-")
|
||||
raise RuntimeError
|
||||
raise EncodingError
|
||||
else
|
||||
buf = encode_block_perl(state,buf)
|
||||
end
|
||||
|
@ -55,7 +55,7 @@ class Metasploit3 < Msf::Encoder
|
|||
# Convert spaces to IFS...
|
||||
if state.badchars.include?(" ")
|
||||
if state.badchars.match(/[${IFS}]/n)
|
||||
raise RuntimeError
|
||||
raise EncodingError
|
||||
end
|
||||
cmd.gsub!(/\s/, '${IFS}')
|
||||
end
|
||||
|
@ -118,7 +118,7 @@ class Metasploit3 < Msf::Encoder
|
|||
state.badchars.unpack('C*') { |c| qot.delete(c.chr) }
|
||||
|
||||
# Throw an error if we ran out of quotes
|
||||
raise RuntimeError if qot.length == 0
|
||||
raise EncodingError if qot.length == 0
|
||||
|
||||
sep = qot[0].chr
|
||||
# Use an explicit length for the H specifier instead of just "H*"
|
||||
|
|
|
@ -50,7 +50,7 @@ class Metasploit3 < Msf::Encoder
|
|||
(state.badchars.include?("|")) or
|
||||
# We must have at least ONE of these two..
|
||||
(state.badchars.include?("x") and state.badchars.include?("0"))
|
||||
raise RuntimeError
|
||||
raise EncodingError
|
||||
end
|
||||
|
||||
# Now we build a string of the original payload with bad characters
|
||||
|
|
|
@ -44,7 +44,7 @@ class Metasploit3 < Msf::Encoder::Xor
|
|||
# add 4 number of passes for the space reserved for the key, at the end of the decoder stub
|
||||
# (see commented source)
|
||||
number_of_passes=state.buf.length+4
|
||||
raise InvalidPayloadSizeException.new("The payload being encoded is too long (#{state.buf.length} bytes)") if number_of_passes > 32766
|
||||
raise EncodingError.new("The payload being encoded is too long (#{state.buf.length} bytes)") if number_of_passes > 32766
|
||||
|
||||
# 16-bits not (again, see also commented source)
|
||||
reg_14 = (number_of_passes+1)^0xFFFF
|
||||
|
|
|
@ -35,8 +35,8 @@ class Metasploit3 < Msf::Encoder::Xor
|
|||
|
||||
# add one xor operation for the key (see comment below)
|
||||
number_of_passes=state.buf.length/4+1
|
||||
raise InvalidPayloadSizeException.new("The payload being encoded is too long (#{state.buf.length} bytes)") if number_of_passes > 10240
|
||||
raise InvalidPayloadSizeException.new("The payload is not padded to 4-bytes (#{state.buf.length} bytes)") if state.buf.length%4 != 0
|
||||
raise EncodingError.new("The payload being encoded is too long (#{state.buf.length} bytes)") if number_of_passes > 10240
|
||||
raise EncodingError.new("The payload is not padded to 4-bytes (#{state.buf.length} bytes)") if state.buf.length%4 != 0
|
||||
|
||||
# 16-bits not (again, see below)
|
||||
reg_14 = (number_of_passes+1)^0xFFFF
|
||||
|
|
|
@ -44,7 +44,7 @@ class Metasploit3 < Msf::Encoder::Xor
|
|||
# add 4 number of passes for the space reserved for the key, at the end of the decoder stub
|
||||
# (see commented source)
|
||||
number_of_passes=state.buf.length+4
|
||||
raise InvalidPayloadSizeException.new("The payload being encoded is too long (#{state.buf.length} bytes)") if number_of_passes > 32766
|
||||
raise EncodingError.new("The payload being encoded is too long (#{state.buf.length} bytes)") if number_of_passes > 32766
|
||||
|
||||
# 16-bits not (again, see also commented source)
|
||||
reg_14 = (number_of_passes+1)^0xFFFF
|
||||
|
|
|
@ -35,8 +35,8 @@ class Metasploit3 < Msf::Encoder::Xor
|
|||
|
||||
# add one xor operation for the key (see comment below)
|
||||
number_of_passes=state.buf.length/4+1
|
||||
raise InvalidPayloadSizeException.new("The payload being encoded is too long (#{state.buf.length} bytes)") if number_of_passes > 10240
|
||||
raise InvalidPayloadSizeException.new("The payload is not padded to 4-bytes (#{state.buf.length} bytes)") if state.buf.length%4 != 0
|
||||
raise EncodingError.new("The payload being encoded is too long (#{state.buf.length} bytes)") if number_of_passes > 10240
|
||||
raise EncodingError.new("The payload is not padded to 4-bytes (#{state.buf.length} bytes)") if state.buf.length%4 != 0
|
||||
|
||||
# 16-bits not (again, see below)
|
||||
reg_14 = (number_of_passes+1)^0xFFFF
|
||||
|
|
|
@ -27,7 +27,7 @@ class Metasploit3 < Msf::Encoder
|
|||
# Have to have these for the decoder stub, so if they're not available,
|
||||
# there's nothing we can do here.
|
||||
["(",")",".","_","c","h","r","e","v","a","l","b","s","6","4","d","o"].each do |c|
|
||||
raise EncodeError if state.badchars.include?(c)
|
||||
raise BadcharError if state.badchars.include?(c)
|
||||
end
|
||||
|
||||
# PHP escapes quotes by default with magic_quotes_gpc, so we use some
|
||||
|
|
|
@ -99,7 +99,7 @@ class Metasploit3 < Msf::Encoder
|
|||
@inst = {}
|
||||
@set = add_or_sub(@avchars)
|
||||
if @set == 0 then
|
||||
raise RuntimeError, "Bad character list includes essential characters."
|
||||
raise EncodingError, "Bad character list includes essential characters."
|
||||
exit
|
||||
elsif @set == 1 then #add
|
||||
@inst["opcode"] = 0x05
|
||||
|
@ -112,7 +112,7 @@ class Metasploit3 < Msf::Encoder
|
|||
@inst["push_esp"] = 0x54
|
||||
@inst["pop_esp"] = 0x5c
|
||||
if state.buf.size%4 != 0 then
|
||||
raise RuntimeError, "Shellcode size must be divisible by 4, try nop padding."
|
||||
raise EncodingError, "Shellcode size must be divisible by 4, try nop padding."
|
||||
exit
|
||||
end
|
||||
#init
|
||||
|
|
|
@ -44,7 +44,7 @@ class Metasploit3 < Msf::Encoder::Alphanum
|
|||
else
|
||||
res = Rex::Arch::X86.geteip_fpu(state.badchars)
|
||||
if (not res)
|
||||
raise RuntimeError, "Unable to generate geteip code"
|
||||
raise EncodingError, "Unable to generate geteip code"
|
||||
end
|
||||
buf, reg, off = res
|
||||
end
|
||||
|
|
|
@ -47,7 +47,7 @@ class Metasploit3 < Msf::Encoder::Alphanum
|
|||
else
|
||||
res = Rex::Arch::X86.geteip_fpu(state.badchars)
|
||||
if (not res)
|
||||
raise RuntimeError, "Unable to generate geteip code"
|
||||
raise EncodingError, "Unable to generate geteip code"
|
||||
end
|
||||
buf, reg, off = res
|
||||
end
|
||||
|
|
|
@ -90,20 +90,6 @@ require 'msf/core'
|
|||
#
|
||||
class Metasploit3 < Msf::Encoder
|
||||
|
||||
#
|
||||
# In some cases, payloads can be an invalid size that is incompatible with
|
||||
# this encoder
|
||||
#
|
||||
class InvalidPayloadSizeException < ::Exception
|
||||
def initialize(msg)
|
||||
@msg = msg
|
||||
end
|
||||
|
||||
def to_s
|
||||
@msg
|
||||
end
|
||||
end
|
||||
|
||||
# This encoder has a manual ranking because it should only be used in cases
|
||||
# where information has been explicitly supplied, like the BufferOffset.
|
||||
Rank = ManualRanking
|
||||
|
@ -136,7 +122,7 @@ class Metasploit3 < Msf::Encoder
|
|||
|
||||
# Check to make sure that the length is a valid size
|
||||
if is_badchar(state, len)
|
||||
raise InvalidPayloadSizeException.new("The payload being encoded is of an incompatible size (#{len} bytes)")
|
||||
raise EncodingError.new("The payload being encoded is of an incompatible size (#{len} bytes)")
|
||||
end
|
||||
|
||||
decoder =
|
||||
|
|
|
@ -161,11 +161,11 @@ class Metasploit3 < Msf::Encoder
|
|||
|
||||
# determine if we have any invalid characters that we rely on.
|
||||
unless all_bytes_valid
|
||||
raise RuntimeError, "Bad character set contains characters that are required for this encoder to function."
|
||||
raise EncodingError, "Bad character set contains characters that are required for this encoder to function."
|
||||
end
|
||||
|
||||
unless @asm['PUSH'][@base_reg]
|
||||
raise RuntimeError, "Invalid base register"
|
||||
raise EncodingError, "Invalid base register"
|
||||
end
|
||||
|
||||
# get the offset from the specified base register, or default to zero if not specifed
|
||||
|
@ -176,7 +176,7 @@ class Metasploit3 < Msf::Encoder
|
|||
|
||||
# if we can't then we bomb, because we know we need to clear out EAX at least once
|
||||
unless @clear1
|
||||
raise RuntimeError, "Unable to find AND-able chars resulting 0 in the valid character set."
|
||||
raise EncodingError, "Unable to find AND-able chars resulting 0 in the valid character set."
|
||||
end
|
||||
|
||||
protect_payload = (datastore['OverwriteProtect'] || "").downcase == "true"
|
||||
|
@ -288,7 +288,7 @@ class Metasploit3 < Msf::Encoder
|
|||
# Write out a stubbed placeholder for the offset instruction based on
|
||||
# the base register, we'll update this later on when we know how big our payload is.
|
||||
encoded, _ = sub_3(0, 0)
|
||||
raise RuntimeError, "Couldn't offset base register." if encoded.nil?
|
||||
raise EncodingError, "Couldn't offset base register." if encoded.nil?
|
||||
data << create_sub(encoded)
|
||||
|
||||
# finally push the value of EAX back into ESP
|
||||
|
@ -312,7 +312,7 @@ class Metasploit3 < Msf::Encoder
|
|||
end
|
||||
|
||||
# if we're still nil here, then we have an issue
|
||||
raise RuntimeError, "Couldn't encode payload" if encoded.nil?
|
||||
raise EncodingError, "Couldn't encode payload" if encoded.nil?
|
||||
|
||||
data << create_sub(encoded)
|
||||
end
|
||||
|
@ -324,7 +324,7 @@ class Metasploit3 < Msf::Encoder
|
|||
encoded, _ = sub_3(total_offset, 0)
|
||||
|
||||
# if we're still nil here, then we have an issue
|
||||
raise RuntimeError, "Couldn't encode protection" if encoded.nil?
|
||||
raise EncodingError, "Couldn't encode protection" if encoded.nil?
|
||||
patch = create_sub(encoded)
|
||||
|
||||
# patch in the correct offset back at the start of our payload
|
||||
|
|
|
@ -281,7 +281,7 @@ protected
|
|||
begin
|
||||
# Generate a permutation saving the ECX, ESP, and user defined registers
|
||||
loop_inst.generate(block_generator_register_blacklist, nil, state.badchars)
|
||||
rescue RuntimeError => e
|
||||
rescue EncodingError => e
|
||||
raise EncodingError
|
||||
end
|
||||
end
|
||||
|
|
|
@ -37,7 +37,7 @@ class Metasploit3 < Msf::Encoder::Alphanum
|
|||
reg = datastore['BufferRegister']
|
||||
offset = datastore['BufferOffset'].to_i || 0
|
||||
if (not reg)
|
||||
raise RuntimeError, "Need BufferRegister"
|
||||
raise EncodingError, "Need BufferRegister"
|
||||
end
|
||||
Rex::Encoder::Alpha2::UnicodeMixed::gen_decoder(reg, offset)
|
||||
end
|
||||
|
|
|
@ -37,7 +37,7 @@ class Metasploit3 < Msf::Encoder::Alphanum
|
|||
reg = datastore['BufferRegister']
|
||||
offset = datastore['BufferOffset'].to_i || 0
|
||||
if (not reg)
|
||||
raise RuntimeError, "Need BufferRegister"
|
||||
raise EncodingError, "Need BufferRegister"
|
||||
end
|
||||
Rex::Encoder::Alpha2::UnicodeUpper::gen_decoder(reg, offset)
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue