When one corruption is not enough: Analyzing an Adobe Pwn2Own ExploitDecember 12, 2018 | Abdul-Aziz Hariri
Throughout this blogpost, I’ll go over the exploitation technique used by 360 to exploit the heap-based buffer overflow in Adobe Reader. For their original submission, they used a kernel exploit to escape the sandbox. This blog post won’t cover the kernel portion of the exploit and focuses solely on the Reader portion.
The version of Reader I used to analyze the exploit is 2015.023.20070 and can be grabbed from Adobe’s FTP server.
Nothing too fancy here. Setup a couple of variables then call
memory1 then more variables and then call
So, what the heck is
memory2? Let’s start with
The function allocates an
Array of size
len2 and sets the first element (I call it the marker element) to 0x11223344. Then fills the
ArrayBuffers of size
len1. Finally, it enters a second loop that pokes holes in the array. It looks close to something like this:
Want to verify that in a debugger? No problem:
But why? Well, first, this is a heap overflow. The logical reason for this is to setup the heap in a way to make sure that the vulnerable object we’re overflowing is thrown in one of the holes poked. In this case, we’re overflowing an object of size 0x1200:
Let’s cover the obvious first. It starts off by getting a reference to a button. If successful, then it loops through the array and starts closing some of the holes poked earlier. It leaves some holes unfilled. It then sets
display.visible. Then calls
The reason for filling the holes and keeping a bit unfilled is to make sure that the vulnerable object, when allocated, fills one of the holes. In my opinion, the most interesting part in this function is “
btt1.display = display.visible”. Why ?
Well, I had to wrap my head around this for a bit. Turns out that if you have an
Icon set to a
Button, and it was initially set to be
display variable of the
display.visible. So in fact, what they did was basically create a
Button object, attach an Icon to it (JPEG2000 image in this case) and set it to hidden. When display is set to
display.visible, the following happens:
1. An object of size 0x1200 is created
2. The overflow is triggered
The fascinating part about the vulnerability is that after it ends up overflowing the next chunk, it also ends up writing a controlled WORD value. In our case, and if everything was aligned properly, it’ll end up overwriting the size of the next ArrayBuffer chunk.
To make this clearer, here’s the ArrayBuffer before the size got overwritten:
And after the size was overwritten:
Since the bug allows us to overwrite the length of the ArrayBuffer object next by a WORD value, the 360 guys logically went with the max they could - 0xFFFF. Then
memory3 is called:
We did overwrite the
0xFFFF but that does not give a lot of read/write freedom. The function loops through the Array to look for the
ArrayBuffer with the corrupted
byteLength. Once found, it created a
DataView object for thatArrayBuffer`.
What happened next? They used the
DataView of the corrupted
ArrayBuffer to corrupt the size of the next
ArrayBuffer with a bigger
The last loop is to find the newly corrupted
ArrayBuffer and create a
DataView object for it.
The rest of the code is mostly to leak memory and gain RCE using the new
To sum up the whole story:
1. The vulnerability was only triggered once.
2. The bug is triggered when the JPEG2000 image is parsed.
4. The Button display mode is changed to visible then the image parsing starts and the bug is triggered.
5. They sprayed a bunch of ArrayBuffers of size 0x1200 and poked holes.
6. They filled some holes then triggered the bug. Note that when the bug is triggered, the vulnerable allocation is created before the parsing happens.
7. The overflow allows overwriting the size of the next chunk with 1 controlled WORD, 0xFFFF.
8. This is not enough for a read/write, so they used the corrupted chunk (with size 0xFFFF) to corrupt the size of the next chunk with size 0x77777777.
9. They looped through the elements in the array until they found the newly corrupted chunk and creates a DataView for it to give them read/write freedom.
Again, this only covers the Adobe Reader portion of their entire exploit chain. Back in 2017, the team combined this heap overflow with a Windows kernel info leak, and an RCE through an uninitialized buffer in the Windows kernel to win $50,000 USD. Of course, Adobe patched this particular issue some time ago. Still, we see similar techniques used in malware leveraging PDFs to this day, and Acrobat and Reader continue to have a broad attack surface. There’s no doubt this will continue to be a fruitful area of research both for myself and security researchers submitting to the ZDI.