CVE-2023-31247
A memory corruption vulnerability exists in the HTTP Server Host header parsing functionality of Weston Embedded uC-HTTP v3.01.01. A specially crafted network packet can lead to code execution. An attacker can send a malicious packet 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
9.0 - CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/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.
When processing the Host
header field, the call at [1]
locates the beginning of the value within the receive buffer and calculates the length of the header value.The length is then checked to ensure that it is at most p_cfg->HostNameLenMax
[2]
. The length is then used as the index into the heap buffer at [3]
. If the value of length is exactly equal to the configured size, this results in a one byte buffer overwrite with the NULL byte at [3]
.
File: http-s_req.c
1713: /* Find beginning of host string val. */
1714: p_val = HTTPsReq_HdrParseValGet(p_field,
1715: HTTP_STR_HDR_FIELD_HOST_LEN,
1716: p_field_end,
1717: &len); /* [1] */
1718:
1719: len = DEF_MIN(len, p_cfg->HostNameLenMax); /* [2] */
1720:
1721: /* Copy host name val in Conn struct. */
1722: (void)Str_Copy_N(p_conn->HostPtr, p_val, len);
1723: /* Make sure to create a string. */
1724: p_conn->HostPtr[len] = ASCII_CHAR_NULL; /* [3] */
Because of the memory layout implemented by the uC-LIB Memory Library, this one byte overwrite results in an arbitrary allocation controlled by the attacker, which could be used to gain code execution as explained below.
When a heap object is freed using uC-LIB Memory Mem_DynPoolBlkFree
, the pointer to the next free chunk of memory within that pool is stored in the first 4 bytes of that memory block [0]
.
File: lib_mem.c
2072: void Mem_DynPoolBlkFree (MEM_DYN_POOL *p_pool,
2073: void *p_blk,
2074: LIB_ERR *p_err)
2075: {
...
2109: *((void **)p_blk) = p_pool->BlkFreePtr; /* [0] */
So, when this NULL byte overwrite occurs and the following heap block has been allocated and freed previously, this will overwrite the least-significant byte of the next free pointer address. It is possible for the attacker to influence allocations such that when overwriting the least-significant byte, the new pointer address will point to a buffer containing attacker controlled data. When this happens, on the next allocation of the heap pool which contains the corrupted free pointer, that same corrupt pointer will be dereferenced and stored in the pool object as the next free pointer [1]
. This dereferenced value is attacker controlled, since the corrupted pointer now points to an attacker controlled buffer as a result of this vulnerability. On the next call to Mem_DynPoolBlkGet
the dereferenced attacker controlled value will be the pointer which is allocated [0]
. The result of this is that the attacker has the ability to allocate memory at an arbitrary address. The impact of an attacker being able to allocate an arbitrary address is that now the attacker can write data anywhere in the program memory space, which could lead to things like overwriting stack data or a function pointer in order to gain code execution.
File: lib_mem.c
1978: void *Mem_DynPoolBlkGet (MEM_DYN_POOL *p_pool,
1979: LIB_ERR *p_err)
1980: {
...
2014: p_blk = p_pool->BlkFreePtr; /* [0] */
2015: p_pool->BlkFreePtr = *((void **)p_blk); /* [1] */
Program received signal SIGSEGV, Segmentation fault.
0x56569556 in Mem_DynPoolBlkGet (p_pool=0x56577398 <HTTP_Heap+184>, p_err=0xffffd39c) at uc-lib/lib_mem.c:2015
2015 p_pool->BlkFreePtr = *((void **)p_blk);
(gdb) i r
eax 0x43434343 1128481603
ecx 0x5657789c 1448573084
edx 0x3 3
ebx 0x56576f64 1448570724
esp 0xffffd350 0xffffd350
ebp 0xffffd368 0xffffd368
esi 0xf7f8e000 -134684672
edi 0xf7f8e000 -134684672
eip 0x56569556 0x56569556 <Mem_DynPoolBlkGet+124>
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 0x56569556 in Mem_DynPoolBlkGet (p_pool=0x56577398 <HTTP_Heap+184>, p_err=0xffffd39c)
at uc-lib/lib_mem.c:2015
#1 0x56563551 in HTTPsMem_TokenGet (p_instance=0x565772fc <HTTP_Heap+28>, p_conn=0x56577828 <HTTP_Heap+1352>,
p_err=0xffffd470) at Server/Source/http-s_mem.c:1527
#2 0x56560f7c in HTTPsResp_DataTransferChunked (p_instance=0x565772fc <HTTP_Heap+28>,
p_conn=0x56577828 <HTTP_Heap+1352>, p_err=0xffffd470) at Server/Source/http-s_resp.c:2100
#3 0x5655f4be in HTTPsResp_Handle (p_instance=0x565772fc <HTTP_Heap+28>, p_conn=0x56577828 <HTTP_Heap+1352>)
at Server/Source/http-s_resp.c:395
#4 0x5655caa3 in HTTPsConn_Process (p_instance=0x565772fc <HTTP_Heap+28>) at Server/Source/http-s_conn.c:217
#5 0x5655ed9f in HTTPsTask_InstanceTaskHandler (p_instance=0x565772fc <HTTP_Heap+28>)
at Server/Source/http-s_task.c:814
#6 0x5655eb05 in HTTPsTask_InstanceTask (p_data=0x565772fc <HTTP_Heap+28>) at Server/Source/http-s_task.c:653
#7 0x565668b0 in KAL_TaskCreate (task_handle=..., p_fnct=0x5655eae0 <HTTPsTask_InstanceTask>,
p_task_arg=0x565772fc <HTTP_Heap+28>, prio=17 '\021', p_cfg=0x0, p_err=0xffffd5c0)
at uc-shims/Source/kal-shim.c:59
#8 0x5655e824 in HTTPsTask_InstanceTaskCreate (p_instance=0x565772fc <HTTP_Heap+28>, p_err=0xffffd63c)
at Server/Source/http-s_task.c:331
#9 0x5655c21c in HTTPs_InstanceStart (p_instance=0x565772fc <HTTP_Heap+28>, p_err=0xffffd63c)
at Server/Source/http-s.c:812
#10 0x56557ee0 in main (argc=1, argv=0xffffd704) at server_app.c:147
(gdb)
Modifying the code within uC-HTTP itself so that the maximum index used is one less than the size of the HostPtr
buffer. A sample bugfix is below:
diff --git a/Server/Source/http-s_req.c b/Server/Source/http-s_req.c
index d487160..93aed53 100644
--- a/Server/Source/http-s_req.c
+++ b/Server/Source/http-s_req.c
@@ -1716,7 +1716,7 @@ static void HTTPsReq_HdrParse (HTTPs_INSTANCE *p_instance,
p_field_end,
&len);
- len = DEF_MIN(len, p_cfg->HostNameLenMax);
+ len = DEF_MIN(len, p_cfg->HostNameLenMax - 1);
/* Copy host name val in Conn struct. */
(void)Str_Copy_N(p_conn->HostPtr, p_val, len);
2023-05-09 - Vendor Disclosure
2023-06-23 - Vendor Patch Release
2023-11-14 - Public Release
Discovered by Kelly Leuschner of Cisco Talos.