CVE-2018-3927
An exploitable information disclosure vulnerability exists in the crash handler of the hubCore
binary of the Samsung SmartThings Hub. When hubCore
crashes, Google Breakpad is used to record minidumps, which are sent over an insecure HTTPS connection to the backtrace.io service, leading to the exposure of sensitive data. An attacker can impersonate the remote backtrace.io server in order to trigger this vulnerability.
Samsung SmartThings Hub STH-ETH-250 - Firmware version 0.20.17
https://www.smartthings.com/products/smartthings-hub
6.8 - CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N
CWE-295: Improper Certificate Validation
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 utilizes Google Breakpad(https://chromium.googlesource.com/breakpad/breakpad/) for generating minidumps in the event of a crash. These minidumps are then sent over to the backtrace.io service(https://backtrace.io/).
When the process starts, the function backtrace_init
is called to set up the crash handler:
.text:008337F8 backtrace_init
.text:008337F8
.text:008337F8 000 STMFD SP!, {R4-R6,LR}
.text:008337FC 010 MOV R6, R0
.text:00833800 010 SUB SP, SP, #0x5A0
.text:00833804 5B0 MOV R5, #0
.text:00833808 5B0 MOV R0, #:lower16:aHubcore_minidu ; "HUBCORE_MINIDUMP_URL"
.text:0083380C 5B0 SUB SP, SP, #8
.text:00833810 5B8 STR R5, [R6]
.text:00833814 5B8 MOVT R0, #:upper16:aHubcore_minidu ; "HUBCORE_MINIDUMP_URL"
.text:00833818 5B8 BL getenv ; [1]
.text:0083381C 5B8 SUBS R4, R0, #0
.text:00833820 5B8 BEQ loc_8338E0
.text:00833824 5B8 MOV R0, #0x8C
.text:00833828 5B8 BL malloc
.text:0083382C 5B8 CMP R0, #0
.text:00833830 5B8 MOV R4, R0
.text:00833834 5B8 STR R0, [R6]
.text:00833838 5B8 BEQ loc_833950
.text:0083383C 5B8 ADD R0, SP, #0x5B8+var_5A0
.text:00833840 5B8 MOV R1, #:lower16:aTmp ; "/tmp"
.text:00833844 5B8 SUB R2, R0, #8
.text:00833848 5B8 MOVT R1, #:upper16:aTmp ; "/tmp"
.text:0083384C 5B8 BL std::string::string(char const*,std::allocator<char> const&)
.text:00833850 5B8 MOV R6, #0xFFFFFFFF
.text:00833854 5B8 MOV R3, #1
.text:00833858 5B8 ADD R1, SP, #0x5B8+var_5A0
.text:0083385C 5B8 STMIA R4, {R3,R6}
.text:00833860 5B8 ADD R0, R4, #8
.text:00833864 5B8 BL std::string::string(std::string const&)
.text:00833868 5B8 LDR R3, =unk_A42314
.text:0083386C 5B8 LDR R2, [SP,#0x5B8+var_5A0]
.text:00833870 5B8 STR R6, [R4,#0x14]
.text:00833874 5B8 SUB R1, R3, #0xC
.text:00833878 5B8 STR R5, [R4,#0x10]
.text:0083387C 5B8 SUB R0, R2, #0xC
.text:00833880 5B8 STR R5, [R4,#0x18]
.text:00833884 5B8 CMP R0, R1
.text:00833888 5B8 STRB R5, [R4,#0x1C]
.text:0083388C 5B8 STRB R5, [R4,#0x1D]
.text:00833890 5B8 STR R5, [R4,#0x20]
.text:00833894 5B8 STR R5, [R4,#0x24]
.text:00833898 5B8 STR R5, [R4,#0x28]
.text:0083389C 5B8 STR R5, [R4,#0x2C]
.text:008338A0 5B8 STR R3, [R4,#0xC]
.text:008338A4 5B8 BNE loc_8339CC
.text:008338A8
.text:008338A8 loc_8338A8
.text:008338A8 5B8 MOV R5, #1
.text:008338AC 5B8 MOV R2, #0xFFFFFFFF
.text:008338B0 5B8 MOV R3, #:lower16:sub_8337E0
.text:008338B4 5B8 STR R2, [SP,#0x5B8+var_5B0]
.text:008338B8 5B8 STMEA SP, {R4,R5}
.text:008338BC 5B8 MOVT R3, #:upper16:sub_8337E0 ; [2]
.text:008338C0 5B8 ADD R0, R4, #0x30
.text:008338C4 5B8 MOV R1, R4
.text:008338C8 5B8 MOV R2, #0
.text:008338CC 5B8 BL google_breakpad::ExceptionHandler::ExceptionHandler(google_breakpad::MinidumpDescriptor const&,bool (*)(void *),bool (*)(google_breakpad::MinidumpDescriptor const&,void *,bool),void *,bool,int)
.text:008338D0 5B8 MOV R0, R5
.text:008338D4 5B8 ADD SP, SP, #0x5A0
.text:008338D8 018 ADD SP, SP, #8
.text:008338DC 010 LDMFD SP!, {R4-R6,PC}
At [1], the function retrieves the URL used to submit the minidump to backtrace.io. This URL has a fixed value and is defined in /etc/default/hubcore:
# cat /etc/default/hubcore | grep URL
export HUBCORE_MINIDUMP_URL="https://smartthings.sp.backtrace.io:8443/post?format=minidump&token=2d711642b726b04401627ca9fbac32f5c8530fb1903cc4db02258717921a4881"
Finally, the function sets up the Google Breakpad exception handler. As we can see, the function sub_8337E0
[2] will be called by Breakpad after the minidump has been generated.
.text:008337E0 sub_8337E0
.text:008337E0
.text:008337E0 000 STMFD SP!, {R4,LR}
.text:008337E4 008 SUBS R4, R2, #0
.text:008337E8 008 BEQ loc_8337F0
.text:008337EC 008 BL sub_833604
.text:008337F0
.text:008337F0 loc_8337F0
.text:008337F0 008 MOV R0, R4
.text:008337F4 008 LDMFD SP!, {R4,PC}
.text:00833604 sub_833604
.text:00833604
.text:00833604 000 STMFD SP!, {R4-R7,LR}
.text:00833608 014 MOV R5, R0
.text:0083360C 014 MOV R0, #:lower16:aHubcore_minidu ; "HUBCORE_MINIDUMP_URL"
.text:00833610 014 SUB SP, SP, #0x3FC
.text:00833614 410 MOVT R0, #:upper16:aHubcore_minidu ; "HUBCORE_MINIDUMP_URL"
.text:00833618 410 BL getenv
.text:0083361C 410 MOV R12, #:lower16:aProduct_nameHu ; "product_name=HubCore"
.text:00833620 410 MOV R6, R0
.text:00833624 410 MOVT R12, #:upper16:aProduct_nameHu ; "product_name=HubCore"
.text:00833628 410 ADD LR, SP, #0x410+var_404
.text:0083362C 410 LDMIA R12!, {R0-R3}
.text:00833630 410 STMIA LR!, {R0-R3}
.text:00833634 410 LDMIA R12, {R0,R1}
.text:00833638 410 STR R0, [LR],#4
.text:0083363C 410 MOV R0, #aHubcore_releas
.text:00833644 410 STRB R1, [LR]
.text:00833648 410 BL getenv
.text:0083364C 410 MOV R1, #0x14
.text:00833650 410 MOV R3, #0x11
.text:00833654 410 MOV R2, #:lower16:aVersionD_D_D ; "version=%d.%d.%d"
.text:00833658 410 MOV R4, R0
.text:0083365C 410 STMEA SP, {R1,R3}
.text:00833660 410 MOVT R2, #:upper16:aVersionD_D_D ; "version=%d.%d.%d"
.text:00833664 410 MOV R1, #0x80
.text:00833668 410 MOV R3, #0
.text:0083366C 410 ADD R0, SP, #0x410+s
.text:00833670 410 BL snprintf
.text:00833674 410 BL getGitVersion
.text:00833678 410 MOV R2, #:lower16:aGitversionS ; "gitVersion=%s"
.text:0083367C 410 MOV R3, R0
.text:00833680 410 MOVT R2, #:upper16:aGitversionS ; "gitVersion=%s"
.text:00833684 410 MOV R1, #0x80
.text:00833688 410 ADD R0, SP, #0x410+var_318
.text:0083368C 410 BL snprintf
.text:00833690 410 MOV R2, #:lower16:aHubidS ; "hubId=%s"
.text:00833694 410 MOV R3, #:lower16:gHubId
.text:00833698 410 MOVT R2, #:upper16:aHubidS ; "hubId=%s"
.text:0083369C 410 MOVT R3, #:upper16:gHubId
.text:008336A0 410 MOV R1, #0x80
.text:008336A4 410 ADD R0, SP, #0x410+var_298
.text:008336A8 410 BL snprintf
.text:008336AC 410 CMP R4, #0
.text:008336B0 410 MOV R3, #:lower16:aUnset ; "unset"
.text:008336B4 410 MOV R2, #:lower16:aChannelS ; "channel=%s"
.text:008336B8 410 MOVT R3, #:upper16:aUnset ; "unset"
.text:008336BC 410 MOVT R2, #:upper16:aChannelS ; "channel=%s"
.text:008336C0 410 MOVNE R3, R4
.text:008336C4 410 MOV R1, #0x80
.text:008336C8 410 ADD R0, SP, #0x410+var_218
.text:008336CC 410 BL snprintf
.text:008336D0 410 MOV R2, #:lower16:aPlatformS ; "platform=%s"
.text:008336D4 410 MOV R3, #:lower16:aHubv2 ; "hubv2"
.text:008336D8 410 MOVT R2, #:upper16:aPlatformS ; "platform=%s"
.text:008336DC 410 MOVT R3, #:upper16:aHubv2 ; "hubv2"
.text:008336E0 410 MOV R1, #0x80
.text:008336E4 410 ADD R0, SP, #0x410+var_198
.text:008336E8 410 BL snprintf
.text:008336EC 410 MOV R2, #:lower16:aUpload_file_mi ; "upload_file_minidump=@%s"
.text:008336F0 410 MOV R1, #0x100
.text:008336F4 410 LDR R3, [R5,#0x10]
.text:008336F8 410 MOVT R2, #:upper16:aUpload_file_mi ; "upload_file_minidump=@%s"
.text:008336FC 410 ADD R0, SP, #0x410+var_118
.text:00833700 410 BL snprintf
.text:00833704 410 BL fork
.text:00833708 410 SUBS R1, R0, #0
.text:0083370C 410 BEQ loc_833724
.text:00833710 410 MOV R1, #0
.text:00833714 410 MOV R2, R1
.text:00833718 410 BL waitpid
.text:0083371C 410 ADD SP, SP, #0x3FC
.text:00833720 014 LDMFD SP!, {R4-R7,PC}
.text:00833724 ---------------------------------------------------------------------------
.text:00833724
.text:00833724 loc_833724
.text:00833724 410 MOV R2, #0x54
.text:00833728 410 ADD R7, SP, #0x410+var_298
.text:0083372C 410 ADD R0, SP, #0x410+argv
.text:00833730 410 MOV R5, #:lower16:aV_0 ; "-v"
.text:00833734 410 BL memset
.text:00833738 410 STR R7, [SP,#0x410+var_3C4]
.text:0083373C 410 ADD R7, SP, #0x410+var_404
.text:00833740 410 ADD R3, SP, #0x410+s
.text:00833744 410 STR R7, [SP,#0x410+var_3BC]
.text:00833748 410 MOV R2, #:lower16:aUsrBinCurl ; "/usr/bin/curl"
.text:0083374C 410 ADD R7, SP, #0x410+var_218
.text:00833750 410 MOVT R2, #:upper16:aUsrBinCurl ; "/usr/bin/curl"
.text:00833754 410 STR R3, [SP,#0x410+var_3D4]
.text:00833758 410 ADD R0, SP, #0x410+var_318
.text:0083375C 410 STR R7, [SP,#0x410+var_3B4]
.text:00833760 410 MOV R4, #:lower16:aK ; [3] "-k"
.text:00833764 410 ADD R7, SP, #0x410+var_198
.text:00833768 410 MOV LR, #:lower16:aX_0 ; "-X"
.text:0083376C 410 MOV R12, #:lower16:aPost_0 ; "POST"
.text:00833770 410 MOV R3, #:lower16:aF ; "-F"
.text:00833774 410 MOVT LR, #:upper16:aX_0 ; "-X"
.text:00833778 410 MOVT R3, #:upper16:aF ; "-F"
.text:0083377C 410 MOVT R12, #:upper16:aPost_0 ; "POST"
.text:00833780 410 STR R0, [SP,#0x410+var_3CC]
.text:00833784 410 ADD R1, SP, #0x410+argv ; argv
.text:00833788 410 STR R7, [SP,#0x410+var_3AC]
.text:0083378C 410 MOVT R5, #:upper16:aV_0 ; "-v"
.text:00833790 410 MOVT R4, #:upper16:aK ; "-k"
.text:00833794 410 MOV R0, R2 ; path
.text:00833798 410 ADD R7, SP, #0x410+var_118
.text:0083379C 410 STR R6, [SP,#0x410+var_3A0]
.text:008337A0 410 STR R7, [SP,#0x410+var_3A4]
.text:008337A4 410 STR R2, [SP,#0x410+argv]
.text:008337A8 410 STR R5, [SP,#0x410+var_3E8]
.text:008337AC 410 STR R4, [SP,#0x410+var_3E4]
.text:008337B0 410 STR LR, [SP,#0x410+var_3E0]
.text:008337B4 410 STR R12, [SP,#0x410+var_3DC]
.text:008337B8 410 STR R3, [SP,#0x410+var_3D8]
.text:008337BC 410 STR R3, [SP,#0x410+var_3D0]
.text:008337C0 410 STR R3, [SP,#0x410+var_3C8]
.text:008337C4 410 STR R3, [SP,#0x410+var_3C0]
.text:008337C8 410 STR R3, [SP,#0x410+var_3B8]
.text:008337CC 410 STR R3, [SP,#0x410+var_3B0]
.text:008337D0 410 STR R3, [SP,#0x410+var_3A8]
.text:008337D4 410 BL execv
.text:008337D8 410 MOV R0, #0x7F
.text:008337DC 410 BL exit
The function collects the minidump file, as well as a set of other information to be sent to backtrace.io using curl
[4].
The actual command executed is:
curl -v -k -X POST -F version=0.20.17 -F gitVersion=6ac91f43 -F hubId=<hub-MAC-address> -F product_name=HubCore -F channel=prod -F platform=hubv2 -F upload_file_minidump=@/tmp/a1fce436-3854-ff88-8cff4b8e-7875d600.dmp https://smartthings.sp.backtrace.io:8443/post?format=minidump&token=2d711642b726b04401627ca9fbac32f5c8530fb1903cc4db02258717921a4881
As we can see, the insecure -k
switch is used [3], which allows cURL to perform insecure SSL connections.
Thus, an attacker with the ability to impersonate the remote “smartthings.sp.backtrace.io” server can intercept the minidump using a self-signed certificate in order to extract sensitive process data.
Note that an hubCore crash can be triggered by using TALOS-2018-0593.
2018-05-14 - Vendor Disclosure
2018-05-23 - Discussion with vendor/review of timeline for fix
2018-07-17 - Vendor patched
2018-07-26 - Public Release
Discovered by Claudio Bozzato of Cisco Talos.