CVE-2023-31475: Buffer Overflow in guci2_get() of libglutil.so
CVE-2023-31475: Buffer Overflow in guci2_get() of libglutil.so
- CVSS Score - 9.0, Critical (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H)
- Overview - The function
guci2_get()found inlibglutil.sohas a buffer overflow vulnerability where an item is requested from a UCI context, and the value is pasted into a char pointer to a buffer without checking the size of the buffer. - Description - The definition for the function
guci2_get()isint guci2_get(int context, char *item, char *storage).libglutil.sois used by various custom GL.iNET binaries, such as the API FastCGI binary located at/www/apiin GL.iNET devices. This FastCGI binary relies onguci2_get()heavily, and makes several calls to that function. Thestoragevariable is always declared insideapiwith a static buffer size, but that buffer size is never communicated to theguci2_get()function. Inside ofguci2_get(), the codesprintf(storage,"%s",*(ptr_to_value_retrieved_from_UCI_context))is run, so if the value is longer than the buffer size, a buffer overflow occurs. - Impact
- An example of this buffer overflow vulnerability can be found in timezone functionality of the
/www/apibinary. The API endpoint that sets the timezone is/api/router/timezone/set, which only requires thezonenameparameter. - This
zonenameparameter is escaped (to prevent command injection) and piped into the commandgrep "%s" /usr/share/zoneinfo/tzdata.lua |awk -F"'" '{print $4}'. If output is found, then the UCI valuesystem.@system[0].zonenameis set to the providedzonenameparameter. - The actual vulnerability lies in the API endpoints that retrieve the
system.@system[0].zonenamevalue. The API endpoint with the HTTP path/api/router/timezone/getdoes this, and has theguci2_get()function copy thezonenamevalue into a 52-byte buffer, meaning any validzonenamevalue over 52 characters long causes a buffer overflow. - A “valid”
zonenamevalue simply has to return chars from the commandgrep "%s" /usr/share/zoneinfo/tzdata.lua |awk -F"'" '{print $4}'. Sincegrepaccepts regular expressions, this allows you to match a specific string, while making the input parameter infinitely long. For example, the Linux commandecho "abc" | grep "ab[czzzzzzzzz]"will return the string successfully. Since you can put in an infinitely long amount ofzcharacters, you can easily achieve a buffer overflow. - Example of
zonenamevalue that is “valid” -Asia/D[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa](140 chars) - Note that this buffer overflow example doesn’t lead to any malicious behavior or RCE since stack canaries present in the
apiexecutable prevent the attacker from overwriting the return address, and all other stack values are overwritten during function execution. However, this still leaves an attack vector open in other API endpoints or executables that rely on this function and either doesn’t have stack canaries, or stack canaries can be bypassed. - Also note that various “valid”
zonenamevalues will cause the endpoints/api/router/timezone/getand/api/router/app/statusto always return a 500 Internal Server Error response (Denial of Service) since the buffer overflow overwrites the stack canary, causing theapiexecutable to exit early.
- An example of this buffer overflow vulnerability can be found in timezone functionality of the
Fix
This was not fixed, as the guci2_get() function still behaves the same way. Instead, the example I provided was fixed by setting grep to treat input as fixed strings and not regular expressions.
PoC
1 | ======= REQUEST 1 ======= |