A few weeks ago I was lucky enough to score a Raspberry Pi from bNull. This awesome little device seemed to be the hottest new gadget to add to the haxoring desk. After I reviewed the specs, it’s not hard to see why. The RPi is quite a versatile piece of hardware. A quick check with Google uncovered scores of blogs featuring projects that use the Raspberry Pi. Another, unrelated, check of my RSS feed seemed to suggest that practical ARM exploitation is a pretty important thing. This was enough to covince me that it’s time to teach myself real world ARM exploitation techniques using a Raspberry Pi! However, before I start blogging about that, I’d like to share an interesting discovery that came about while setting up the RPi testbed.
While setting up my test environment I noticed something very interesting. After upgrading my RPi to the new Raspbian Wheezy image from the initial Debian image availble earlier, all my binariers now had an executable stack. The screen shot below shows the memory layout of a simple program I wrote that had a vanilla stack based buffer overflow bug.
Notice that the stack of this process, located at 0xbea31000, had the read, write, and execute permissions applied to it. This was quite a surprise to me, since this very same binary did not have an executable stack when executed on the previous default RPi debian image. So what was changed? And what was this libconfi_rpi library that was loaded into memory?
A quick search revealed that libconfi_rpi was the optimized memcpy and memset library packaged with the Wheezy distribution. It was loaded into memory using /etc/ld.so.preload. Could this be making the stack executable?
Lets step back for a second, why would a stack be made executable? This article sumed it up nicely. Simply put, a stack will be made executable if:
1. GCC generates code that requires an executable stack.
2. ASM source (.s files) explicitly asks for executable stack.
3. ASM source (.s files) is missing a GNU-stack note. (A common bug)
If a binary is complied from source containing one of the above conditions, or loads a shared object that had any of the above conditions during compilation, the process’ stack for that binary will be marked executable. Knowing that my binary previouly had a noexec stack, and this libcofi_rpi.so was now loaded into my memory, I was pretty sure it explicitly asked for an executable stack. In fact, a quick scan of the shared object (below) did in fact reveal that library was compiled to have a RWX stack!
So, now that we found the problem, how do we fix it. Well I pulled down the open source libcofi_pi, and attempted to verify if any of the above conditions were true. Low and behold, the code was written in ARM assembly and does not include the GNU-stack note in either of the two source files. This forced the assembler to create a shared object that requested an executable stack. By adding the note (pictured below, line 336) and recompiling the sources files, the shared object should now require only a read, write stack.
After making the subsequent edits to the sources files and rebuilding the shared object, a quick scan of the elf indicated that the library, did indeed, only require a read, write stack (image below). Simply overwriting the old shared object with this new binary should fix Wheezy eXotic stack.
Rerunning my test server and reviewing its memory layout confirmed that we are now back to a RW stack and ready to learn ARM exploitation on a relatively up to date system.
All of these edits were pushed to the libcofi_rpi project hosted on GitHub. If you have an RPi and want to pull down the new update, I suspect you have to do this manually for now. I am not sure how long this will take to be pushed up to the Debian image.
Both comments and trackbacks are currently closed.