In Linux, a coredump is the log of a crash of an executable. This is generated when a process receives a variety of different signals, such as SIGSEGV. The coredump can be used to explore the memory of the process at the time of a crash.
Every process has many attributes. One of these attributes is the
dumpable property. This is used to determine whether to generate a core file for a crashing process. There are three values for this:
- 0 - Process is not dumpable, and core file won’t be created.
- 1- Process is dumpable.
- 2 - Dump created only if core_pattern is an absolute path or a pipe to a program (suidsafe).
Linux gives the ability to run a program as another user called setuid. Of course, we do not want a coredump to occur, as this could leaks secrets from the program. In order to prevent this from happening, the dumpable value of a setuid binary should be set to 0 instead of 1 at process creation.
This check is done by comparing the Real Id for a user or group to the Effective Id of a user or group. If the process has a real user ID (the actual uid of the user) that is different than the effective (the executed binaries user), then the dumpable attribute is set to 0.
This begs the question: "What would be the dumpable value of a child of a suid process?” A child process would have the dumpable value of 1 if the suid process dropped its privileges. Here is the attack idea: if a suid binary creates a child process that is not suid without dropping the permissions, then a core dump could occur. With this insight, it is time to find an application that this is true in that we can cause to crash!
After investigating, they found that sudo (in some non-standard configurations) was a good candidate. In some setups of sudo, all users can execute a binary as any other user. In the example they use true, which has literally no logic what-so-ever. When true is executed via sudo, the fork call does NOT drop permissions. Because true does not have the setuid bit, the dumpable value is set to 1 when we execute this.
If we can find a crash, this will work! Luckily for us, there are many environmental ways to make a program easily crash:
- Using 'RLIMIT_CPU' to to limit the amount of resources in the program.
- CTRL + \ or
SIGQUIT will stop the process immediately and trigger a coredump.
When using sudo, only some ENV variables are passed through. Because of this, we need to be careful with how we make a coredump happen at a location of our choosing. One of them is the XAUTHORITY ENV variable. By including information into this (that we control), we can control part of the coredump that we are writing.
The program
Logrotate is used generally for automatic rotation, compression, removal, and mailing of log files. Logrotate is extremely lax in how it interrupts files (it ignores binary data), being an ideal candidate once we have a file write primitive. By writing a coredump to the logrotate directory, we can force a string in the
XAUTHORITY to be executed.
The exploit flow goes like this:
- set XAUTHORITY to our logrotate configuration so it will be in child’s memory.
- chdir into
/etc/logrotate. Now, the coredump will occur here.
- Crash the program. This can be done with the
SIGQUIT signal or playing with the CPUs.
- execve our privileged sudo command (true binary in our example) via logrotate.
A second approach was found using Pluggable Authentication Modules (PAM) in Linux. PAM is used by su which will eventually use several external binaries. A code path that does this can be reached only if SELinux is enabled. By using the same method as before with su and the PAM modules, a coredump can be put into logrotate to execute code down the code.
The most interesting part of the post is that there is no true fix for this at the moment. coredumps are an important part of Linux debugging that need to be created. This post used a subtle quirk in the checking of the dumpable property (that is NOT trivial to fix) and expected functionality for crashing binaries in order to cause a coredump in a bad place.
Overall, amazing article with great insight into how Linux and the coredump mechanics work. Not all of the bugs are fixable or caused by memory corruption; some of them are logic flaws.