Skip to content

Commit f71ca92

Browse files
committed
Land rapid7#8801, Support padding on the CAN bus.
2 parents 83cd0bc + e157615 commit f71ca92

File tree

4 files changed

+119
-53
lines changed

4 files changed

+119
-53
lines changed

documentation/modules/post/hardware/automotive/getvinfo.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ PIDs to ASCII.
2424

2525
**CLEAR_DTCS***
2626

27-
If any Diagnostic Trouble Codes (DTCs) are present it will clear those and reset the MIL (Enginge Light)
27+
If any Diagnostic Trouble Codes (DTCs) are present it will clear those and reset the MIL (Engine Light).
28+
29+
**PADDING**
30+
31+
Optional byte-value to use for padding all CAN bus packets to an 8-byte length. Padding is disabled by default.
2832

2933
## Scenarios
3034

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

Lines changed: 84 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,13 @@ def get_current_data(bus, src_id, dst_id, pid, opt = {})
100100
# @param bus [String] unique CAN bus identifier
101101
# @param src_id [Integer] Integer representation of the Sending CAN ID
102102
# @param dst_id [Integer] Integer representation of the receiving CAN ID
103+
# @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response
103104
#
104105
# @return [Array] All supported pids from Mode $01 get current data
105-
def get_current_data_pids(bus, src_id, dst_id)
106+
def get_current_data_pids(bus, src_id, dst_id, opt={})
106107
pids = []
107-
packets = get_current_data(bus, src_id, dst_id, 0, { "MAXPKTS" => 1 })
108+
opt['MAXPKTS'] = 1
109+
packets = get_current_data(bus, src_id, dst_id, 0, opt)
108110
return pids if packets.nil?
109111
if (packets.key? "Packets") && !packets["Packets"].empty?
110112
hexpids = packets["Packets"][0]["DATA"][3, 6]
@@ -114,7 +116,7 @@ def get_current_data_pids(bus, src_id, dst_id)
114116
end
115117
end
116118
if pids.include? 0x20
117-
packets = get_current_data(bus, src_id, dst_id, 0x20, { "MAXPKTS" => 1 })
119+
packets = get_current_data(bus, src_id, dst_id, 0x20, opt)
118120
if (packets.key? "Packets") && !packets["Packets"].empty?
119121
hexpids = packets["Packets"][0]["DATA"][3, 6]
120122
hexpids = hexpids.join.hex.to_s(2).rjust(32, '0').split('') # Array of 1s and 0s
@@ -124,7 +126,7 @@ def get_current_data_pids(bus, src_id, dst_id)
124126
end
125127
end
126128
if pids.include? 0x40
127-
packets = get_current_data(bus, src_id, dst_id, 0x40, { "MAXPKTS" => 1 })
129+
packets = get_current_data(bus, src_id, dst_id, 0x40, opt)
128130
if (packets.key? "Packets") && !packets["Packets"].empty?
129131
hexpids = packets["Packets"][0]["DATA"][3, 6]
130132
hexpids = hexpids.join.hex.to_s(2).rjust(32, '0').split('') # Array of 1s and 0s
@@ -134,7 +136,7 @@ def get_current_data_pids(bus, src_id, dst_id)
134136
end
135137
end
136138
if pids.include? 0x60
137-
packets = get_current_data(bus, src_id, dst_id, 0x60, { "MAXPKTS" => 1 })
139+
packets = get_current_data(bus, src_id, dst_id, 0x60, opt)
138140
if (packets.key? "Packets") && !packets["Packets"].empty?
139141
hexpids = packets["Packets"][0]["DATA"][3, 6]
140142
hexpids = hexpids.join.hex.to_s(2).rjust(32, '0').split('') # Array of 1s and 0s
@@ -144,7 +146,7 @@ def get_current_data_pids(bus, src_id, dst_id)
144146
end
145147
end
146148
if pids.include? 0x80
147-
packets = get_current_data(bus, src_id, dst_id, 0x80, { "MAXPKTS" => 1 })
149+
packets = get_current_data(bus, src_id, dst_id, 0x80, opt)
148150
if (packets.key? "Packets") && !packets["Packets"].empty?
149151
hexpids = packets["Packets"][0]["DATA"][3, 6]
150152
hexpids = hexpids.join.hex.to_s(2).rjust(32, '0').split('') # Array of 1s and 0s
@@ -154,7 +156,7 @@ def get_current_data_pids(bus, src_id, dst_id)
154156
end
155157
end
156158
if pids.include? 0xA0
157-
packets = get_current_data(bus, src_id, dst_id, 0xA0, { "MAXPKTS" => 1 })
159+
packets = get_current_data(bus, src_id, dst_id, 0xA0, opt)
158160
if (packets.key? "Packets") && !packets["Packets"].empty?
159161
hexpids = packets["Packets"][0]["DATA"][3, 6]
160162
hexpids = hexpids.join.hex.to_s(2).rjust(32, '0').split('') # Array of 1s and 0s
@@ -164,7 +166,7 @@ def get_current_data_pids(bus, src_id, dst_id)
164166
end
165167
end
166168
if pids.include? 0xC0
167-
packets = get_current_data(bus, src_id, dst_id, 0xC0, { "MAXPKTS" => 1 })
169+
packets = get_current_data(bus, src_id, dst_id, 0xC0, opt)
168170
if (packets.key? "Packets") && !packets["Packets"].empty?
169171
hexpids = packets["Packets"][0]["DATA"][3, 6]
170172
hexpids = hexpids.join.hex.to_s(2).rjust(32, '0').split('') # Array of 1s and 0s
@@ -182,10 +184,12 @@ def get_current_data_pids(bus, src_id, dst_id)
182184
# @param bus [String] unique CAN bus identifier
183185
# @param src_id [Integer] Integer representation of the Sending CAN ID
184186
# @param dst_id [Integer] Integer representation of the receiving CAN ID
187+
# @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response
185188
#
186189
# @return [Hash] Packet Hash with { "MIL" => true|false "DTC_COUNT" => 0 }
187-
def get_monitor_status(bus, src_id, dst_id)
188-
packets = get_current_data(bus, src_id, dst_id, 0x01, { "MAXPKTS" => 1 })
190+
def get_monitor_status(bus, src_id, dst_id, opt = {})
191+
opt['MAXPKTS'] = 1
192+
packets = get_current_data(bus, src_id, dst_id, 0x01, opt)
189193
return {} if packets.nil?
190194
return packets if packets.key? "error"
191195
return packets unless packets.key? "Packets"
@@ -200,10 +204,12 @@ def get_monitor_status(bus, src_id, dst_id)
200204
# @param bus [String] unique CAN bus identifier
201205
# @param src_id [Integer] Integer representation of the Sending CAN ID
202206
# @param dst_id [Integer] Integer representation of the receiving CAN ID
207+
# @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response
203208
#
204209
# @return [Hash] Packet Hash with { "TEMP_C" => <Celcious Temp>, "TEMP_F" => <Fahrenheit TEmp> }
205-
def get_engine_coolant_temp(bus, src_id, dst_id)
206-
packets = get_current_data(bus, src_id, dst_id, 0x05, { "MAXPKTS" => 1 })
210+
def get_engine_coolant_temp(bus, src_id, dst_id, opt = {})
211+
opt['MAXPKTS'] = 1
212+
packets = get_current_data(bus, src_id, dst_id, 0x05, opt)
207213
return {} if packets.nil?
208214
return packets if packets.key? "error"
209215
return packets unless packets.key? "Packets"
@@ -220,10 +226,12 @@ def get_engine_coolant_temp(bus, src_id, dst_id)
220226
# @param bus [String] unique CAN bus identifier
221227
# @param src_id [Integer] Integer representation of the Sending CAN ID
222228
# @param dst_id [Integer] Integer representation of the receiving CAN ID
229+
# @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response
223230
#
224231
# @return [Hash] Packet Hash with { "RPM" => <RPMs> }
225-
def get_rpms(bus, src_id, dst_id)
226-
packets = get_current_data(bus, src_id, dst_id, 0x0C, { "MAXPKTS" => 1 })
232+
def get_rpms(bus, src_id, dst_id, opt = {})
233+
opt['MAXPKTS'] = 1
234+
packets = get_current_data(bus, src_id, dst_id, 0x0C, opt)
227235
return {} if packets.nil?
228236
return packets if packets.key? "error"
229237
return packets unless packets.key? "Packets"
@@ -237,10 +245,12 @@ def get_rpms(bus, src_id, dst_id)
237245
# @param bus [String] unique CAN bus identifier
238246
# @param src_id [Integer] Integer representation of the Sending CAN ID
239247
# @param dst_id [Integer] Integer representation of the receiving CAN ID
248+
# @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response
240249
#
241250
# @return [Hash] Packet Hash with { "SPEED_K" => <km/h>, "SPEED_M" => <mph> }
242-
def get_vehicle_speed(bus, src_id, dst_id)
243-
packets = get_current_data(bus, src_id, dst_id, 0x0D, { "MAXPKTS" => 1 })
251+
def get_vehicle_speed(bus, src_id, dst_id, opt = {})
252+
opt['MAXPKTS'] = 1
253+
packets = get_current_data(bus, src_id, dst_id, 0x0D, opt)
244254
return {} if packets.nil?
245255
return packets if packets.key? "error"
246256
return packets unless packets.key? "Packets"
@@ -256,10 +266,12 @@ def get_vehicle_speed(bus, src_id, dst_id)
256266
# @param bus [String] unique CAN bus identifier
257267
# @param src_id [Integer] Integer representation of the Sending CAN ID
258268
# @param dst_id [Integer] Integer representation of the receiving CAN ID
269+
# @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response
259270
#
260271
# @return [String] Description of standard
261-
def get_obd_standards(bus, src_id, dst_id)
262-
packets = get_current_data(bus, src_id, dst_id, 0x1C, { "MAXPKTS" => 1 })
272+
def get_obd_standards(bus, src_id, dst_id, opt = {})
273+
opt['MAXPKTS'] = 1
274+
packets = get_current_data(bus, src_id, dst_id, 0x1C, opt)
263275
return "" if packets.nil?
264276
if packets.key? "error"
265277
print_error("OBD ERR: #{packets['error']}")
@@ -532,11 +544,13 @@ def get_vehicle_info(bus, src_id, dst_id, mode, opt = {})
532544
# @param bus [String] unique CAN bus identifier
533545
# @param src_id [Integer] Integer representation of the Sending CAN ID
534546
# @param dst_id [Integer] Integer representation of the receiving CAN ID
547+
# @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response
535548
#
536549
# @return [Array] Array of PIDS supported by Mode $09
537-
def get_vinfo_supported_pids(bus, src_id, dst_id)
550+
def get_vinfo_supported_pids(bus, src_id, dst_id, opt = {})
551+
opt['MAXPKTS'] = 1
538552
pids = []
539-
packets = get_vehicle_info(bus, src_id, dst_id, 0, { "MAXPKTS" => 1 })
553+
packets = get_vehicle_info(bus, src_id, dst_id, 0, opt)
540554
return pids if packets.nil?
541555
if (packets.key? "Packets") && !packets["Packets"].empty?
542556
unless packets["Packets"][0]["DATA"][1].hex == 0x49
@@ -558,10 +572,11 @@ def get_vinfo_supported_pids(bus, src_id, dst_id)
558572
# @param bus [String] unique CAN bus identifier
559573
# @param src_id [Integer] Integer representation of the Sending CAN ID
560574
# @param dst_id [Integer] Integer representation of the receiving CAN ID
575+
# @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response
561576
#
562577
# @return [String] VIN as ASCII
563-
def get_vin(bus, src_id, dst_id)
564-
packets = get_vehicle_info(bus, src_id, dst_id, 0x02)
578+
def get_vin(bus, src_id, dst_id, opt = {})
579+
packets = get_vehicle_info(bus, src_id, dst_id, 0x02, opt)
565580
return "" if packets.nil?
566581
return "UDS ERR: #{packets['error']}" if packets.key? "error"
567582
data = response_hash_to_data_array(dst_id.to_s(16), packets)
@@ -575,10 +590,11 @@ def get_vin(bus, src_id, dst_id)
575590
# @param bus [String] unique CAN bus identifier
576591
# @param src_id [Integer] Integer representation of the Sending CAN ID
577592
# @param dst_id [Integer] Integer representation of the receiving CAN ID
593+
# @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response
578594
#
579595
# @return [String] Calibration ID as ASCII
580-
def get_calibration_id(bus, src_id, dst_id)
581-
packets = get_vehicle_info(bus, src_id, dst_id, 0x04)
596+
def get_calibration_id(bus, src_id, dst_id, opt = {})
597+
packets = get_vehicle_info(bus, src_id, dst_id, 0x04, opt)
582598
return "" if packets.nil?
583599
return "UDS ERR: #{packets['error']}" if packets.key? "error"
584600
data = response_hash_to_data_array(dst_id.to_s(16), packets)
@@ -592,10 +608,11 @@ def get_calibration_id(bus, src_id, dst_id)
592608
# @param bus [String] unique CAN bus identifier
593609
# @param src_id [Integer] Integer representation of the Sending CAN ID
594610
# @param dst_id [Integer] Integer representation of the receiving CAN ID
611+
# @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response
595612
#
596613
# @return [String] ECU Name as ASCII
597-
def get_ecu_name(bus, src_id, dst_id)
598-
packets = get_vehicle_info(bus, src_id, dst_id, 0x0A)
614+
def get_ecu_name(bus, src_id, dst_id, opt = {})
615+
packets = get_vehicle_info(bus, src_id, dst_id, 0x0A, opt)
599616
return "" if packets.nil?
600617
return "UDS ERR: #{packets['error']}" if packets.key? "error"
601618
data = response_hash_to_data_array(dst_id.to_s(16), packets)
@@ -616,9 +633,10 @@ def get_ecu_name(bus, src_id, dst_id)
616633
# @param src_id [Integer] Integer representation of the Sending CAN ID
617634
# @param dst_id [Integer] Integer representation of the receiving CAN ID
618635
# @param level [Integer] The desired DSC level
636+
# @param opt [Hash] Optional arguments. PADDING if set uses this hex value for padding
619637
#
620638
# @return [Hash] client.automtoive response
621-
def set_dsc(bus, src_id, dst_id, level)
639+
def set_dsc(bus, src_id, dst_id, level, opt = {})
622640
unless client.automotive
623641
print_error("Not an automotive hwbridge session")
624642
return {}
@@ -631,9 +649,12 @@ def set_dsc(bus, src_id, dst_id, level)
631649
print_line("No active bus, use 'connect' or specify bus via the options")
632650
return {}
633651
end
652+
padding = nil
653+
padding = opt['PADDING'] if opt.key? 'PADDING'
634654
opt = {}
635655
opt["TIMEOUT"] = 20
636656
opt["MAXPKTS"] = 1
657+
opt["PADDING"] = padding unless padding.nil?
637658
client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x10, level], opt)
638659
end
639660

@@ -674,10 +695,11 @@ def reset_ecu(bus, src_id, dst_id, hard, opt = {})
674695
# @param src_id [Integer] Integer representation of the Sending CAN ID
675696
# @param dst_id [Integer] Integer representation of the receiving CAN ID
676697
# @param id [Array] 2 Bytes in an array of the identifier. Example [ 0xF1, 0x90 ]
677-
# @param show_error [Boolean] If an error, return the Packet hash instead, Default false
698+
# @param opt [Hash] Additional Options. SHOW_ERROR (Returns packet hash instead, default false)
699+
# PADDING if set uses this hex value for padding
678700
#
679701
# @return [Array] Data retrieved. If show_error is true and an error is detected, then packet hash will be returned instead
680-
def read_data_by_id(bus, src_id, dst_id, id, show_error = false)
702+
def read_data_by_id(bus, src_id, dst_id, id, opt = {})
681703
data = []
682704
unless client.automotive
683705
print_error("Not an automotive hwbridge session")
@@ -702,14 +724,22 @@ def read_data_by_id(bus, src_id, dst_id, id, show_error = false)
702724
print_line("No active bus, use 'connect' or specify bus via the options")
703725
return {}
704726
end
727+
show_error = false
728+
padding = nil
729+
show_error = true if opt.key? 'SHOW_ERROR'
730+
padding = opt['PADDING'] if opt.key? 'PADDING'
705731
opt = {}
706732
opt["MAXPKTS"] = 15
733+
opt["PADDING"] = padding unless padding.nil?
707734
packets = client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x22] + id, opt)
708735
return [] if packets.nil?
709736
if packets.key? "error"
710737
return packets if show_error
711738
else
712739
data = response_hash_to_data_array(dst_id, packets)
740+
if id.size > 1 # Remove IDs from return
741+
data = data[(id.size-1)..data.size]
742+
end
713743
end
714744
data
715745
end
@@ -723,9 +753,10 @@ def read_data_by_id(bus, src_id, dst_id, id, show_error = false)
723753
# @param src_id [Integer] Integer representation of the Sending CAN ID
724754
# @param dst_id [Integer] Integer representation of the receiving CAN ID
725755
# @param level [Integer] Requested security access level. Default is 1
756+
# @param opt [Hash] Optional settings. PADDING if set uses this hex value for padding
726757
#
727758
# @return [Hash] Packet Hash with { "SEED" => [ XX, XX ] }
728-
def get_security_token(bus, src_id, dst_id, level = 1)
759+
def get_security_token(bus, src_id, dst_id, level = 1, opt = {})
729760
unless client.automotive
730761
print_error("Not an automotive hwbridge session")
731762
return {}
@@ -738,8 +769,11 @@ def get_security_token(bus, src_id, dst_id, level = 1)
738769
print_line("No active bus, use 'connect' or specify bus via the options")
739770
return {}
740771
end
772+
padding = nil
773+
padding = opt['PADDING'] if opt.key? 'PADDING'
741774
opt = {}
742-
opt["MAXPKTS"] = 1
775+
opt["MAXPKTS"] = 2
776+
opt["PADDING"] = padding unless padding.nil?
743777
packets = client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x27, level], opt)
744778
return {} if packets.nil?
745779
unless packets.key? "error"
@@ -754,11 +788,12 @@ def get_security_token(bus, src_id, dst_id, level = 1)
754788
# @param bus [String] unique CAN bus identifier
755789
# @param src_id [Integer] Integer representation of the Sending CAN ID
756790
# @param dst_id [Integer] Integer representation of the receiving CAN ID
757-
# param key [Array] Array of Hex to be used as the key. Same size as the seed
791+
# @param key [Array] Array of Hex to be used as the key. Same size as the seed
758792
# @param response_level [Integer] Requested security access level response. Usually level + 1. Default is 2
793+
# @param opt [Hash] Optional settings. PADDING if set uses this hex value for padding
759794
#
760795
# @return [Hash] packet response from client.automotoive
761-
def send_security_token_response(bus, src_id, dst_id, key, response_level = 2)
796+
def send_security_token_response(bus, src_id, dst_id, key, response_level = 2, opt = {})
762797
unless client.automotive
763798
print_error("Not an automotive hwbridge session")
764799
return {}
@@ -776,8 +811,11 @@ def send_security_token_response(bus, src_id, dst_id, key, response_level = 2)
776811
print_line("No active bus, use 'connect' or specify bus via the options")
777812
return {}
778813
end
814+
padding = nil
815+
padding = opt['PADDING'] if opt.key? 'PADDING'
779816
opt = {}
780-
opt["MAXPKTS"] = 1
817+
opt["MAXPKTS"] = 2
818+
opt["PADDING"] = padding unless padding.nil?
781819
client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x27, response_level] + key, opt)
782820
end
783821

@@ -791,9 +829,10 @@ def send_security_token_response(bus, src_id, dst_id, key, response_level = 2)
791829
# @param dst_id [Integer] Integer representation of the receiving CAN ID
792830
# @param id [Array] 2 Bytes in an array of the identifier. Example [ 0xF1, 0x90 ]
793831
# @param data [Array] Array of bytes to write
832+
# @param opt [Hash] Optional settings. PADDING if set uses this hex value for padding
794833
#
795834
# @return [Hash] Packet hash from client.automotive
796-
def write_data_by_id(bus, src_id, dst_id, id, data)
835+
def write_data_by_id(bus, src_id, dst_id, id, data, opt = {})
797836
unless client.automotive
798837
print_error("Not an automotive hwbridge session")
799838
return {}
@@ -815,8 +854,11 @@ def write_data_by_id(bus, src_id, dst_id, id, data)
815854
print_line("No active bus, use 'connect' or specify bus via the options")
816855
return {}
817856
end
857+
padding = nil
858+
padding = opt['PADDING'] if opt.key? 'PADDING'
818859
opt = {}
819860
opt["MAXPKTS"] = 1
861+
opt["PADDING"] = padding unless padding.nil?
820862
client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x27] + id + data, opt)
821863
end
822864

@@ -871,10 +913,11 @@ def routine_control(bus, src_id, dst_id, routine_type, id, data = [], opt = {})
871913
# @param bus [String] unique CAN bus identifier
872914
# @param src_id [Integer] Integer representation of the Sending CAN ID
873915
# @param dst_id [Integer] Integer representation of the receiving CAN ID
874-
# @param suppress_response [Boolean] By default suppress ACK from ECU. Set to false if you want confirmation
916+
# @param opt [Hash] Optional arguments such as: PADDING if set uses this hex value for padding
917+
# SUPPRESS_RESPONSE By default suppress ACK from ECU. Set to false if you want confirmation
875918
#
876919
# @return [Hash] Packet hash from client.automotive. Typically blank unless suppress_response is false
877-
def send_tester_present(bus, src_id, dst_id, suppress_response = true)
920+
def send_tester_present(bus, src_id, dst_id, opt = {})
878921
unless client.automotive
879922
print_error("Not an automotive hwbridge session")
880923
return {}
@@ -886,10 +929,13 @@ def send_tester_present(bus, src_id, dst_id, suppress_response = true)
886929
print_line("No active bus, use 'connect' or specify bus via the options")
887930
return {}
888931
end
932+
padding = nil
889933
suppress = 0x80
890-
suppress = 0 unless suppress_response
934+
suppress = 0 unless (opt.key? 'SUPRESS_RESPONSE') && opt['SUPRESS_RESPONSE'] == false
935+
padding = opt['PADDING'] if opt.key? 'PADDING'
891936
opt = {}
892937
opt["MAXPKTS"] = 1
938+
opt["PADDING"] = padding unless padding.nil?
893939
client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x3E, suppress], opt)
894940
end
895941

0 commit comments

Comments
 (0)