Skip to content

Commit a6f416e

Browse files
committed
Land rapid7#8290, Hwbridge Automotive Fix and Extension Enhancements
2 parents 90c86db + d0b1354 commit a6f416e

File tree

12 files changed

+578
-364
lines changed

12 files changed

+578
-364
lines changed

lib/msf/core/post/hardware/automotive/dtc.rb

Lines changed: 298 additions & 298 deletions
Large diffs are not rendered by default.

lib/msf/core/post/hardware/automotive/uds.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ def get_dtcs(bus, src_id, dst_id, opt = {})
393393
end
394394
if (data.key? "Packets") && !data["Packets"].empty?
395395
data = response_hash_to_data_array(dst_id, data, 4)
396-
if !data.empty? && data.even?
396+
if !data.empty? && data.size.even?
397397
(0..data.size / 2).step(2) do |idx|
398398
code = ""
399399
case data[idx].hex & 0xC0 >> 3

lib/msf/core/post/hardware/zigbee/utils.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -220,26 +220,26 @@ def dot154_packet_decode(packet)
220220
daddr_mask = (fcf & DOT154_FCF_DADDR_MASK) >> 10
221221
if daddr_mask == DOT154_FCF_ADDR_EXT
222222
pktchop[3] = packet[offset,8]
223-
offset+=8
223+
offset += 8
224224
elsif daddr_mask == DOT154_FCF_ADDR_SHORT
225225
pktchop[3] = packet[offset,2]
226-
offset+=2
226+
offset += 2
227227
end
228228

229229
# Examine the Intra-PAN flag
230230
if (fcf & DOT154_FCF_INTRA_PAN) == 0
231231
pktchop[4] = packet[offset,2]
232-
offset+=2
232+
offset += 2
233233
end
234234

235235
# Examine the source addressing mode
236236
saddr_mask = (fcf & DOT154_FCF_SADDR_MASK) >> 14
237237
if daddr_mask == DOT154_FCF_ADDR_EXT
238238
pktchop[5] = packet[offset,8]
239-
offset+=8
239+
offset += 8
240240
elsif daddr_mask == DOT154_FCF_ADDR_SHORT
241241
pktchop[5] = packet[offset,2]
242-
offset+=2
242+
offset += 2
243243
end
244244
end
245245
# Append remaining payload

lib/rex/post/hwbridge/client.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@ def get_status
6363
send_request("/status")
6464
end
6565

66+
#
67+
# Gets the devices statistics
68+
#
69+
def get_statistics
70+
send_request("/statistics")
71+
end
72+
6673
#
6774
# Fetches custom methods from HW, if any
6875
#

lib/rex/post/hwbridge/extensions/automotive/automotive.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def is_valid_bus?(bus)
4141
valid = false
4242
get_supported_buses if buses.nil?
4343
unless bus.blank?
44-
buses.each do |b|
44+
self.buses.each do |b|
4545
valid = true if b["bus_name"] == bus
4646
end
4747
end
@@ -86,8 +86,8 @@ def set_active_bus(bus)
8686
end
8787

8888
def get_supported_buses
89-
buses = client.send_request("/automotive/supported_buses")
90-
buses
89+
self.buses = client.send_request("/automotive/supported_buses")
90+
self.buses
9191
end
9292

9393
def get_bus_config(bus)

lib/rex/post/hwbridge/extensions/automotive/uds_errors.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ module UDSErrors
5656
0x78 => "RCRRP",
5757
0x7E => "SFNSIAS",
5858
0x7F => "SNSIAS",
59-
0x81 => "RTH",
60-
0x82 => "RTL",
59+
0x81 => "RPMTH",
60+
0x82 => "RPMTL",
6161
0x83 => "EIR",
6262
0x84 => "EINR",
6363
0x85 => "ERTTL",
@@ -100,8 +100,8 @@ module UDSErrors
100100
"RCRRP" => "Request Correctly Received, but Response is Pending",
101101
"SFNSIAS" => "Sub-Function Not Supoorted In Active Session",
102102
"SNSIAS" => "Service Not Supported In Active Session",
103-
"RTH" => "RPM Too High",
104-
"RTL" => "RPM Too Low",
103+
"RPMTH" => "RPM Too High",
104+
"RPMTL" => "RPM Too Low",
105105
"EIR" => "Engine is Running",
106106
"EINR" => "Engine is not Running",
107107
"ERTTL" => "Engine Run Time Too Low",
@@ -117,7 +117,7 @@ module UDSErrors
117117
"SLNIP" => "Shifter Lever Not In Park",
118118
"TCCL" => "Torque Converter Clutch Locked",
119119
"VTH" => "Voltage Too High",
120-
"VTL" => "Voltage Too Low"
120+
"VTL" => "Voltage Too Low"
121121
}
122122

123123
end

lib/rex/post/hwbridge/ui/console/command_dispatcher/automotive.rb

Lines changed: 166 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ class Console::CommandDispatcher::Automotive
1313
include Console::CommandDispatcher
1414
include Msf::Auxiliary::Report
1515

16+
def initialize(shell)
17+
super
18+
self.tpjobs = []
19+
self.tpjob_id = 0
20+
end
21+
1622
#
1723
# List of supported commands.
1824
#
@@ -21,14 +27,17 @@ def commands
2127
'supported_buses' => 'Get supported buses',
2228
'busconfig' => 'Get baud configs',
2329
'connect' => 'Get HW supported methods for a bus',
24-
'cansend' => 'Send a CAN packet'
30+
'cansend' => 'Send a CAN packet',
31+
'isotpsend' => 'Send an ISO-TP Packet and get a response',
32+
'testerpresent' => 'Sends TesterPresent Pulses to the bus'
2533
}
2634

2735
reqs = {
2836
'supported_buses' => ['get_supported_buses'],
2937
'busconfig' => ['get_bus_config'],
3038
'connect' => ['get_supported_methods'],
31-
'cansend' => ['cansend']
39+
'cansend' => ['cansend'],
40+
'testerpresent' => ['testpresent']
3241
}
3342

3443
# Ensure any requirements of the command are met
@@ -106,9 +115,10 @@ def cmd_connect(*args)
106115
end
107116
unless client.automotive.is_valid_bus? bus
108117
print_error("You must specify a valid bus via -b")
118+
print_line("Current active bus: #{self.active_bus}") if self.active_bus
109119
return
110120
end
111-
active_bus = bus
121+
self.active_bus = bus
112122
client.automotive.set_active_bus(bus)
113123
hw_methods = client.automotive.get_supported_methods(bus)
114124
hw_methods
@@ -141,7 +151,7 @@ def cmd_cansend(*args)
141151
data = val
142152
end
143153
end
144-
bus = active_bus if bus.blank? && !active_bus.nil?
154+
bus = self.active_bus if bus.blank? && !self.active_bus.nil?
145155
unless client.automotive.is_valid_bus? bus
146156
print_error("You must specify a valid bus via -b")
147157
return
@@ -154,17 +164,167 @@ def cmd_cansend(*args)
154164
success
155165
end
156166

167+
#
168+
# Generic ISO-TP CAN send packet command
169+
#
170+
def cmd_isotpsend(*args)
171+
bus = ''
172+
id = ''
173+
ret = ''
174+
data = ''
175+
timeout = nil
176+
maxpackets = nil
177+
cansend_opts = Rex::Parser::Arguments.new(
178+
'-h' => [ false, 'Help Banner' ],
179+
'-b' => [ true, 'Target bus'],
180+
'-I' => [ true, 'CAN ID'],
181+
'-R' => [ true, 'Return ID'],
182+
'-D' => [ true, 'Data packet in Hex (Do not include ISOTP command size)'],
183+
'-t' => [ true, 'Timeout value'],
184+
'-m' => [ true, 'Max packets to receive']
185+
)
186+
cansend_opts.parse(args) do |opt, _idx, val|
187+
case opt
188+
when '-h'
189+
print_line("Usage: isotpsend -I <ID> -D <data>\n")
190+
print_line(cansend_opts.usage)
191+
return
192+
when '-b'
193+
bus = val
194+
when '-I'
195+
id = val
196+
when '-R'
197+
ret = val
198+
when '-D'
199+
data = val
200+
when '-t'
201+
timeout = val.to_i
202+
when '-m'
203+
maxpackets = val.to_i
204+
end
205+
end
206+
bus = self.active_bus if bus.blank? && !self.active_bus.nil?
207+
unless client.automotive.is_valid_bus? bus
208+
print_error("You must specify a valid bus via -b")
209+
return
210+
end
211+
if id.blank? || data.blank?
212+
print_error("You must specify a CAN ID (-I) and the data packets (-D)")
213+
return
214+
end
215+
if ret.blank?
216+
ret = (id.hex + 8).to_s(16)
217+
print_line("Default return set to #{ret}")
218+
end
219+
bytes = data.scan(/../) # Break up data string into 2 char (byte) chunks
220+
if bytes.size > 8
221+
print_error("Data section can only contain a max of 8 bytes (for now)")
222+
return
223+
end
224+
opt = {}
225+
opt['TIMEOUT'] = timeout unless timeout.nil?
226+
opt['MAXPKTS'] = maxpackets unless maxpackets.nil?
227+
result = client.automotive.send_isotp_and_wait_for_response(bus, id, ret, bytes, opt)
228+
if result.key? 'Packets'
229+
result['Packets'].each do |pkt|
230+
print_line pkt.inspect
231+
end
232+
end
233+
print_line(result['error'].inspect) if result.key? 'error'
234+
result
235+
end
236+
237+
#
238+
# Sends TesterPresent packets as a background job
239+
#
240+
def cmd_testerpresent(*args)
241+
bus = ''
242+
id = ''
243+
stop = false
244+
stopid = 0
245+
tp_opts = Rex::Parser::Arguments.new(
246+
'-h' => [ false, 'Help Banner' ],
247+
'-b' => [ true, 'Target bus' ],
248+
'-I' => [ true, 'CAN ID' ],
249+
'-x' => [ true, 'Stop TesterPresent JobID']
250+
)
251+
tp_opts.parse(args) do |opt, _idx, val|
252+
case opt
253+
when '-h'
254+
print_line("Usage: testerpresent -I <ID>\n")
255+
print_line(tp_opts.usage)
256+
return
257+
when '-b'
258+
bus = val
259+
when '-I'
260+
id = val
261+
when '-x'
262+
stop = true
263+
stopid = val.to_i
264+
end
265+
end
266+
bus = self.active_bus if bus.blank? && !self.active_bus.nil?
267+
unless client.automotive.is_valid_bus? bus
268+
print_error("You must specify a valid bus via -b")
269+
return
270+
end
271+
if id.blank? && !stop
272+
if self.tpjobs.size.positive?
273+
print_line("TesterPresent is currently active")
274+
self.tpjobs.each_index do |jid|
275+
if self.tpjobs[jid]
276+
print_status("TesterPresent Job #{jid}: #{self.tpjobs[jid][:args].inspect}")
277+
end
278+
end
279+
else
280+
print_line("TesterPreset is not active. Use -I to start")
281+
end
282+
return
283+
end
284+
if stop
285+
if self.tpjobs[stopid]
286+
self.tpjobs[stopid].kill
287+
self.tpjobs[stopid] = nil
288+
print_status("Stopped TesterPresent #{stopid}")
289+
else
290+
print_error("TesterPresent #{stopid} was not running")
291+
end
292+
else
293+
jid = self.tpjob_id
294+
print_status("Starting TesterPresent sender (#{self.tpjob_id})")
295+
self.tpjob_id += 1
296+
self.tpjobs[jid] = Rex::ThreadFactory.spawn("TesterPresent(#{id})-#{jid}", false, jid, args) do |myjid,xargs|
297+
::Thread.current[:args] = xargs.dup
298+
begin
299+
loop do
300+
client.automotive.cansend(bus, id, "023E00")
301+
sleep(2)
302+
end
303+
rescue ::Exception
304+
print_error("Error in TesterPResent: #{$!.class} #{$!}")
305+
elog("Error in TesterPreset: #{$!.class} #{$!}")
306+
dlog("Callstack: #{$@.join("\n")}")
307+
end
308+
self.tpjobs[myjid] = nil
309+
print_status("TesterPreset #{myjid} has stopped (#{::Thread.current[:args].inspect})")
310+
end
311+
end
312+
end
313+
157314
#
158315
# Name for this dispatcher
159316
#
160317
def name
161318
'Automotive'
162319
end
163320

164-
private
165-
166321
attr_accessor :active_bus
167322

323+
protected
324+
325+
attr_accessor :tpjobs, :tpjob_id # :nodoc:
326+
327+
168328
end
169329

170330
end

0 commit comments

Comments
 (0)