February 14, 2023 • 8 mins read
May 26, 2022: BugProve reports the issue to Silicon Labs.
May 26, 2022: Silicon Labs acknowledges the issue.
Aug 3, 2022: Silicon Labs officially confirms the issue with a fix.
Aug 13, 2022: Silicon Labs releases advisory with version 4.1.1.0 of Gecko SDK.
Sep 16, 2022: Silicon Labs allocates CVE-2022-24942
for the vulnerability after resolving technical issues with their CVE Services systems.
Feb 15, 2023: Release of this write-up.
https://www.silabs.com/developers/micrium
https://github.com/SiliconLabs/gecko_sdk
µC/OS is a full-featured embedded operating system originally developed by Micriµm™, it is provided as part of Silicon Lab’s Gecko SDK. In addition to the two highly popular kernels, µC/OS features support for TCP/IP, USB-Device, USB-Host, and Modbus, as well as a robust File System. The uC-HTTP implementation is used on embedded systems that are running the µC/OS II or µC/OS III RTOS kernels. The HTTP server included in it supports many HTTP features, enabling embedded systems developers to rely on it for a variety of use cases in their design.
A heap based buffer overflow vulnerability exists in the HTTP Server functionality of Micrium uC-HTTP 3.01.01. A specially crafted HTTP request can lead to remote code execution. An attacker can send an HTTP request to trigger this vulnerability.
The HTTP server supports multipart requests. Following HTML 4.01 Specification and RFC2045 and EFC2388, the implementation checks the presence of a boundary when the Content-Type header is multipart/form-data and stores it in p_conn->FormBoundaryPtr
However, when calculating the size of the string segment to be copied, the implementation does not check the resulting value against the maximum length the allocated buffer can hold (HTTPs_FORM_BOUNDARY_STR_LEN_MAX
)
The relevant piece of code is located in
platform/micrium_os/net/source/http/server/http_server_req.c
(function HTTPsReq_HdrParse
):
static void HTTPsReq_HdrParse(HTTPs_INSTANCE *p_instance,
HTTPs_CONN *p_conn,
HTTPs_ERR *p_err)
{
CPU_CHAR *p_field;
CPU_CHAR *p_field_end;
CPU_CHAR *p_val;
[..]
p_val = Str_Char_N(p_val, len, ASCII_CHAR_EQUALS_SIGN);
if (p_val == DEF_NULL) {
*p_err = HTTPs_ERR_REQ_FORMAT_INVALID;
return;
}
p_val++; // Remove space before boundary val.
p_val = HTTP_StrGraphSrchFirst(p_val,
len);
len = p_field_end - p_val;
// Copy boundary val to Conn struct.
Str_Copy_N(p_conn->FormBoundaryPtr,
p_val,
len);
// Make sure to create a string.
p_conn->FormBoundaryPtr[len] = ASCII_CHAR_NULL;
p_conn->FormBoundaryLen = len;
We found the vulnerability while testing the compatibility of our binary analysis engine PRIS™ with Silicon Labs’ Gecko SDK. We selected uC-HTTP binaries for analysis since we suspected that most of the alerts raised by PRIS were going to be easy candidates for our taint analysis component to reason about in terms of correlating function parameters to pointers to networking data.
In order to make our analysis work, we had to implement support for the special libc used in Micrium (https://github.com/weston-embedded/uC-LIB/tree/b3a8be2e81bf24cf5722eec632b1c0aa16b6112e)
After that, we left our code running on the different binaries and inspected the results. The file http-s_req.o
in charge of handling HTTP requests raised an alert that indicated that a function semantically equivalent to strncpy()
was called on tainted data. Moreover, the ‘num’
parameter of the call was incorrectly calculated based on pointer arithmetic of an attacker-controlled string without further boundary checks:
The data flow dependencies for the vulnerable call site can be summarized as follows (the build used here is ARMv7
):
Here, you can see that the definition at 0x401109
is a tainted pointer expression. In fact, the input pointer is the result of the HTTP parser trying to find the end of the multipart boundary value, essentially reducing strncpy()
to an unsafe strcpy()
.
Using Ghidra, and shifting all addresses by one due to Thumb mode, it can be verified that the subs instruction highlighted below is the one responsible for this runtime behavior.
We verified the issue by sending a large boundary value string to the HTTP server that crashed it.
Using a build of the code with address sanitizer enabled (x86-64 for convenience), the vulnerability can be also demonstrated using specially crafted input:
==31170==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60700000032f at pc 0x55b0167b85c8 bp 0x7ffca0e2aa60 sp 0x7ffca0e2aa50
WRITE of size 1 at 0x60700000032f thread T0
\#0 0x55b0167b85c7 in HTTPsReq_HdrParse (/home/ubuntu/sbox/uC-HTTP/Server/Source/a.out+0x95c7)
\#1 0x55b0167b37ad in HTTPsReq_Handle (/home/ubuntu/sbox/uC-HTTP/Server/Source/a.out+0x47ad)
\#2 0x55b0167be5ec in main (/home/ubuntu/sbox/uC-HTTP/Server/Source/a.out+0xf5ec)
\#3 0x7ffbef679bf6 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21bf6)
\#4 0x55b0167b2969 in _start (/home/ubuntu/sbox/uC-HTTP/Server/Source/a.out+0x3969)
0x60700000032f is located 15 bytes inside of 1094795585-byte region [0x607000000320,0x607041414461)
==31170==AddressSanitizer CHECK failed: ../../../../src/libsanitizer/asan/asan_descriptions.cc:176 "((res.trace)) != (0)" (0x0, 0x0)
\#0 0x7ffbefb32bf2 (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xe9bf2)
\#1 0x7ffbefb51575 in __sanitizer::CheckFailed(char const*, int, char const*, unsigned long long, unsigned long long) (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x108575)
\#2 0x7ffbefa7646c (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x2d46c)
\#3 0x7ffbefa77838 (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x2e838)
\#4 0x7ffbefa7a8db (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x318db)
\#5 0x7ffbefb3254f (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xe954f)
\#6 0x7ffbefb334b9 in __asan_report_store1 (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xea4b9)
\#7 0x55b0167b85c7 in HTTPsReq_HdrParse (/home/ubuntu/sbox/uC-HTTP/Server/Source/a.out+0x95c7)
\#8 0x55b0167b37ad in HTTPsReq_Handle (/home/ubuntu/sbox/uC-HTTP/Server/Source/a.out+0x47ad)
\#9 0x55b0167be5ec in main (/home/ubuntu/sbox/uC-HTTP/Server/Source/a.out+0xf5ec)
\#10 0x7ffbef679bf6 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21bf6)
\#11 0x55b0167b2969 in _start (/home/ubuntu/sbox/uC-HTTP/Server/Source/a.out+0x3969)
As one can verify, this is a straightforward heap-based buffer overflow, potentially allowing for remote code execution on systems that don’t feature any additional mitigations.
The vulnerability was found by Attila Szasz at BugProve, using BugProve PRIS™.
We have just launched our automated firmware analysis tool, BugProve, to reduce the time spent on embedded systems security research and binary reverse engineering, and to increase the overall security of IoT products on the market. It features PRIS™, a code analysis engine with similar capabilities as highlighted above, supporting standard libc’s on ARMv7, MIPS, MIPS64, ARMv8, x86, and PPC (for the complete list, please refer to BugProve Knowledge Hub).
At a high-level BugProve gives you the following:
Give it a try now!