The blog continues at suszter.com/ReversingOnWindows

February 13, 2014

Data Flow Tracking in Flash Player: Undocumented Bytecodes and JIT

Undocumented Bytecodes

I did some analysis how the bytecodes in DoABC tag parsed, and compared the result against what I saw in the AVM2 documentation (May 2007). I found that Flash Player can parse certain bytecodes that are not mentioned in the documentation.

Bytecode Note Bytecode Note Bytecode Note Bytecode Note
0x00 RESERVED 0x40 newfunction 0x80 coerce 0xc0 increment_i
0x01 UNDOCUMENTED 0x41 call 0x81 UNDOCUMENTED 0xc1 decrement_i
0x02 nop 0x42 construct 0x82 coerce_a 0xc2 inclocal_i
0x03 throw 0x43 callmethod 0x83 UNDOCUMENTED 0xc3 declocal_i
0x04 getsuper 0x44 callstatic 0x84 UNDOCUMENTED 0xc4 negate_i
0x05 setsuper 0x45 callsuper 0x85 coerce_s 0xc5 add_i
0x06 dxns 0x46 callproperty 0x86 astype 0xc6 subtract_i
0x07 dxnslate 0x47 returnvoid 0x87 astypelate 0xc7 multiply_i
0x08 kill 0x48 returnvalue 0x88 UNDOCUMENTED 0xc8 RESERVED
0x09 label 0x49 constructsuper 0x89 UNDOCUMENTED 0xc9 RESERVED
0x0a RESERVED 0x4a constructprop 0x8a RESERVED 0xca RESERVED
0x0b RESERVED 0x4b RESERVED 0x8b RESERVED 0xcb RESERVED
0x0c ifnlt 0x4c callproplex 0x8c RESERVED 0xcc RESERVED
0x0d ifnle 0x4d RESERVED 0x8d RESERVED 0xcd RESERVED
0x0e ifngt 0x4e callsupervoid 0x8e RESERVED 0xce RESERVED
0x0f ifnge 0x4f callpropvoid 0x8f RESERVED 0xcf RESERVED
0x10 jump 0x50 UNDOCUMENTED 0x90 negate 0xd0 getlocal_0
0x11 iftrue 0x51 UNDOCUMENTED 0x91 increment 0xd1 getlocal_1
0x12 iffalse 0x52 UNDOCUMENTED 0x92 inclocal 0xd2 getlocal_2
0x13 ifeq 0x53 UNDOCUMENTED 0x93 decrement 0xd3 getlocal_3
0x14 ifne 0x54 RESERVED 0x94 declocal 0xd4 setlocal_0
0x15 iflt 0x55 newobject 0x95 typeof 0xd5 setlocal_1
0x16 ifle 0x56 newarray 0x96 not 0xd6 setlocal_2
0x17 ifgt 0x57 newactivation 0x97 bitnot 0xd7 setlocal_3
0x18 ifge 0x58 newclass 0x98 RESERVED 0xd8 RESERVED
0x19 ifstricteq 0x59 getdescendants 0x99 RESERVED 0xd9 RESERVED
0x1a ifstrictne 0x5a newcatch 0x9a RESERVED 0xda RESERVED
0x1b lookupswitch 0x5b RESERVED 0x9b RESERVED 0xdb RESERVED
0x1c pushwith 0x5c RESERVED 0x9c RESERVED 0xdc RESERVED
0x1d popscope 0x5d findpropstrict 0x9d RESERVED 0xdd RESERVED
0x1e nextname 0x5e findproperty 0x9e RESERVED 0xde RESERVED
0x1f hasnext 0x5f UNDOCUMENTED 0x9f RESERVED 0xdf RESERVED
0x20 pushnull 0x60 getlex 0xa0 add 0xe0 RESERVED
0x21 pushundefined 0x61 setproperty 0xa1 subtract 0xe1 RESERVED
0x22 RESERVED 0x62 getlocal 0xa2 multiply 0xe2 RESERVED
0x23 nextvalue 0x63 setlocal 0xa3 divide 0xe3 RESERVED
0x24 pushbyte 0x64 getglobalscope 0xa4 modulo 0xe4 RESERVED
0x25 pushshort 0x65 getscopeobject 0xa5 lshift 0xe5 RESERVED
0x26 pushtrue 0x66 getproperty 0xa6 rshift 0xe6 RESERVED
0x27 pushfalse 0x67 UNDOCUMENTED 0xa7 urshift 0xe7 RESERVED
0x28 pushnan 0x68 initproperty 0xa8 bitand 0xe8 RESERVED
0x29 pop 0x69 RESERVED 0xa9 bitor 0xe9 RESERVED
0x2a dup 0x6a deleteproperty 0xaa bitxor 0xea RESERVED
0x2b swap 0x6b RESERVED 0xab equals 0xeb RESERVED
0x2c pushstring 0x6c getslot 0xac strictequals 0xec RESERVED
0x2d pushint 0x6d setslot 0xad lessthan 0xed RESERVED
0x2e pushuint 0x6e getglobalslot 0xae lessequals 0xee RESERVED
0x2f pushdouble 0x6f setglobalslot 0xaf greaterequals 0xef debug
0x30 pushscope 0x70 convert_s 0xb0 UNDOCUMENTED 0xf0 debugline
0x31 pushnamespace 0x71 esc_xelem 0xb1 instanceof 0xf1 debugfile
0x32 hasnext2 0x72 esc_xattr 0xb2 istype 0xf2 UNDOCUMENTED
0x33 RESERVED 0x73 convert_i 0xb3 istypelate 0xf3 RESERVED
0x34 RESERVED 0x74 convert_u 0xb4 in 0xf4 RESERVED
0x35 UNDOCUMENTED 0x75 convert_d 0xb5 RESERVED 0xf5 RESERVED
0x36 UNDOCUMENTED 0x76 convert_b 0xb6 RESERVED 0xf6 RESERVED
0x37 UNDOCUMENTED 0x77 convert_o 0xb7 RESERVED 0xf7 RESERVED
0x38 UNDOCUMENTED 0x78 checkfilter 0xb8 RESERVED 0xf8 RESERVED
0x39 UNDOCUMENTED 0x79 RESERVED 0xb9 RESERVED 0xf9 RESERVED
0x3a UNDOCUMENTED 0x7a RESERVED 0xba RESERVED 0xfa RESERVED
0x3b UNDOCUMENTED 0x7b RESERVED 0xbb RESERVED 0xfb RESERVED
0x3c UNDOCUMENTED 0x7c RESERVED 0xbc RESERVED 0xfc RESERVED
0x3d UNDOCUMENTED 0x7d RESERVED 0xbd RESERVED 0xfd RESERVED
0x3e UNDOCUMENTED 0x7e RESERVED 0xbe RESERVED 0xfe RESERVED
0x3f RESERVED 0x7f RESERVED 0xbf RESERVED 0xff RESERVED

The loop and the big switch statement parsing DoABC bytecode is near 0x6087e9. Instruction near 0x58f25d also reads bytecode. The documentation certainly needs an update on Adobe's side so developers can add the currently undocumented bytecodes to their decompiler/disassembler.

JIT

After adding new functionalities to my pintool I run it against Flash Player. Here is my observation.

When executing a flash file containing DoAction tag in Flash Player no memory page allocated with or set to *EXECUTE* flag. Thus no dynamically generated code was executed with the most common method. Therefore I think DoAction works with interpreted execution. Meaning every single bytecode run on isolation rather than a set of bytes compiled&run (JIT).

When executing a flash file containing DoABC tag in Flash Player I observed increased usage of VirtualAlloc. The page was allocated with PAGE_READWRITE flag. Later on the execution the page was set to PAGE_EXECUTE_READ and the execution flow was transferred to the page. When the execution was returned to the caller the page was set back to PAGE_READWRITE. I knew this was a part of how JIT works. Change of the memory protection flags is the mitigation for DEP.

0x5205a6 is a VirtualProtect call to change the memory protection flags. When it's called with PAGE_READWRITE it's called via 0x5fc39c. When it's called with PAGE_EXECUTE_READ it's called via 0x5fc2e9.

During my experiment I figured out that instruction at 0x5d20ef calls into the JIT-compiled code. Though this might not be the only address to call JIT-compiled code from. I observed many call backs in the JIT-compiled code. One of the callback might be to give continuous feedback to the caller for example if a long loop is being executed. I observed that constants are encrypted with xor instructions to make memory spraying more difficult. This is not new but first time for me to see. This is how 0x41414141 looks like when it's encrypted.
03af1f67 b83a7c1959      mov     eax,59197C3Ah
03af1f6c 357b3d5818      xor     eax,18583D7Bh
All offsets in this post are RVAs, that is relative to Flash Player's image base. Offsets are appropriate in Flash Player 12.0.0.38 (flashplayer_12_sa.exe has a size of 10,339,208).

February 9, 2014

Data Flow Tracking in Flash Player: DefineBitsJPEG2

Here are some offsets of the standalone Flash Player 12.0.0.38 (flashplayer_12_sa.exe has a size of 10,339,208). The offsets are reached when parsing ImageData field in DefineBitsJPEG2 tag.
0x570e7  | Checks for PNG signature.
0x57124  | Checks for GIF87a signature.
0x57138  | Checks for GIF89a signature.
0x5717D  | Checks for JPEG XR (Windows Media Photo) signature.
0x5719B  | Checks for ATF (Adobe Texture Format) signature.
0x4b6fc2 | Checks for JPEG (ff d8) signature.
The first five checks performed on the permanent buffer that I wrote about in the previous post. The last check is performed on the match buffer that contains the first 0x200 bytes of ImageData in the permanent buffer. The bytes are copied from the permanent buffer to the match buffer using fast memcpy function (0x701030).

I looked at the specification of DefineBitsJPEG2 tag. It's interesting to see that swf specification version 19 says "Compressed image data is either JPEG, PNG, or GIF89a format". However as seen above there might be other file formats supported. Good to know if you want to fuzz this area.

All offsets in this post are RVAs, that is relative to Flash Player's image base.

February 4, 2014

Data Flow Tracking in Flash Player

I've been writing a Pintool that is to track the data flow between buffers in Flash Player. The tool logs when bytes from the flash file are read to the buffer, and when bytes from the buffer are copied to the subsequent buffer. The tool also logs the instruction that dereferences a position in the buffer. And, if appropriate, the tool can project the position in the buffer back to the position in the flash file.

Using Pintool can speed up the work that I would do with debuggers otherwise. When analyzing with Pintool I don't see all the non-relevant instructions that a debugger would show up but rather see more, and more relevant information. Therefore I can focus better on what's important.

I picked up an uncompressed flash file - with FWS signature in its header - and loaded it in the standalone Flash Player 12.0.0.38 (flashplayer_12_sa.exe).

When executing, the flash file is read by a loop of ReadFile() that takes 0x10000 as the number of bytes (64Kb) to read in each iteration. Once ReadFile() receives the bytes read from the file, the bytes are copied to the permanent buffer. _fastcopy_I is used to copy bytes to the permanent buffer that has RVA of 0x70c396. Note, it's reasonable to assume there might be other copy functions embedded in Flash Player for different architectures.

Many bytes in the permanent buffer are just propagated to other buffers. Otherwise, a validation is directly performed by dereferencing certain regions of the permanent buffer. I was looking at the latter as I'd inspect the data flow on a deeper level at a later date. One such validation on the permanent buffer is the following inline strlen() core, that has RVA of 0x1a922.

0040a922 8a08            mov     cl,byte ptr [eax]
0040a924 40              inc     eax
0040a925 84c9            test    cl,cl
0040a927 75f9            jne     FlashPlayer!WinMainSandboxed+0x176a8 (0040a922)


Instructions dereference the permanent buffer from 42 ditinct locations in Flash Player. I had a look at the addresses with their surrounding code and found the inline strlen() core above to be the most interesting. Note, the above inline strlen() core can be found at multiple locations in Flash Player.

There are couple of reasons I found the above code interesting. When looking at the surrounding code I didn't see sanity check of the string size. The position in the buffer can be projected back to the position in the flash file by Pintool. At this point, I suspected I had good control over the string size as I can make it to be a long string and even I can remove the ending zero in the flash file without causing Flash Player to bail out early.

Below is the screenshot of the flash file. strlen() is triggered on "movieLoader" string ending with zero. It's highlighted.

I was considering to alter the flash file in a way to overwrite the ending zero of the string, and all subsequent zeros in the following tags (DefineButton2, PlaceObject2, etc). It would mean the string would run until the end of the file hoping strlen() to read out of the bounds. Actually, when experimenting, I took the plunge to remove the last few tags and appended few "A" characters to the string until end-of-file, without ending zero. Also, adjusted the file size in the header as it was obligatory. Here is a photo of the string.

I run Flash Player and saw in the log produced by Pintool that the inline strlen() is triggered meaning it processes the altered string. This is good because the code is still reachable when reading the corrupted string. However an unexpected zero byte beyond the string causing the loop to break without Flash Player entering in an inconsistent state or reading out of bounds.

I wanted to know how the zero byte is set at the end of the string so I changed Pintool to log all write accesses on the permanent buffer. When I run Flash Player again, I didn't see in the log that zero byte is set at the end of the string. As being paranoid today, I immediately thought that might be an uninitialized value that is zero by chance but this was a guess so thought better check how the memory is allocated for the permanent buffer. I added the required code to Pintool to see how the memory is allocated and I saw it is allocated by VirtualAlloc. This explains the zero byte as memory allocated with this function is automatically initialized with zero.

I was thinking if I can construct the flash file to place the string at the end of memory page without leaving space for padding zero bytes. I was able to control the amount of memory to allocate by changing the file size field in the flash file (at offset 4). What I observed is that the size of allocated memory is always bigger than the file size in the header and so there are always padding bytes. In my experiment I saw the pattern that the amount of memory to be allocated is calculated by incrementing the file size by one and rounding up to the nearest multiple of 0x1000.

It seems defense against this string attack is consciously added by Adobe preventing to read out of bounds.

January 14, 2014

Flash Player Unloading Vulnerability III

This is the third article in this series that I didn't expect to write but it turns out the fix for CVE-2013-5332 insufficiently addresses the issue around the dialog boxes. Adobe had issued a fix that prevents the testcase I provided them from crashing the plugin but it's still possible to reach the bug just by adding an additional step to that testcase. I talked to Adobe about this.

Now the crash state is different to the crash state previously seen but in both cases the instruction dereferences freed memory. The vulnerability enables the attacker to divert the execution flow via the dispatch table that can be constructed due to a use-after-free issue.

I'm using Application Verifier and GFlags tool to make the vulnerability easy to see, and I'm also doing this because I observed that the application didn't crash at certain times. It could have happened because an object was allocated to the freed memory in a way to contain a valid function pointer. So rather than dereferencing freed memory the wrong function was called by the dispatcher and the execution completed without access violation.

Anyway here is the configuration. I configured GFlags for Internet Explorer 11 like below.

Configured Application Verifier, too.

In Windbg, I set debug of child process so when to open iexplore.exe from the disk I'm able to debug both broker and renderer processes. In the beginning of the article I mentioned that an additional step is required to the testcase in order to trigger the bug. It is to visit a web page that contains a Flash object which simply is to exercise the Flash plugin. After that, we can load the testcase to trigger the dialog box seen below.

At this point we can see many problems reported by Application Verifier. Here are two.
=======================================
VERIFIER STOP 00000202: pid 0xBE0: Freeing heap block containing an active critical section.

4C3D6FE0 : Critical section address.
00DEF2FC : Critical section initialization stack trace.
4C3D6FE0 : Heap block address.
0000001C : Heap block size.

=======================================
[...]
=======================================
VERIFIER STOP 00000350: pid 0xBE0: Unloading DLL that allocated TLS index that was not freed.

004BABBA : TLS index
6759965F : Address of the code that allocated this TLS index.
4B916FCE : DLL name address. Use du to dump it.
67060000 : DLL base address.

=======================================
After the close of dialog box the instruction at 6724f02b dereferences freed memory during processing the dispatch table. I highlighted the vulnerable path that can execute injected code.
(c44.e64): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\system32\Macromed\Flash\Flash32_11_9_900_170.ocx -
eax=0b611060 ebx=0b5fd0a0 ecx=7ffd7000 edx=6e1027a4 esi=0b5ef000 edi=0b612020
eip=6724f02b esp=067fc018 ebp=067fc028 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00210206
Flash32_11_9_900_170!DllUnregisterServer+0x173da:
6724f02b 8b7024 mov esi,dword ptr [eax+24h] ds:0023:0b611084=????????
2:055> u
Flash32_11_9_900_170!DllUnregisterServer+0x173da:
6724f02b 8b7024 mov esi,dword ptr [eax+24h] <--Read freed memory
6724f02e eb02 jmp Flash32_11_9_900_170!DllUnregisterServer+0x173e1 (6724f032)
6724f030 33f6 xor esi,esi
6724f032 85f6 test esi,esi
6724f034 7420 je Flash32_11_9_900_170!DllUnregisterServer+0x17405 (6724f056)

6724f036 8b06 mov eax,dword ptr [esi] <--Read attacker controlled memory
6724f038 8bce mov ecx,esi
6724f03a ff5004 call dword ptr [eax+4] <--Divert execution
 I recorded a video of the vulnerability using the latest Flash Player (12.0.0.38) for Internet Explorer.

January 10, 2014

Triaging crash on instruction "call [rax]"

The following Python script causing handled access violation when it's executed with Python 2.7.6.
import tkMessageBox
import time

time.sleep(6)
The exception can be caught by the following command.
C:\Work>"c:\Program Files\Debugging Tools for Windows (x64)\windbg.exe" -g c:\Python27\python.exe messagebox.py
Then Windbg displays:
(c2a4.c374): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for c:\Python27\DLLs\tk85.dll -
tk85!Tk_MainLoop+0x122:
00000000`102de8b2 ff9068030000    call    qword ptr [rax+368h] ds:00000000`00000368=????????????????
call [rax] suggests to pay attention because the issue could be exploitable if rax is attacker controlled.

We can see the crash happens when we read address near null so you may think it's a non-exploitable null pointer dereference. However to confirm this we need to investigate how rax is set to null. If null is read from previously freed memory we may have the chance to corrupt the memory in a way to inject arbitrary pointer therefore to make the issue exploitable.

So the preceding instruction sets rax that is:
0:000> ub rip L1
tk85!Tk_MainLoop+0x11b:
00000000`102de8ab 488b0576bd0d00  mov     rax,qword ptr [tk85!XDrawLine+0x59b98 (00000000`103ba628)]
We can see the address is fixed, relative to tk85, which was allocated when the module was being loaded in the virtual address space. Now we can say with more confidence the issue is a non-exploitable null pointer dereference.

Python 3.x doesn't support tkMessageBox so it's not affected.

January 9, 2014

Using Pintools to Detect Bugs II: Overlap of Regions

There are functions that can take source and destination parameters to copy data. That functions include the followings: strncpy(), strncat(), memcpy(), wcsncpy(), wcsncat(), strcat(), strcpy(), wcscat(), wcscpy(), CopyMemory(), sscanf(), printf(), swscanf(), swprintf(). If the destination and source regions overlap the behavior is undefined. This really means one of the regions can get partly overwritten when copying. I wrote about this earlier.

Some time ago I wrote a tool to detect such errors runtime and I used Pin framework. Though I've never seen an exploitable bug regarding this classification it's still valuable to detect these issues as the attacker could write memory that he's not supposed to. This could lead to enter the program in an inconsistent state.

The tool I wrote produces the following straightforward output on the test sample.
Overlap of source and destination regions at 6c79396f in wcsncat(021b1ee8,021b1eec,8)
  Stack
    001efd90 7c 10 eb 00 e8 1e 1b 02 ec 1e 1b 02 08 00 00 00
    001efda0 74 33 eb 00 01 00 00 00 07 12 eb 00 01 00 00 00
    001efdb0 58 3e 1b 02 40 5c 1b 02 10 5a cc 31 00 00 00 00
    001efdc0 00 00 00 00 00 e0 fd 7e 00 00 00 00 00 00 00 00
  Source
    021b1eec 75 00 72 00 63 00 65 00 20 00 73 00 74 00 72 00
    021b1efc 69 00 6e 00 67 00 00 00 00 00 00 00 00 00 00 00
    021b1f0c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    021b1f1c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  Destination
    021b1ee8 73 00 6f 00 75 00 72 00 63 00 65 00 20 00 73 00
    021b1ef8 74 00 72 00 69 00 6e 00 67 00 00 00 00 00 00 00
    021b1f08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    021b1f18 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
You may ask what's the news to detect this bug as Valgrind can do for ages. Well, my approach is not to use symbols, source code, or any debug information so I can apply my tests against arbitrary binaries.

Even just few string copy functions were added to the tool I had found plenty low-severity bugs in high-profile applications by this approach.

Here is the tool. Feel free to improve it according to your needs.

UPDATE 15/January/2014 Added CopyMemory() to the list.
UPDATE 2/February/2014 Added sscanf(), printf(), swscanf(), swprintf() to the list. Reference.
  This blog is written and maintained by Attila Suszter. Read in Feed Reader.