Local Privilege Escalation in the glibc's ld.so

We discussed this vulnerability during Episode 218 on 10 October 2023

A buffer overflow vulnerability was introduced in a 2021 patch to glibc’s dynamic loader when processing GLIBC_TUNABLES environment variables. Tunables are basically configuration settings of the runtime that can be set via key/value pairs in the form of key=val. All GLIBC_TUNABLES variables will be processed via __tunables_init(), and will pass the duplicated tunable name and value through parse_tunables(). Before the 2021 commit, you could pass any tunables you wanted including malformed ones, including tunables with the TUNABLE_SECLEVEL_SXID_ERASE security level. The commit addressed this to remove SXID_ERASE tunables as they were considered dangerous tunables that shouldn’t be passed through.

Buffer overflow in tunable processing The problem is, due to how the argument parsing code is written, you can set a tunable to a tunable key/value pair string, and it’ll then also copy and process that second tunable, which goes out of bounds of the duplicated string when attempting to append the value. This duplicated string also resides in mmap()‘d memory, which they could leverage to overflow into adjacent mappings.

Exploitation This bug was leveraged to target link_map objects used for dynamic linking. Since the map came from mmap(), it was assumed to be zeroed memory and thus not explicitly zero-initialized. This is fine in normal cases, however, due to the overflow, this assumption could be violated. By overwriting the zeroed data with setup pointers, they could create an uninitialized use type scenario to setup an attacker-controlled l_info field, which is used for searching for libraries. An attacker could smash this pointer to point to a controlled path setup on the stack to load arbitrary libraries.