CVE-2018-4012
An exploitable buffer overflow vulnerability exists in the HTTP header-parsing function of the Webroot BrightCloud SDK. The function bc_http_read_header
incorrectly handles overlong headers, leading to arbitrary code execution. An unauthenticated attacker could impersonate a remote BrightCloud server to trigger this vulnerability.
Webroot BrightCloud SDK
9.0 - CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H
CWE-122: Heap-based Buffer Overflow
BrightCloud provides an API service that allows its clients to access websites’ classification and reputation data. Their service can be queried to retrieve the category for the content of a specific URL and its reputation index. BrightCloud also provides an SDK to access their web services API that can be used, for example, by appliances that want to restrict access to non-malicious sites.
A binary using this SDK, called webroot.so
, was found to be inside the CUJO Smart Firewall — an internet-of-things device that monitors the wireless internet in the user’s home — running version 7003, and is used to detect and deny access to potentially malicious websites. Specifically, in the device that we tested, CUJO accesses the BrightCloud API at the URL bcap15.brightcloud.com
over a plain HTTP
connection.
While the following analysis is written in the context of the CUJO Smart Firewall, this advisory does apply to the Webroot BrightCloud SDK itself.
The SDK provides the function bc_http_read_header
, which is used to store the headers of an HTTP connection into a global buffer. This function is used during any communication with BrightCloud servers.
.text:000176BC bc_http_read_header:
.text:000176BC
.text:000176BC 000 li $gp, 0x54B14
.text:000176C4 000 addu $gp, $t9
.text:000176C8 000 addiu $sp, -0x38
.text:000176CC 038 sw $ra, 0x38+var_4($sp)
.text:000176D0 038 sw $fp, 0x38+var_8($sp)
.text:000176D4 038 move $fp, $sp
.text:000176D8 038 sw $gp, 0x38+var_28($sp)
.text:000176DC 038 sw $a0, 0x38+struct($fp)
.text:000176E0 038 sw $a1, 0x38+var_20($fp)
.text:000176E4 038 la $v0, __stack_chk_guard
.text:000176E8 038 nop
.text:000176EC 038 lw $v0, (__stack_chk_guard - 0x95528)($v0)
.text:000176F0 038 nop
.text:000176F4 038 sw $v0, 0x38+var_C($fp)
.text:000176F8 038 la $v0, unk_70000
.text:000176FC 038 nop
.text:00017700 038 addiu $v0, (HeaderBuf - 0x70000) ; [1]
.text:00017704 038 sw $v0, 0x38+header_buf_ptr($fp)
.text:00017708 038 lw $v0, 0x38+header_buf_ptr($fp)
.text:0001770C 038 nop
.text:00017710 038 sw $v0, 0x38+header_buf_start($fp)
.text:00017714 038 sw $zero, 0x38+lines_counter($fp)
.text:00017718 038 b loc_17770
.text:0001771C 038 nop
.text:00017720 # ---------------------------------------------------------------------------
.text:00017720
.text:00017720 loc_17720: ; [2] loop
.text:00017720 038 lw $v0, 0x38+lines_counter($fp)
.text:00017724 038 nop
.text:00017728 038 addiu $v0, 1
.text:0001772C 038 sw $v0, 0x38+lines_counter($fp)
.text:00017730 038 lw $v0, 0x38+header_buf_ptr($fp)
.text:00017734 038 nop
.text:00017738 038 move $a1, $v0
.text:0001773C 038 lw $a0, 0x38+header_buf_start($fp)
.text:00017740 038 li $v0, 0x10000
.text:00017744 038 nop
.text:00017748 038 addiu $v0, (is_empty - 0x10000)
.text:0001774C 038 move $t9, $v0
.text:00017750 038 bal is_empty ; [6]
.text:00017754 038 nop
.text:00017758 038 lw $gp, 0x38+var_28($fp)
.text:0001775C 038 bnez $v0, loc_177AC ; exit loop
.text:00017760 038 nop
.text:00017764 038 lw $v0, 0x38+header_buf_ptr($fp)
.text:00017768 038 nop
.text:0001776C 038 sw $v0, 0x38+header_buf_start($fp)
.text:00017770
.text:00017770 loc_17770:
.text:00017770 038 addiu $v0, $fp, 0x38+header_buf_ptr ; [5]
.text:00017774 038 li $a3, 0x2000
.text:00017778 038 move $a2, $v0
.text:0001777C 038 lw $a1, 0x38+header_buf_start($fp) ; [4]
.text:00017780 038 lw $a0, 0x38+struct($fp)
.text:00017784 038 la $v0, bc_net_readline
.text:00017788 038 nop
.text:0001778C 038 move $t9, $v0
.text:00017790 038 jalr $t9 ; [3] bc_net_readline
.text:00017794 038 nop
.text:00017798 038 lw $gp, 0x38+var_28($fp)
.text:0001779C 038 bgtz $v0, loc_17720 ; [2] loop
.text:000177A0 038 nop
.text:000177A4 038 b loc_177B0 ; exit loop
.text:000177A8 038 nop
.text:000177AC # ---------------------------------------------------------------------------
.text:000177AC
.text:000177AC loc_177AC:
.text:000177AC 038 nop
.text:000177B0
.text:000177B0 loc_177B0:
...
Initially, the function saves a reference to the global buffer HeaderBuf
[1], which is stored in the .bss
section.
Then, the function enters a loop [2] that reads lines (terminated by \n
) from the socket using bc_net_readline
: the invocation at [3] reads a maximum of 0x2000
bytes, storing the data (without stripping newline terminators) in the buffer pointed by header_buf_start
[4]. A pointer to the end of the header line is stored in header_buf_ptr
[5].
If no errors occurred, the function checks if the last line read is empty [6], in which case, the loop exits. Otherwise, the loop continues until an empty line is found.
Since there are no exit conditions related to the size of the destination buffer, an attacker could exploit this vulnerability to write past the HeaderBuf
buffer, which has a size of 0x2000
bytes, overwriting data in the .bss
section that could eventually allow the attacker to execute arbitrary code.
In the context of the CUJO Smart Firewall, the webroot.so
library is executed by the threatd
LUA
script, running as user root
. Every time a new host is resolved via DNS
in the network monitored by the device, the function lwebroot_lookup
is called, which eventually queries BrightCloud’s servers using the supplied SDK, which is using the vulnerable bc_http_read_header
function.
In this case, an attacker can impersonate the remote server bcap15.brightcloud.com
. For example, a malicious actor could carry out a man-in-the-middle attack to execute arbitrary code in the device with root
user privileges.
The following proof of concept shows how to crash the threatd
process in CUJO Smart Firewall, assuming the attacker has redirected connections toward bcap15.brightcloud.com:80
to their own machine.
$ perl -e 'print "AAAAAAAAA\n"x1200,"\n"' | nc -l -p 80
2018-10-10 - Vendor Disclosure
2018-10-17 - Vendor Patched
2018-12-17 - Public Release
Discovered by Claudio Bozzato of Cisco Talos.