CVE-2023-24585
An out-of-bounds write vulnerability exists in the HTTP Server functionality of Weston Embedded uC-HTTP v3.01.01. A specially crafted network packet can lead to memory corruption. An attacker can send a network request to trigger this vulnerability.
The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.
Weston Embedded uC-HTTP v3.01.01
Weston Embedded Cesium NET 3.07.01
Silicon Labs Gecko Platform 4.3.1.0
uC-HTTP - https://weston-embedded.com/micrium/overview Cesium NET - https://www.weston-embedded.com/cesium-cs-net Gecko Platform - https://www.silabs.com/developers/gecko-software-development-kit
7.7 - CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:H
CWE-119 - Improper Restriction of Operations within the Bounds of a Memory Buffer
The uC-HTTP server implementation is designed to be used on embedded systems that are running the µC/OS II or µC/OS III RTOS kernels. This HTTP server supports many features including persistent connections, form processing, chunked transfer encoding, HTTP header fields processing, HTTP query string processing and dynamic content.
This out-of-bounds write vulnerability occurs when parsing the method of an HTTP request and could lead to heap corruption. The µC/OS heap implementation stores a pointer to the next free chunk within the first 4 bytes of a free chunk. An attacker could corrupt this next free chunk pointer using this out of bounds write vulnerability and potentially control the address of the next heap allocation.
If the method string within the HTTP request is prepended with bytes with a value less than 0x21
(exclamation point in ascii) or greater than 0x7e
(tilde in ascii), the connection instance variable p_conn->RxBufLenRem
will be larger than the actual remaining length of the receive buffer because the connection instance variable p_conn->RxBufPtr
has been advanced farther than the length variable p_conn->RxBufLenRem
accounts for. This leads to an out-of-bounds write occurring elsewhere in the code when p_conn->RxBufLenRem
is used as an index for p_conn->RxBufPtr
and writes beyond the bounds of the original buffer.
Consider the code below. A local variable p_request_method_start
is used to store a pointer to the location of the first character whose value is less than 0x21
(exclamation point in ascii) or greater than 0x7e
[1]. Next, the local variable len
is correctly calculated to account for bytes that may have been skipped. After locating the next space character in the buffer [3], the local variable len
is set as the number of characters before a space was encountered [4]. The result of this calculation is that the len
variable no longer accounts for the previously skipped characters. Later, the connection instance variable p_conn->RxBufLenRem
is updated but does not account for the skipped characters [5]. The connection instance variable p_conn->RxBufPtr
is advanced and does account for the skipped characters. Therefore, the buffer pointer used elsewhere p_conn->RxBufPtr
and the length variable used elsewhere p_conn->RxBufLenRem
are now mismatched.
static void HTTPsReq_MethodParse (HTTPs_INSTANCE *p_instance,
HTTPs_CONN *p_conn,
HTTPs_ERR *p_err)
{
...
len = p_conn->RxBufLenRem;
...
/* Move the start ptr to the first meanningful char. */
p_request_method_start = HTTP_StrGraphSrchFirst(p_conn->RxBufPtr, len); /* [1] p_request_method_start advances to the
first character between 0x21 - 0x7e*/
if (p_request_method_start == DEF_NULL) {
*p_err = HTTPs_ERR_REQ_FORMAT_INVALID;
return;
}
len -= p_request_method_start - p_conn->RxBufPtr ; /* [2] len is correctly calculated */
/* Find the end of method string. */
p_request_method_end = Str_Char_N(p_request_method_start, len, ASCII_CHAR_SPACE); /* [3] */
if (p_request_method_end == DEF_NULL) {
*p_err = HTTPs_ERR_REQ_FORMAT_INVALID;
return;
}
len = p_request_method_end - p_request_method_start; /* [4] This is the bug */
...
p_conn->RxBufLenRem -= len; /* [5] */
p_conn->RxBufPtr = p_request_method_end; /* [6] */
}
Later on, if the packet contains form data, the incorrect p_conn->RxBufLenRem
will be used as the local variable len_str
[1] when parsing key/value pairs by calling HTTPsReq_BodyFormAppKeyValBlkAdd
[2], which then calls HTTPsReq_URL_EncodeStrParse
with that same incorrect value len_str
.
static CPU_BOOLEAN HTTPsReq_BodyFormAppParse (HTTPs_INSTANCE *p_instance,
HTTPs_CONN *p_conn,
HTTPs_ERR *p_err)
{
...
while (done != DEF_YES) {
/* ----------- VALIDATE CUR KEY/VAL PAIRS ------------- */
p_key_next = Str_Char_N(p_key_name, /* Srch beginning of next key/val pairs. */
p_conn->RxBufLenRem,
ASCII_CHAR_AMPERSAND);
if (p_key_next == DEF_NULL) { /* If next key/val pairs not found ... */
/* ... determine if all data are received or next ... */
/* ... key/val pairs are missing. */
len_content_rxd = p_conn->ReqContentLenRxd
+ p_conn->RxBufLenRem;
if (len_content_rxd < p_conn->ReqContentLen) { /* If data are missing ... */
*p_err = HTTPs_ERR_REQ_MORE_DATA_REQUIRED; /* ... receive more data. */
goto exit;
} else { /* If all data received ... */
len_str = p_conn->RxBufLenRem; /* [1]
/* ... last key/val pairs to parse. */
}
} else { /* Next key/val pairs found ... */
len_str = (p_key_next - p_key_name); /* ... parse key/val pairs. */
}
/* Add key-Value block to list. */
result = HTTPsReq_BodyFormAppKeyValBlkAdd(p_instance,
p_conn,
p_key_name,
len_str,
p_err); /* [2] */
...
}
When this function attempts to null terminate the value portion of the key/value pair, the pointer p_str
is within the receive buffer, but str_len
indexes beyond the receive buffer, causing an out-of-bounds write [1].
static CPU_BOOLEAN HTTPsReq_URL_EncodeStrParse (HTTPs_INSTANCE *p_instance,
HTTPs_CONN *p_conn,
HTTPs_KEY_VAL *p_key_val,
CPU_BOOLEAN from_query,
CPU_CHAR *p_str,
CPU_SIZE_T str_len)
{
...
/* Find separator "=". */
p_str_sep = Str_Char_N(p_str, str_len, ASCII_CHAR_EQUALS_SIGN);
p_str[str_len] = ASCII_CHAR_NULL; /* [1] */
...
}
Program received signal SIGSEGV, Segmentation fault.
0x565674b8 in Str_Cmp_N (
p1_str=0x560071dc <error: Cannot access memory at address 0x560071dc>,
p2_str=0x5656a07b "Log out", len_max=9) at uc-lib/lib_str.c:882
882 while ((*p1_str_cmp == *p2_str_cmp) && /* Cmp strs until non-matching chars (see Note #3c) ... */
(gdb) i r
eax 0x560071dc 1442869724
ecx 0x0 0
edx 0x5656a07b 1448517755
ebx 0x56575f64 1448566628
esp 0xffffd418 0xffffd418
ebp 0xffffd438 0xffffd438
esi 0xf7f91000 -134672384
edi 0xf7f91000 -134672384
eip 0x565674b8 0x565674b8 <Str_Cmp_N+172>
eflags 0x10202 [ IF RF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
k0 0x0 0
k1 0x0 0
k2 0x0 0
k3 0x0 0
k4 0x0 0
k5 0x0 0
k6 0x0 0
k7 0x0 0
(gdb) bt
#0 0x565674b8 in Str_Cmp_N (
p1_str=0x560071dc <error: Cannot access memory at address 0x560071dc>,
p2_str=0x5656a07b "Log out", len_max=9) at uc-lib/lib_str.c:882
#1 0x56557869 in HTTPs_ReqRdySignalHook (p_instance=0x5657645c <Mem_Heap+28>,
p_conn=0x56576988 <Mem_Heap+1352>, p_hook_cfg=0x0, p_data=0x56586de4 <Mem_Heap+68004>)
at app_basic_http-s_hooks.c:685
#2 0x565594b1 in HTTPsReq_RdySignal (p_instance=0x5657645c <Mem_Heap+28>,
p_conn=0x56576988 <Mem_Heap+1352>) at Server/Source/http-s_req.c:742
#3 0x5655cb0d in HTTPsConn_Process (p_instance=0x5657645c <Mem_Heap+28>)
at Server/Source/http-s_conn.c:184
#4 0x5655ee9b in HTTPsTask_InstanceTaskHandler (p_instance=0x5657645c <Mem_Heap+28>)
at Server/Source/http-s_task.c:814
#5 0x5655ec01 in HTTPsTask_InstanceTask (p_data=0x5657645c <Mem_Heap+28>)
at Server/Source/http-s_task.c:653
#6 0x565669ac in KAL_TaskCreate (task_handle=...,
p_fnct=0x5655ebdc <HTTPsTask_InstanceTask>, p_task_arg=0x5657645c <Mem_Heap+28>,
prio=17 '\021', p_cfg=0x0, p_err=0xffffd5e0) at uc-shims/Source/kal-shim.c:59
#7 0x5655e920 in HTTPsTask_InstanceTaskCreate (p_instance=0x5657645c <Mem_Heap+28>,
p_err=0xffffd654) at Server/Source/http-s_task.c:331
#8 0x5655c2e0 in HTTPs_InstanceStart (p_instance=0x5657645c <Mem_Heap+28>,
p_err=0xffffd654) at Server/Source/http-s.c:812
#9 0x56557fc2 in main (argc=1, argv=0xffffd714) at server_app.c:105
2023-02-28 - Vendor Disclosure
2023-06-23 - Vendor Patch Release
2023-11-14 - Public Release
Discovered by Kelly Leuschner of Cisco Talos.