Back in the dim & distant past – late 1999, although no records capture the exact date – I was asked to compromise a server and gain root access. I said yes.
This is the first and only time I have deliberately cracked a live, production server.
This was not as questionable an undertaking as it sounds. I knew of the machine in question, and I knew its operator, and he still had a working secure shell login. But sudo had not been configured, and the root password had been forgotten. Whoops. Could I help? I was willing to try.
Why not simply reboot the machine in single user mode? Because it was a busy DNS server and downtime was undesirable. And it wasn’t physically nearby.
I remember looking into current known vulnerabilities. The server was running FreeBSD 3.x-RELEASE and there weren’t many. Moreover I did not trust any “off the shelf” root kits, considering them a source of hidden malware of their own, and I did not have time to learn & practice x86 assembler to develop & discover anything myself. And remembering the brief – I didn’t want to accidentally DoS the server by fumbling a kernel vulnerability.
Fortunately we had the OS source code revision history. I went hunting for recently fixed bugs, in the hope of exploiting them. And found one.
(We didn’t have github back then. But I was subscribed to the FreeBSD commit mailing list).
The issue was in the fts(3) system library and its use by find(1). There was a daily periodic script that ran as root, and invoked find(1) to traverse the entire filesystem. The bug in fts(3) was a buffer overrun in pointer arithmetic when handling a memory reallocation caused by deep recursion, resulting in a segmentation error. Which due to a little bit of sloppiness in the periodic script, meant a core dump.
Even better, it meant a core dump to a file in the current working directory, named
find.core. Et voila. There was our hook: a process memory dump, written as root, to a known filename.
The trick was to make
find.core a symlink, in this case to
/root/.ssh/authorized_keys. The idea being that the dump will be written through the symlink to that destination filename. And to ensure that our SSH key would appear in the resulting file, simply make a deep, deep directory tree with long directories named for that key (with appropriate newline padding), each one containing that symlink.
The long, deep directory hierarchy would trigger the bug, resulting in the core dump, which being a memory image should necessarily include the directory name – i.e., our key would be in the file.
A very small exploit script was run to create just such a structure.
We woke up the next morning, and behold – the periodic task had executed, root’s
authorized_keys file contained a core dump, and amongst the garbage was our public key, for which we had the private part and which sshd(8) would honour.
Et voila, root access gained, privilege escalated, and (recalling the brief) as safely as possible, since the erroneous pointer arithmetic occurred in userland, not in kernel space.