In this blog post I'm writing about the method I experiment with to discover potential areas, that may or may not be prone to integer errors, in Flash Player.
I have 26k flash files that are used as a corpus to generate the test samples for Flash Player. The test samples have an element of 0x41424241 in the integer pool. I have a total of 344k files generated to test Flash Player with.
During the test, I use a pintool to instrument the JITted code. The pintool is based on this implementation. Since the elements in the integer pool being dereferenced by action script it makes sense to restrict the instrumentation to JITted code.
I use instruction-level instrumentation that allows to check the register values at every single instruction being executed. If any of the general registers have the value of 0x41424241 and the instruction is referencing to that register, the instruction information along with general registers are logged.
The pintool pre-allocates the address of 0x41424241 so Flash Player won't use that memory address and so reducing the irrelevant lines in the log.
There is no need to wait for the test to finish to get partial results. A log file is generated for each test file rendered by Flash Player.
The size of log files are vary. Some are close to size 0 specially if the value above makes the code to fail early. There are many log files with size 4k. When the execution keeps going long the size is about 16k. If the value has to do something with a loop the log can reach 100k but that's rare.
Logs can be grouped and many can be thrown away as they don't contain instructions associated with vulnerabilities.
What I look for is like signed shift, addition, subtraction, or multiplication instructions. If the value is used in displacement with lea instruction that counts suspicious too.
Once an address in the log is chosen for closer inspection, I reproduce the log on isolation with an option to dump the JITted pages so I can manually analyze the surrounding area of that address in disassembler. Knowing the state information it's also possible to debug the code.
If results positive, certain level of automation can be added.
Showing posts with label Flash Player. Show all posts
Showing posts with label Flash Player. Show all posts
August 9, 2014
July 16, 2014
251 Potential NULL Pointer Dereferences in Flash Player
251 potential NULL pointer dereference issues have been identified in Flash Player 14 by pattern matching approach. The file examined is NPSWF32_14_0_0_145.dll (17,029,808 bytes).
The issues are classified as CWE-690: Unchecked Return Value to NULL Pointer Dereference.
I don't copy&paste all the issues in this blog post but bringing up few examples.
NPSWF32_14_0_0_145!BrokerMainW+0xf6f6b:
5438a1d0 f6410810 test byte ptr [ecx+8],10h
5438a1d4 8b4104 mov eax,dword ptr [ecx+4]
5438a1d7 7411 je NPSWF32_14_0_0_145!BrokerMainW+0xf6f85 (5438a1ea)
NPSWF32_14_0_0_145!BrokerMainW+0xf6f74:
5438a1d9 85c0 test eax,eax
5438a1db 740b je NPSWF32_14_0_0_145!BrokerMainW+0xf6f83 (5438a1e8)
NPSWF32_14_0_0_145!BrokerMainW+0xf6f78:
5438a1dd 8b4c2404 mov ecx,dword ptr [esp+4]
5438a1e1 8b448808 mov eax,dword ptr [eax+ecx*4+8]
5438a1e5 c20400 ret 4
NPSWF32_14_0_0_145!BrokerMainW+0xf6f83:
5438a1e8 33c0 xor eax,eax <--Set return value to NULL
NPSWF32_14_0_0_145!BrokerMainW+0xf6f85:
5438a1ea c20400 ret 4 <--Return with NULL
0:012> u 5438a47b L2
NPSWF32_14_0_0_145!BrokerMainW+0xf7216:
5438a47b e850fdffff call NPSWF32_14_0_0_145!BrokerMainW+0xf6f6b (5438a1d0)
5438a480 8a580c mov bl,byte ptr [eax+0Ch] <--Dereference NULL
NPSWF32_14_0_0_145!BrokerMainW+0xcfbfb:
54362e60 8b4128 mov eax,dword ptr [ecx+28h]
54362e63 8b4c2404 mov ecx,dword ptr [esp+4]
54362e67 3b4804 cmp ecx,dword ptr [eax+4]
54362e6a 7205 jb NPSWF32_14_0_0_145!BrokerMainW+0xcfc0c (54362e71)
NPSWF32_14_0_0_145!BrokerMainW+0xcfc07:
54362e6c 33c0 xor eax,eax <--Set return value to NULL
54362e6e c20400 ret 4 <--Return with NULL
NPSWF32_14_0_0_145!BrokerMainW+0xcfc0c:
54362e71 56 push esi
54362e72 8b748808 mov esi,dword ptr [eax+ecx*4+8]
54362e76 56 push esi
54362e77 e8e4b0faff call NPSWF32_14_0_0_145!BrokerMainW+0x7acfb (5430df60)
54362e7c 83c404 add esp,4
54362e7f 85c0 test eax,eax
54362e81 7407 je NPSWF32_14_0_0_145!BrokerMainW+0xcfc25 (54362e8a)
NPSWF32_14_0_0_145!BrokerMainW+0xcfc1e:
54362e83 8b4010 mov eax,dword ptr [eax+10h]
54362e86 5e pop esi
54362e87 c20400 ret 4
NPSWF32_14_0_0_145!BrokerMainW+0xcfc25:
54362e8a 8bc6 mov eax,esi
54362e8c 83e0f8 and eax,0FFFFFFF8h
54362e8f 5e pop esi
54362e90 c20400 ret 4
0:012> u NPSWF32_14_0_0_145+006b4eb2 L2
NPSWF32_14_0_0_145!BrokerMainW+0xd1c4d:
54364eb2 e8a9dfffff call NPSWF32_14_0_0_145!BrokerMainW+0xcfbfb (54362e60)
54364eb7 8b7004 mov esi,dword ptr [eax+4] <--Dereference NULL
NPSWF32_14_0_0_145!BrokerMainW+0x6535:
5429979a 0fb74108 movzx eax,word ptr [ecx+8]
5429979e 48 dec eax
5429979f 48 dec eax
542997a0 740c je NPSWF32_14_0_0_145!BrokerMainW+0x6549 (542997ae)
NPSWF32_14_0_0_145!BrokerMainW+0x653d:
542997a2 83e815 sub eax,15h
542997a5 7403 je NPSWF32_14_0_0_145!BrokerMainW+0x6545 (542997aa)
NPSWF32_14_0_0_145!BrokerMainW+0x6542:
542997a7 33c0 xor eax,eax <--Set return value to NULL
542997a9 c3 ret <--Return with NULL
NPSWF32_14_0_0_145!BrokerMainW+0x6545:
542997aa 8d4110 lea eax,[ecx+10h]
542997ad c3 ret
NPSWF32_14_0_0_145!BrokerMainW+0x6549:
542997ae 8d410c lea eax,[ecx+0Ch]
542997b1 c3 ret
0:012> u NPSWF32_14_0_0_145+005f3423 L2
NPSWF32_14_0_0_145!BrokerMainW+0x101be:
542a3423 e87263ffff call NPSWF32_14_0_0_145!BrokerMainW+0x6535 (5429979a)
542a3428 8038fe cmp byte ptr [eax],0FEh <--Dereference NULL
You can find a list of 251 potential NULL pointer dereferences in Flash Player here.
The issues are classified as CWE-690: Unchecked Return Value to NULL Pointer Dereference.
I don't copy&paste all the issues in this blog post but bringing up few examples.
First Example
0:012> uf 5438a1d0NPSWF32_14_0_0_145!BrokerMainW+0xf6f6b:
5438a1d0 f6410810 test byte ptr [ecx+8],10h
5438a1d4 8b4104 mov eax,dword ptr [ecx+4]
5438a1d7 7411 je NPSWF32_14_0_0_145!BrokerMainW+0xf6f85 (5438a1ea)
NPSWF32_14_0_0_145!BrokerMainW+0xf6f74:
5438a1d9 85c0 test eax,eax
5438a1db 740b je NPSWF32_14_0_0_145!BrokerMainW+0xf6f83 (5438a1e8)
NPSWF32_14_0_0_145!BrokerMainW+0xf6f78:
5438a1dd 8b4c2404 mov ecx,dword ptr [esp+4]
5438a1e1 8b448808 mov eax,dword ptr [eax+ecx*4+8]
5438a1e5 c20400 ret 4
NPSWF32_14_0_0_145!BrokerMainW+0xf6f83:
5438a1e8 33c0 xor eax,eax <--Set return value to NULL
NPSWF32_14_0_0_145!BrokerMainW+0xf6f85:
5438a1ea c20400 ret 4 <--Return with NULL
0:012> u 5438a47b L2
NPSWF32_14_0_0_145!BrokerMainW+0xf7216:
5438a47b e850fdffff call NPSWF32_14_0_0_145!BrokerMainW+0xf6f6b (5438a1d0)
5438a480 8a580c mov bl,byte ptr [eax+0Ch] <--Dereference NULL
Second Example
0:012> uf 54362e60NPSWF32_14_0_0_145!BrokerMainW+0xcfbfb:
54362e60 8b4128 mov eax,dword ptr [ecx+28h]
54362e63 8b4c2404 mov ecx,dword ptr [esp+4]
54362e67 3b4804 cmp ecx,dword ptr [eax+4]
54362e6a 7205 jb NPSWF32_14_0_0_145!BrokerMainW+0xcfc0c (54362e71)
NPSWF32_14_0_0_145!BrokerMainW+0xcfc07:
54362e6c 33c0 xor eax,eax <--Set return value to NULL
54362e6e c20400 ret 4 <--Return with NULL
NPSWF32_14_0_0_145!BrokerMainW+0xcfc0c:
54362e71 56 push esi
54362e72 8b748808 mov esi,dword ptr [eax+ecx*4+8]
54362e76 56 push esi
54362e77 e8e4b0faff call NPSWF32_14_0_0_145!BrokerMainW+0x7acfb (5430df60)
54362e7c 83c404 add esp,4
54362e7f 85c0 test eax,eax
54362e81 7407 je NPSWF32_14_0_0_145!BrokerMainW+0xcfc25 (54362e8a)
NPSWF32_14_0_0_145!BrokerMainW+0xcfc1e:
54362e83 8b4010 mov eax,dword ptr [eax+10h]
54362e86 5e pop esi
54362e87 c20400 ret 4
NPSWF32_14_0_0_145!BrokerMainW+0xcfc25:
54362e8a 8bc6 mov eax,esi
54362e8c 83e0f8 and eax,0FFFFFFF8h
54362e8f 5e pop esi
54362e90 c20400 ret 4
0:012> u NPSWF32_14_0_0_145+006b4eb2 L2
NPSWF32_14_0_0_145!BrokerMainW+0xd1c4d:
54364eb2 e8a9dfffff call NPSWF32_14_0_0_145!BrokerMainW+0xcfbfb (54362e60)
54364eb7 8b7004 mov esi,dword ptr [eax+4] <--Dereference NULL
Third Example
0:012> uf 5429979aNPSWF32_14_0_0_145!BrokerMainW+0x6535:
5429979a 0fb74108 movzx eax,word ptr [ecx+8]
5429979e 48 dec eax
5429979f 48 dec eax
542997a0 740c je NPSWF32_14_0_0_145!BrokerMainW+0x6549 (542997ae)
NPSWF32_14_0_0_145!BrokerMainW+0x653d:
542997a2 83e815 sub eax,15h
542997a5 7403 je NPSWF32_14_0_0_145!BrokerMainW+0x6545 (542997aa)
NPSWF32_14_0_0_145!BrokerMainW+0x6542:
542997a7 33c0 xor eax,eax <--Set return value to NULL
542997a9 c3 ret <--Return with NULL
NPSWF32_14_0_0_145!BrokerMainW+0x6545:
542997aa 8d4110 lea eax,[ecx+10h]
542997ad c3 ret
NPSWF32_14_0_0_145!BrokerMainW+0x6549:
542997ae 8d410c lea eax,[ecx+0Ch]
542997b1 c3 ret
0:012> u NPSWF32_14_0_0_145+005f3423 L2
NPSWF32_14_0_0_145!BrokerMainW+0x101be:
542a3423 e87263ffff call NPSWF32_14_0_0_145!BrokerMainW+0x6535 (5429979a)
542a3428 8038fe cmp byte ptr [eax],0FEh <--Dereference NULL
You can find a list of 251 potential NULL pointer dereferences in Flash Player here.
July 14, 2014
Issues with Flash Player & Firefox in Non-default Configurations
Few months ago I encountered a bug when a fuzzed flash file is being rendered by Flash Player in Firefox. This bug can be reached only in the non-default configuration described below so very unlikely you are affected by this bug.
To trigger the bug the flash player module has to be loaded into Firefox's virtual address space. And this can be achieved if Flash Player protected mode is disabled and Firefox plugin container process is disabled too.
The bug involves to dereference arbitrary memory address via a CALL instruction in the vtable dispatcher. Here you can see the bug in the exception state.
Implementation limit exceeded: attempting to allocate too-large object
error: out of memory
(170fc.16998): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000001 ebx=00000000 ecx=0034f670 edx=00000000 esi=1600f2c8 edi=0000001c
eip=5996bd5f esp=0034f638 ebp=0034f668 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010202
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\SysWOW64\Macromed\Flash\NPSWF32_14_0_0_145.dll -
NPSWF32_14_0_0_145!unuse_netscape_plugin_Plugin+0x5c2:
5996bd5f 8b461c mov eax,dword ptr [esi+1Ch] ds:002b:1600f2e4=????????
0:000> u eip L10
NPSWF32_14_0_0_145!unuse_netscape_plugin_Plugin+0x5c2:
5996bd5f 8b461c mov eax,dword ptr [esi+1Ch] <--Read unmapped address
5996bd62 a801 test al,1
5996bd64 7420 je NPSWF32_14_0_0_145!unuse_netscape_plugin_Plugin+0x5e9 (5996bd86)
5996bd66 33d2 xor edx,edx
5996bd68 39550c cmp dword ptr [ebp+0Ch],edx
5996bd6b 7519 jne NPSWF32_14_0_0_145!unuse_netscape_plugin_Plugin+0x5e9 (5996bd86)
5996bd6d 8b4e04 mov ecx,dword ptr [esi+4]
5996bd70 83e0fe and eax,0FFFFFFFEh
5996bd73 89461c mov dword ptr [esi+1Ch],eax
5996bd76 8b06 mov eax,dword ptr [esi] <--Read unmapped address
5996bd78 51 push ecx
5996bd79 8bce mov ecx,esi
5996bd7b 895604 mov dword ptr [esi+4],edx
5996bd7e 895618 mov dword ptr [esi+18h],edx
5996bd81 ff500c call dword ptr [eax+0Ch] <--Dereference arbitrary memory content
5996bd84 eb06 jmp NPSWF32_14_0_0_145!unuse_netscape_plugin_Plugin+0x5ef (5996bd8c)
I had reported this bug to Adobe and they opened a case PSIRT-2707 on 14/April/2014 but so far Adobe didn't confirm whether or not it was able to reproduce the bug or the exception state reported.
Again, the bug doesn't affect the default configuration, and so very unlikely you're affected by this. However, users using Firefox with plugin-container disabled as well as Flash Player plugin with protected mode disabled are affected by this issue.
The original report is about Flash Player 13_0_0_182 and Firefox 28.0 but the testcase fails with Flash Player 14_0_0_145 and Firefox 30.0 (latest available till today).
These are the steps to reproduce the bug.
Drop me an email if you think you need the testcase.
To trigger the bug the flash player module has to be loaded into Firefox's virtual address space. And this can be achieved if Flash Player protected mode is disabled and Firefox plugin container process is disabled too.
The bug involves to dereference arbitrary memory address via a CALL instruction in the vtable dispatcher. Here you can see the bug in the exception state.
0:048> gImplementation limit exceeded: attempting to allocate too-large object
error: out of memory
(170fc.16998): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000001 ebx=00000000 ecx=0034f670 edx=00000000 esi=1600f2c8 edi=0000001c
eip=5996bd5f esp=0034f638 ebp=0034f668 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010202
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\SysWOW64\Macromed\Flash\NPSWF32_14_0_0_145.dll -
NPSWF32_14_0_0_145!unuse_netscape_plugin_Plugin+0x5c2:
5996bd5f 8b461c mov eax,dword ptr [esi+1Ch] ds:002b:1600f2e4=????????
0:000> u eip L10
NPSWF32_14_0_0_145!unuse_netscape_plugin_Plugin+0x5c2:
5996bd5f 8b461c mov eax,dword ptr [esi+1Ch] <--Read unmapped address
5996bd62 a801 test al,1
5996bd64 7420 je NPSWF32_14_0_0_145!unuse_netscape_plugin_Plugin+0x5e9 (5996bd86)
5996bd66 33d2 xor edx,edx
5996bd68 39550c cmp dword ptr [ebp+0Ch],edx
5996bd6b 7519 jne NPSWF32_14_0_0_145!unuse_netscape_plugin_Plugin+0x5e9 (5996bd86)
5996bd6d 8b4e04 mov ecx,dword ptr [esi+4]
5996bd70 83e0fe and eax,0FFFFFFFEh
5996bd73 89461c mov dword ptr [esi+1Ch],eax
5996bd76 8b06 mov eax,dword ptr [esi] <--Read unmapped address
5996bd78 51 push ecx
5996bd79 8bce mov ecx,esi
5996bd7b 895604 mov dword ptr [esi+4],edx
5996bd7e 895618 mov dword ptr [esi+18h],edx
5996bd81 ff500c call dword ptr [eax+0Ch] <--Dereference arbitrary memory content
5996bd84 eb06 jmp NPSWF32_14_0_0_145!unuse_netscape_plugin_Plugin+0x5ef (5996bd8c)
I had reported this bug to Adobe and they opened a case PSIRT-2707 on 14/April/2014 but so far Adobe didn't confirm whether or not it was able to reproduce the bug or the exception state reported.
Again, the bug doesn't affect the default configuration, and so very unlikely you're affected by this. However, users using Firefox with plugin-container disabled as well as Flash Player plugin with protected mode disabled are affected by this issue.
The original report is about Flash Player 13_0_0_182 and Firefox 28.0 but the testcase fails with Flash Player 14_0_0_145 and Firefox 30.0 (latest available till today).
These are the steps to reproduce the bug.
- Edit mms.cfg to have ProtectedMode=0 to disable protected mode in Flash Player
- Start cmd.exe and type "set MOZ_DISABLE_OOP_PLUGINS=1" to disable plugin-container in Firefox
- Start Firefox from command prompt opened previously
- Open fuzzed.swf in Firefox (drag n drop should work)
- Attach firefox.exe process to Windbg when you notice that Firefox is hanging
- Exception should occur in few second. If you see the out-of-memory error in the debugger log without exception you may restart the browser and try again.
Drop me an email if you think you need the testcase.
February 19, 2014
Bug in Flash Player when processing PNG format
The Bug
The PNG file consists of a sequence of data structures called chunks. A chunk has aLength field that is a DWORD value. A specially crafted Length field can cause integer overflow in Flash Player leading to read out of the designated buffer. Here is the disassembly code snippet explaining the bug.
015344a0 e8f7feffff call FlashPlayer!WinMainSandboxed+0x1f1122 (0153439c) ;Read CHUNK.Length from attacker controlled buffer
015344a5 8bd8 mov ebx,eax ;CHUNK.Length = 0ffffffd3h
015344a7 6a04 push 4
015344a9 8d45fc lea eax,[ebp-4]
015344ac 50 push eax
015344ad 8bce mov ecx,esi
015344bb e8dcfeffff call FlashPlayer!WinMainSandboxed+0x1f1122 (0153439c)
015344c0 8b4d08 mov ecx,dword ptr [ebp+8]
015344c3 8901 mov dword ptr [ecx],eax
015344c5 8b560c mov edx,dword ptr [esi+0Ch] ;Current Position in buffer = 29h
015344c8 8945fc mov dword ptr [ebp-4],eax
015344cb 8d441a04 lea eax,[edx+ebx+4] ;<-First integer overflow
;TotalValue = Position + CHUNK.Length + 4
;TotalValue = 29h + 0ffffffd3h + 4 = 0
015344cf 3b4610 cmp eax,dword ptr [esi+10h] ;Compare TotalValue (0) to FileSize (3d0h)
015344d2 7351 jae FlashPlayer!WinMainSandboxed+0x1f12ab (01534525) ;Unsigned evaluation. Jump is not taken
015344d4 57 push edi
015344d5 6afc push 0FFFFFFFCh
015344d7 58 pop eax
015344d8 83cfff or edi,0FFFFFFFFh
015344db 3bd8 cmp ebx,eax ;Compare CHUNK.Length (0ffffffd3h) to hardcoded 0FFFFFFFCh
015344dd 7e26 jle FlashPlayer!WinMainSandboxed+0x1f128b (01534505) ;Signed evaluation. Jump is taken.
[...]
01534505 8b4e14 mov ecx,dword ptr [esi+14h] ;Set pointer to Buffer
01534508 03ca add ecx,edx ;Set Current Position in Buffer
0153450a 03cb add ecx,ebx ;<-Second integer overflow
;Increment by CHUNK.Length leading to position out of the buffer backward
0153450c e88bfeffff call FlashPlayer!WinMainSandboxed+0x1f1122 (0153439c)
[...]
0153439c 0fb601 movzx eax,byte ptr [ecx] ;<-Can read out of designated buffer
0153439f 0fb65101 movzx edx,byte ptr [ecx+1] ;<-Can read out of designated buffer
015343a3 c1e008 shl eax,8
015343a6 0bc2 or eax,edx
015343a8 0fb65102 movzx edx,byte ptr [ecx+2] ;<-Can read out of designated buffer
015343ac 0fb64903 movzx ecx,byte ptr [ecx+3] ;<-Can read out of designated buffer
015343b0 c1e008 shl eax,8
015343b3 0bc2 or eax,edx
015343b5 c1e008 shl eax,8
015343b8 0bc1 or eax,ecx
015343ba c3 ret
State in the erroneous code path looks like below. The designated buffer containing the content of PNG file starts at
00e4c810 where the PNG signature is seen. Due to the bug the instruction reads the memory at 4 bytes minus the pointer to the buffer, at 00e4c80c. Note, the instruction doesn't cause access violation because the illegally accessed memory address is mapped.0:000> t
eax=fffffffc ebx=ffffffd3 ecx=00e4c80c edx=00000029 esi=0019e134 edi=ffffffff
eip=0153439c esp=0019dbf4 ebp=0019dc08 iopl=0 nv up ei pl nz na pe cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000207
FlashPlayer!WinMainSandboxed+0x1f1122:
0153439c 0fb601 movzx eax,byte ptr [ecx] ds:002b:00e4c80c=00
0:000> db ecx
00e4c80c 00 00 00 00 89 50 4e 47-0d 0a 1a 0a 00 00 00 0d .....PNG........
00e4c81c 49 48 44 52 00 00 01 2c-00 00 01 2c 08 02 00 00 IHDR...,...,....
00e4c82c 00 f6 1f 19 22 ff ff ff-d3 49 44 41 54 78 9c ed ...."....IDATx..
00e4c83c d9 31 8a c3 40 14 44 c1-1e e3 fb 5f 59 8a 9d 09 .1..@.D...._Y...
00e4c84c 1c bc 40 55 6c b4 20 70-f2 68 98 7f b6 6b bb ce ..@Ul. p.h...k..
00e4c85c ef df b6 f3 e8 9f f3 ad-6f 7d fb e7 b7 9f 01 a9 ........o}......
00e4c86c ef 4e fd 13 e0 dd 44 08-31 11 42 4c 84 10 13 21 .N....D.1.BL...!
00e4c87c c4 bc 8e 42 cc 12 42 4c-84 10 13 21 c4 44 08 31 ...B..BL...!.D.1
Root Cause
Two incorrect sanity checks were identified.Incorrect sanity check (
015344cf) because it happens after the overflow (015344cb).Incorrect sanity check (
015344db) because signed comparison is performed on CHUNK.Length that is unsigned.Severity
The technical severity of this bug is low because diverting execution flow is not possible. Further analysis suggests that address disclosure is not possible because the memory region can be accessed out of the designated buffer doesn't contain address.Reproduction
Open Flash Player 12.0.0.38 (flashplayer_12_sa.exe has a size of 10,339,208) in Windbg. Then execute the following command.0:006> bp flashplayer + 001f44a0 2
0:006> g
Open the PoC in Flash Player (send me an e-mail for a copy). Debugger breaks-in so you can step through the disassembly code and see the data-flow as explained above.
I'm aware there is a new version of Flash Player 12.0.0.44. I verified and it's affected by this bug, too.
UPDATE On 26th February an Adobe engineer confirmed via e-mail that he could reproduce the bug.
February 13, 2014
Data Flow Tracking in Flash Player: Undocumented Bytecodes and JIT
Undocumented Bytecodes
I did some analysis how the bytecodes inDoABC 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
I looked at the specification of
All offsets in this post are RVAs, that is relative to Flash Player's image base.
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
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
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
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.
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
I run Flash Player and saw in the log produced by Pintool that the inline
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
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
It seems defense against this string attack is consciously added by Adobe preventing to read out of bounds.
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.
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.
December 11, 2013
Flash Player Unloading Vulnerability II
UPDATED 20/February 2014: This vulnerability is CVE-2013-5332 and technical details were publicly announced on 10th December 2013 after the vendor patch was released to end users. On 19th of February 2014 I unexpectedly received an e-mail from HackerOne saying "The Internet Bug Bounty has awarded you a $2000.00 bounty for Flash memory corruption vulnerability could lead to code execution".
Adobe has notified me that it addressed the Flash Player Unloading vulnerability I reported them earlier. The patch is now released to end users and the security bulletin is published which contains the nature of the vulnerability.
In this post, I describe the technical details of the vulnerability in the hope that software developers can learn from it.
In the Windows version of Safari, when a Flash file is opened, the browser initiates to load the Flash Player into the process address space. When the Flash file is no longer opened the browser initiates to unload the Flash Player.
The Flash Player can display a dialog box using
This is a use-after-free vulnerability and it is same in nature to the one I reported Adobe earlier however this time the vulnerability is triggered via a different code path. The crash state looks like below, and it suggests the issue is most likely exploitable for code execution.
The vulnerability I reported Adobe earlier is same in nature to this one. Also, if a developer purely adds a new
Also, for Microsoft, hardening on OS level is worthy to consider which may involve to crash in a not exploitable manner when a bug is triggered. The problem looks to be more ubiquitous than the public vulnerability reports suggest. The approach to discover these issues is to identify dialog box and DLL unloading code fragments that can be manually attacked.
Since there may be many bugs that could end up dereferencing unloaded Flash Player, Mozilla long time back fixed the problem by permanently keeping the plugin in the memory in Firefox process.
I'm currently working on tools to identify attack surfaces. It involves to identify DLLs calling
I created a sample implementation to represent the vulnerability including how the freed memory gets dereferenced. It is a good exercise for developers to think about how to make the code secure without removing the thread creation.
When OK is clicked the instruction dereferences freed memory.
Just a note that the control transfer instruction to dereference freed memory is not
Adobe has notified me that it addressed the Flash Player Unloading vulnerability I reported them earlier. The patch is now released to end users and the security bulletin is published which contains the nature of the vulnerability.
In this post, I describe the technical details of the vulnerability in the hope that software developers can learn from it.
In the Windows version of Safari, when a Flash file is opened, the browser initiates to load the Flash Player into the process address space. When the Flash file is no longer opened the browser initiates to unload the Flash Player.
The Flash Player can display a dialog box using
MessageBox API. While the dialog box is active, an other thread can unload the Flash Player module from the address space. When the execution returns back from the MessageBox call to the Flash Player module, which is already unloaded, the instruction dereferences freed memory causing data execution prevention exception.This is a use-after-free vulnerability and it is same in nature to the one I reported Adobe earlier however this time the vulnerability is triggered via a different code path. The crash state looks like below, and it suggests the issue is most likely exploitable for code execution.
(3860.37ec): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=523bb781 ebx=00000001 ecx=006f0d68 edx=00000000 esi=523bb781 edi=00000000
eip=523bb781 esp=001deb90 ebp=001debb8 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00210206
<Unloaded_NPSWF32_11_7_700_224.dll>+0x20b781:
523bb781 ?? ???
0:000> |.
. 0 id: 3860 attach name: C:\Program Files (x86)\Safari\Apple Application Support\WebKit2WebProcess.exe
One possible fix would be to synchronize the DLL unloading thread with the code calling MessageBox.The vulnerability I reported Adobe earlier is same in nature to this one. Also, if a developer purely adds a new
MessageBox call he has a high probability to inherently create a new vulnerability that can be reached in the same way described in this post. Therefore, for Adobe, it would be beneficial to review the entire code base for unsafe dialog box calls.Also, for Microsoft, hardening on OS level is worthy to consider which may involve to crash in a not exploitable manner when a bug is triggered. The problem looks to be more ubiquitous than the public vulnerability reports suggest. The approach to discover these issues is to identify dialog box and DLL unloading code fragments that can be manually attacked.
Since there may be many bugs that could end up dereferencing unloaded Flash Player, Mozilla long time back fixed the problem by permanently keeping the plugin in the memory in Firefox process.
I'm currently working on tools to identify attack surfaces. It involves to identify DLLs calling
MessageBox, and identify ways to unload MessageBox DLLs from the process address space.I created a sample implementation to represent the vulnerability including how the freed memory gets dereferenced. It is a good exercise for developers to think about how to make the code secure without removing the thread creation.
// This is the EXE file.
// Main thread loads the DLL file to call ShowMessageBox() export that calls MessageBox().
// Secondary thread frees DLL but the dialog box is still visible.
// When OK is clicked the freed memory is dereferenced.
#include <Windows.h>
static HMODULE handle;
DWORD WINAPI Thread(LPVOID lpParam)
{
printf("[Thread] Waiting 5 seconds.\n");
Sleep(5000);
FreeLibrary(handle);
printf("[Thread] FreeLibrary() called. Click OK to dereference freed memory.\n");
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
typedef void (WINAPI *FUNC)(void);
FUNC ShowMessageBox;
handle = LoadLibrary(L"DialogDLL.dll");
printf("LoadLibrary() called.\n");
ShowMessageBox = (FUNC)GetProcAddress(handle, "ShowMessageBox");
CreateThread(NULL, 0, Thread, NULL, NULL, NULL);
printf("Thread created for FreeLibrary().\n");
printf("MessageBox pops up.\n");
ShowMessageBox();
return 0;
}
// This is the DLL file.
// It has an export that calls MessageBox()
extern "C" __declspec( dllexport ) void ShowMessageBox();
void ShowMessageBox()
{
MessageBox(NULL, L"...shown by the DLL that can be unloaded while this dialog box is still visible.\n\nThe unloaded DLL
can be dereferenced when OK is clicked.", L"This is a dialog box...", MB_OK);
}
The complete source code for Visual C++ 2010 can be downloaded from here. When executing the program it looks like below.
When OK is clicked the instruction dereferences freed memory.

call that can be seen in v-table bugs but ret.
March 13, 2013
Flash Player Unloading Vulnerability
Opera unloads Flash Player after two minutes of not being used. Flash Player can create dialog that can run even when the player itself is unloaded. When it's unloaded, the running dialog makes a call back to the unloaded module, in a time window.
If an attacker can exploit the time window between the unload and the dereference, it's possible to redirect the execution flow.
While experimenting, I used heap spray to inject
When investigated this vulnerability, I wanted evidence to the question: what module unloads the Flash Player? I used Windbg to place breakpoint at unload events. I let the application to trigger the unload events, and when the debugger hit the breakpoint, printed the call stack.
I needed the answer for the question also: what module created the thread that calls back to the unloaded module? Here are the series of Windbg commands used to get the answer.
And here is some interesting observation.
When started to look into triggering a dialog in Flash Player I created the following ActionScript that executes an infinite loop.
It got me thinking if Adobe fixed security problem either silently or "accidentally". When I checked the release notes of the latest version I didn't see indication of this kind of fix. I still don't know what had happened between the two releases but thought to investigate this issue further. I tried to trigger the bug via different code paths. I looked at my Flash file collection to dig out a file that triggers a dialog. And here it is, with the one I found, I could crash the player with the same call stack as before.
Initially, I thought Opera could fix this issue by leaving the module permanent in the address space, so I reported this to Opera. However, they notified Adobe after confirming it's not the problem in Opera (though they considered it as a stability issue). Adobe received the report at the end of November, 2012. The bug is now fixed in the security update that has a number of APSB13-09 at 12 March, 2013.
The preliminary version of this blog post was reviewed by Adobe. The preliminary version is same to the published version apart from some changes in the wording.
If an attacker can exploit the time window between the unload and the dereference, it's possible to redirect the execution flow.
While experimenting, I used heap spray to inject
0xCC bytes to the deleted memory. I succeeded once of many attempts and this suggests it's practically possible to create an exploit that could inject malicious code within the time window.When investigated this vulnerability, I wanted evidence to the question: what module unloads the Flash Player? I used Windbg to place breakpoint at unload events. I let the application to trigger the unload events, and when the debugger hit the breakpoint, printed the call stack.
0:014> sxe udI saw the Flash Player was freed by Opera indeed.
0:014> g
Unload module C:\Windows\SysWOW64\Macromed\Flash\NPSWF32_11_4_402_287.dll at 54760000
eax=00000000 ebx=035f5584 ecx=00000000 edx=00000000 esi=035f5bc8 edi=00000000
eip=77b1fc72 esp=0037dab0 ebp=0037db30 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00200246
ntdll!ZwUnmapViewOfSection+0x12:
77b1fc72 83c404 add esp,4
0:000> kc
ntdll!ZwUnmapViewOfSection
ntdll!LdrpUnloadDll
ntdll!LdrUnloadDll
KERNELBASE!FreeLibrary
WARNING: Stack unwind information not available. Following frames may be wrong.
Opera_534b0000!OpSetSpawnPath
Opera_534b0000!OpWaitFileWasPresent
I needed the answer for the question also: what module created the thread that calls back to the unloaded module? Here are the series of Windbg commands used to get the answer.
sxn etI saw that thread
sxn ud
bp CreateRemoteThreadEx "kc; gu; !handle eax 8; gc"
g
KERNELBASE!CreateRemoteThreadEx
kernel32!CreateThreadStub
WARNING: Stack unwind information not available. Following frames may be wrong.
NPSWF32_11_4_402_287!native_ShockwaveFlash_TCallLabel
Opera_534b0000!OpGetNextUninstallFile
Opera_534b0000!OpGetNextUninstallFile
NPSWF32_11_4_402_287!NP_Shutdown
NPSWF32_11_4_402_287
NPSWF32_11_4_402_287!DllUnregisterServer
Opera_534b0000!OpWaitFileWasPresent
ntdll!TppPoolReserveTaskPost
ntdll!TppTimerpSet
Opera_534b0000!OpGetNextUninstallFile
Opera_534b0000!OpSetLaunchMan
Opera_534b0000!OpSetLaunchMan
Handle a20
Object Specific Information
Thread Id 88ac.1700
Priority 10
Base Priority 0
Start Address 5497083d NPSWF32_11_4_402_287!native_ShockwaveFlash_TCallLabel
ModLoad: 6bda0000 6bdd0000 C:\Windows\SysWOW64\wdmaud.drv
ModLoad: 72cb0000 72cb4000 C:\Windows\SysWOW64\ksuser.dll
ModLoad: 6d9e0000 6d9e7000 C:\Windows\SysWOW64\AVRT.dll
ModLoad: 6cad0000 6cad8000 C:\Windows\SysWOW64\msacm32.drv
ModLoad: 6bd80000 6bd94000 C:\Windows\SysWOW64\MSACM32.dll
ModLoad: 6bd70000 6bd77000 C:\Windows\SysWOW64\midimap.dll
Exit thread 6:3f90, code 0
Exit thread 7:4074, code 0
Unload module C:\Windows\SysWOW64\Macromed\Flash\NPSWF32_11_4_402_287.dll at 54760000
Unload module C:\Windows\system32\WINSPOOL.DRV at 736f0000
(88ac.1700): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000102 ebx=00000000 ecx=75a914d0 edx=00000000 esi=11c8d000 edi=11c8d470
eip=549706c0 esp=0aacfd38 ebp=0aacfd80 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
<Unloaded_NPSWF32_11_4_402_287.dll>+0x2106c0:
549706c0 ?? ???
88ac.1700 is created by the Flash Player. When the player is unloaded the thread is still running. Finally, the thread calls back to the unloaded module. Therefore, I knew Flash Player created the thread that calls back to its own module that has been unloaded.And here is some interesting observation.
When started to look into triggering a dialog in Flash Player I created the following ActionScript that executes an infinite loop.
class InfiniteLoop {I built the Flash file with the command below.
static function main() {
for (var i = 0; i < 1;) {}
}
}
mtasc.exe -swf InfiniteLoop.swf -main -header 125:125:20 InfiniteLoop.asThe Flash file triggers a slow script warning dialog. I was able to unload and to crash the Flash Player while the dialog was still running. I achieved this with version 11.4.402.278. When reported the problem to Opera they couldn't reproduce it. That time there was a Flash Player update, and I found it out that they used the latest version of Flash Player that was 11.4.402.287. With the latest version, I couldn't reproduce the problem either.
It got me thinking if Adobe fixed security problem either silently or "accidentally". When I checked the release notes of the latest version I didn't see indication of this kind of fix. I still don't know what had happened between the two releases but thought to investigate this issue further. I tried to trigger the bug via different code paths. I looked at my Flash file collection to dig out a file that triggers a dialog. And here it is, with the one I found, I could crash the player with the same call stack as before.
Initially, I thought Opera could fix this issue by leaving the module permanent in the address space, so I reported this to Opera. However, they notified Adobe after confirming it's not the problem in Opera (though they considered it as a stability issue). Adobe received the report at the end of November, 2012. The bug is now fixed in the security update that has a number of APSB13-09 at 12 March, 2013.
The preliminary version of this blog post was reviewed by Adobe. The preliminary version is same to the published version apart from some changes in the wording.
October 8, 2012
Flash Player Enables Sandbox via Global Pointer
The Windows version of Adobe Flash Player in Firefox has protected mode functionality. The concept of this mode is similar to the sandbox concept in Chrome: there is a broker process and a renderer process. The renderer process is running in low-integrity mode, and communicating with the broker process. The broker process is to give permission for legitimate system change but to reject questionable request made by the renderer process. The basic idea is the flash file is loaded and executed by the renderer process so, any non-legitimate invocation occurs by a vulnerability it will be rejected by the broker process.
Possible ways to circumvent the protection provided by protected mode include the followings. Corrupt the borkerer process to accept non-legitimate request from the renderer process. Or find Windows vulnerability to escalate right in low-integrity (i.e. renderer) process. Since the previous implementation when we didn't have the protected mode functionality is still available in the Flash Player it sounds to be logical by the attacker to disable protected mode functionality so the flash file is loaded and executed without sandbox protection. I'm exploring the latter further.
I examined
The value via the global pointer set to 1 by default (sandbox enabled) but it can be overwritten by adding
Both the value and the page of the global pointer have the memory protection flags of read and write and since the global pointer is at a fixed address it's possible to overwrite it without changing memory protection flags or guessing the address.
Even though there is a need for a vulnerability to overwrite the global pointer table from security point of view it would be logical to discard the fixed address method and the writable memory protection flag. Using random address with read only page (apply writable flag when it's needed) would be more appropriate.
Here come some research artifacts.
Hijacking global pointer in Windbg. Higlighted dword is our new protected mode flag that is disabled.
Possible ways to circumvent the protection provided by protected mode include the followings. Corrupt the borkerer process to accept non-legitimate request from the renderer process. Or find Windows vulnerability to escalate right in low-integrity (i.e. renderer) process. Since the previous implementation when we didn't have the protected mode functionality is still available in the Flash Player it sounds to be logical by the attacker to disable protected mode functionality so the flash file is loaded and executed without sandbox protection. I'm exploring the latter further.
I examined
NPSWF32_11_4_402_278.dll (11,264,432 bytes) file that is used in Firefox. In my test environment the DLL was located in C:\Windows\SysWOW64\Macromed\Flash folder. This file has the logic to decide if the flash file should be loaded and executed with or without sandbox protection. Flash Player uses a global pointer variable at fixed address (RVA: 0a2be70h) to store if sandbox mode should be used (1/0: with/without sandbox).The value via the global pointer set to 1 by default (sandbox enabled) but it can be overwritten by adding
ProtectedMode = 0 line to mms.cfg file that is located in the folder mentioned above.Both the value and the page of the global pointer have the memory protection flags of read and write and since the global pointer is at a fixed address it's possible to overwrite it without changing memory protection flags or guessing the address.
Even though there is a need for a vulnerability to overwrite the global pointer table from security point of view it would be logical to discard the fixed address method and the writable memory protection flag. Using random address with read only page (apply writable flag when it's needed) would be more appropriate.
Here come some research artifacts.
Hijacking global pointer in Windbg. Higlighted dword is our new protected mode flag that is disabled.
0:000> sxe ld:NPSWF32_11_4_402_278Setting up protected mode flag below.
0:000> g
ModLoad: 59fe0000 5abbb000 C:\Windows\SysWOW64\Macromed\Flash\NPSWF32_11_4_402_278.dll
eax=00000000 ebx=00000000 ecx=00000000 edx=00000000 esi=fffdd000 edi=0059bfcc
eip=7784fc42 esp=0059bea0 ebp=0059bef4 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
ntdll!NtMapViewOfSection+0x12:
7784fc42 83c404 add esp,4
0:000> db 59fe0000 +a2be70
5aa0be70 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
5aa0be80 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
5aa0be90 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
5aa0bea0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
5aa0beb0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
5aa0bec0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
5aa0bed0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
5aa0bee0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0:000> .dvalloc 1000
Allocated 1000 bytes starting at 00730000
0:000> db 00730000
00730000 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
00730010 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
00730020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
00730030 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
00730040 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
00730050 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
00730060 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
00730070 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0:000> ed 59fe0000 +a2be70 00730000
0:000> g
56245e56 807dff00 cmp byte ptr [ebp-1],0Checking if protected mode flag is set below.
56245e5a 7406 je NPSWF32_11_4_402_278!NP_SetNPAPIHostProxy+0x168c (56245e62)
56245e5c 8b45f8 mov eax,dword ptr [ebp-8]
56245e5f c60001 mov byte ptr [eax],1
56245e62 8bcb mov ecx,ebx
56245e6f 8b75f8 mov esi,dword ptr [ebp-8]Highlighted code path of initialization with protected mode disabled below.
56245e72 59 pop ecx
56245e73 803e00 cmp byte ptr [esi],0
56245e76 0f8411010000 je NPSWF32_11_4_402_278!NP_SetNPAPIHostProxy+0x17b7 (56245f8d) [br=1]
562460b0 e8dffeffff call NPSWF32_11_4_402_278!NP_SetNPAPIHostProxy+0x17be (56245f94)I'd like to make it clear this is not a software vulnerability.
562460b5 84c0 test al,al
562460b7 7414 je NPSWF32_11_4_402_278!NP_Initialize+0x57 (562460cd) [br=1]
562460b9 56 push esi
562460ba e83bf4ffff call NPSWF32_11_4_402_278!NP_SetNPAPIHostProxy+0xd24 (562454fa)
562460bf 59 pop ecx
562460c0 84c0 test al,al
562460c2 7404 je NPSWF32_11_4_402_278!NP_Initialize+0x52 (562460c8)
562460c4 33c0 xor eax,eax
562460c6 eb0a jmp NPSWF32_11_4_402_278!NP_Initialize+0x5c (562460d2)
562460c8 33c0 xor eax,eax
562460ca 40 inc eax
562460cb eb05 jmp NPSWF32_11_4_402_278!NP_Initialize+0x5c (562460d2)
562460cd e83595ffff call NPSWF32_11_4_402_278!unuse_netscape_plugin_Plugin+0x11de9 (5623f607)
562460d2 5e pop esi
562460d3 c20400 ret 4
September 2, 2012
Timeline for Fix of an Arbitrary Address Write Bug
In today's post I'm writing about an arbitrary address write bug in Flash Player in Firefox (CVE-2012-4171) that is now fixed.
The issue was reported to Mozilla, but the fix made by Adobe as it turned out it was a bug in the Flash Player. The bug was tracked in Mozilla's bug tracking system (BugZilla) here [still restricted at the time of writing].
To trigger this vulnerability there is no requirement to use malformed data in any way. All the constructs can be legitimate. The PoC demonstrates when the security dialog box is shown it is possible to navigate to an other page that pops up another security dialog while the first dialog is still visible. When the second dialog is OK'd Flash Player crashes.
Below code snippet demonstrates the vulnerable code path.
Below is the timeline for the fix.
Thanks for those who involved from Mozilla, Adobe and CERT.
The issue was reported to Mozilla, but the fix made by Adobe as it turned out it was a bug in the Flash Player. The bug was tracked in Mozilla's bug tracking system (BugZilla) here [still restricted at the time of writing].
To trigger this vulnerability there is no requirement to use malformed data in any way. All the constructs can be legitimate. The PoC demonstrates when the security dialog box is shown it is possible to navigate to an other page that pops up another security dialog while the first dialog is still visible. When the second dialog is OK'd Flash Player crashes.
Below code snippet demonstrates the vulnerable code path.
mov ecx,dword ptr [esi+4] *(1)At line (1)
<STRIPPED>
mov esi,ecx
add dword ptr [esi+1B8h],0FFFFFFFFh *(2)
[ESI+4] is an address in a valid heap region. The heap can be arranged to contain user controlled data. Therefore, at line (2) an attacker can write arbitrary address using add instruction. Due to depending on add instruction the attacker has limited control what data to write.Below is the timeline for the fix.
This timeline contains the technically important communications. If you are aware of that I missed something that you think is important to mention, please let me know and I'll update this page.
Days Date Channel Action 0 days 25-Jan-2010 Report sent to Mozilla. 0 days 25-Jan-2010 Mozilla confirms the behavior described in the report. A case opened in the bug tracking database (BugZilla). 731 days 26-Jan-2012 BugZilla A Mozilla engineer says he can reproduce the issue with Firefox 9 on Windows 7 but cannot reproduce with nightly build. 731 days 26-Jan-2012 BugZilla An Adobe engineer says they will triage this issue ASAP. 749 days 13-Feb-2012 BugZilla A Mozilla engineer asks for status update from Adobe. 749 days 13-Feb-2012 BugZilla An Adobe engineer confirms he cannot reproduce the crash. 749 days 13-Feb-2012 BugZilla An Adobe engineer confirms he can reproduce the crash by experimenting with waiting times before clicking "OK" on the prompt. 749 days 13-Feb-2012 BugZilla Reporter recommends to switch off plugin-container introduced since the report to get consistent crash state. 779 days 14-March-2012 Reporter asks for status update, and points out the existing testcase reliably crashes Firefox when plugin-container disabled. 779 days 14-March-2012 Mozilla confirm there is no other update on the case, than seen in BugZilla. Mozilla asks to put additional information about crashes. 780 days 15-March-2012 BugZilla Reporter adds additional information about crashes. 780 days 15-March-2012 Reporter asks for an estimation of the date of the fix. 780 days 15-March-2012 Mozilla confirm they don't have an estimation. They say to have to see what the developers can do with it in the short term. 780 days 15-March-2012 In response to an earlier email Mozilla say "flash bugs are often slow to be fixed". 805 days 9-Apr-2012 Reporter decided to share crash information with CERT, and asked if they can help motivating the vendor to issue a patch. 805 days 9-Apr-2012 CERT confirm they have spoken with the vendor. 806 days 10-Apr-2012 BugZilla Mozilla say they effectively mitigated this issue with out of process plugins and they require a testcase which crashes Firefox in an exploitable manner. 806 days 10-Apr-2012 BugZilla Reporter responses that existing testcase crashes Firefox in 1/10 ratio on reporter side. With plugin-container disabled it crashes Firefox in 10/10 ratio. 807 days 11-Apr-2012 BugZilla An Adobe engineer confirms they cannot reproduce the issue. 808 days 12-Apr-2012 BugZilla Reporter recommends to disable plugin-container to get a consistent crash state. Reporter also highlights plugin container is just a mitigation that could be bypassed. 808 days 12-Apr-2012 BugZilla A Mozilla Security Researcher asks how the plugin-container could be bypassed. 808 days 12-Apr-2012 BugZilla Reporter highlights attack surfaces but he also states discussing how to bypass mitigation is out of the scope of this bug. 814 days 18-Apr-2012 BugZilla Adobe say they have a good set of test cases for this issue now, and this will be fixed in the following release. 861 days 4-June-2012 BugZilla Adobe confirm it is fixed in 11.4.400.128. [This seems to be an internal build] 939 days 21-Aug-2012 Web Fix released in 11.4.402.265. To see Adobe's Security Bulletin click here. N/A 27-Aug-2012 BugZilla Adobe confirm 11.4.402.265 is released on 21st of August and mark the bug as fixed. N/A 29-Aug-2012 Reporter checks Adobe's Security Bulletin and realizes this bug is not mentioned in it. Asks Adobe regarding CVE number. N/A 30-Aug-2012 Adobe confirm the Security Bulletin has been updated with the CVE number.
Thanks for those who involved from Mozilla, Adobe and CERT.