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.so
has 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.so
is used by various custom GL.iNET binaries, such as the API FastCGI binary located at/www/api
in GL.iNET devices. This FastCGI binary relies onguci2_get()
heavily, and makes several calls to that function. Thestorage
variable is always declared insideapi
with 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/api
binary. The API endpoint that sets the timezone is/api/router/timezone/set
, which only requires thezonename
parameter. - This
zonename
parameter 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].zonename
is set to the providedzonename
parameter. - The actual vulnerability lies in the API endpoints that retrieve the
system.@system[0].zonename
value. The API endpoint with the HTTP path/api/router/timezone/get
does this, and has theguci2_get()
function copy thezonename
value into a 52-byte buffer, meaning any validzonename
value over 52 characters long causes a buffer overflow. - A “valid”
zonename
value simply has to return chars from the commandgrep "%s" /usr/share/zoneinfo/tzdata.lua |awk -F"'" '{print $4}'
. Sincegrep
accepts 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 ofz
characters, you can easily achieve a buffer overflow. - Example of
zonename
value 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
api
executable 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”
zonename
values will cause the endpoints/api/router/timezone/get
and/api/router/app/status
to always return a 500 Internal Server Error response (Denial of Service) since the buffer overflow overwrites the stack canary, causing theapi
executable 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 ======= |