SUID Priv Escalation - LD_LIBRARY_PATH versus ldconfig and /etc/ld.so.conf



  • Background

    Currently doing some vulnservers on Offensive Security's Proving Grounds Practice Labs. A vulnserver is a machine configured with vulnerabilities for testing/audit and research purposes.

    I came across a machine that had a cronjob running /usr/sbin/ldconfig every 2 minutes and the machine also had an interesting SUID binary that when executed, outputs that it is missing a shared object library file. On the target host, strace command is not installed, but instead, I used ldd to test and analyze the said vulnerable SUID binary.

    Once confirmed that the .so library file is missing, I thought of two ways to exploit such vulnerability. One worked, whereas the other did not. Both methods included compiling a .so file from a C source that will set uid to 0, and launch bash with privileges preserved /bin/bash -p.

    Possible Exploit Paths

    1. Compiling the .so file in current working directory, and running the vulnerable SUID binary while setting LD_LIBRARY_PATH=. (This method did not work)

    2. Checking out /etc/ld.so.conf.d directory for the vulnerable binary configuration and see where it looks for its shared object library files. If I have access (and I do) I can compile the malicious .so file into the library path set forth by its configuration file inside /etc/ls.so.conf.d/.conf. Wait until the cronjob runs, check with ldd again and executing the SUID binary. (This worked)

    Questions

    1. Why did the first method fail in escalating my privilege to root?
    2. Could it have worked if this was a different SUID binary; if this scenario is a binary dependent situation?
    3. From the OS point of view, what is the difference between the two methods of escalation, aside from the obvious that setting LD_LIBRARY_PATH while executing a command only affects the execution environment of the command and not subsequent executions (unless the variable is set again before execution)

    MISC I understand that the cronjob itself was a BIG hint that the second method of exploitation is the intended way. However, I would like to know why the first (and somewhat easier) method did not work as intended?



  • Why did the first method fail in escalating my privilege to root?

    Any setuid binary that runs with elevated privileges will disable LD_LIBRARY_PATH and a number of other security-related environmental variables. You can tell if this is the case because the auxiliary vector AT_SECURE will be set to 1 (run it with LD_SHOW_AUXV=1 to see). This is done by the kernel and causes the dynamic linker to automatically enter secure execution mode.

    Could it have worked if this was a different SUID binary; if this scenario is a binary dependent situation?

    Not if it would run with higher privileges than its parent. Note that statically-linked executables do not have this protection, but they don't need it because they don't use shared libraries anyway.

    From the OS point of view, what is the difference between the two methods of escalation, aside from the obvious that setting LD_LIBRARY_PATH while executing a command only affects the execution environment of the command and not subsequent executions (unless the variable is set again before execution)

    ld.so.conf allows preloading libraries for all binaries, even setuid ones. The reason that is allowed is because you have to be privileged to edit that file, which is not the case for passing environmental variables to executables, even setuid ones.


    Sources:

    Userspace: elf/dl-support.c:304 and elf/dl-support.c:363
    Kernelspace: security/commoncap.c:886, fs/exec.c:1341, and fs/binfmt_elf.c:259



Suggested Topics

  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2