Resources

People often ask me "How did you learn how to hack?" The answer: by reading. This page is a collection of the blog posts and other articles that I have accumulated over the years of my journey. Enjoy!

Looney Tunables: Local Privilege Escalation in the glibc's ld.so (CVE-2023-4911)- 1254

QualysPosted 2 Years Ago
  • The GNU C dynamic loader (ld) will find and load shared object libraries needs by the program. The dynamic loader is extremely security sensitive since it runs with whatever permissions of the binary, such as setuid permissions. Finding a vulnerability in this leads to catastrophic consequences.
  • At the beginning of execution, the function __tunables_init() is called; this processes the GLIBC_TUNABLES environment variable. For each variable that it finds, the program will make a copy of the variable, parse it, sanitize it and edit the original inline. The goal of the parsing is to remove all dangerous tunables out of it.
  • The expected format is tunable1=aaa:tunable2=bbb. However, there is bad input validation on the validity of the format. Providing a value of tunable1=tunable2=AAA will cause some major problems.
  • First, the program copies the entire tunable into the temporary string. Next, since the pointer is not incremented because of the missing ":", the pointer still points to the beginning part of the tunable (tunable1) instead of the next tunable in the list (tunable2). Finally, the second iteration will strcpy into the same buffer, leading to a buffer overflow on the inline write of the variable.
  • Exploitation is super interesting. At this point, regular malloc does not exist. the minimal version of malloc calls mmap() to get memory. So, the authors had to find a way to exploit this by corrupting the mmaped pages. The read-write ELF section makes for an interesting target but the authors could not find a way to get their allocation behind it for the overflow.
  • So, they decided to tackle the mmaped pages written by the tunables_strdup() function. mmap is a top-down allocator. So, by creating a tunable without corrupting then performing the overflow in a second variable, it is possible to overflow the first variable. This ended up not being very fruitful though.
  • Within the loading of the link_map structure, they noticed that not all members are initialized to zero. Additionally, unlike regular malloc, the minimal malloc with calloc() does not initialize to zero. With this, it is possible to control the pointers of the structure! This completely breaks the logic of ld.so in favor of the attacker.
  • Out of all the different data structures, the library search path was the holy grail. This could be used to force ld.so to use a directory that it was not intended to use for loading binaries. Mostly, importantly, we could force it to load malicious libraries as root within the process. This was a pointer though; so, they put data a ton of data (16GB) onto the stack via environment variables and brute forced this. This takes about 30s on Debian and 5m on Ubuntu/Fedora because of Apport.
  • Overall, another amazing blog post from Qualys! Their exploit techniques and innovation are always awesome. In particular I enjoyed the explanation of pointer usage and the various exploit paths that didn't work.