The blog continues at suszter.com/ReversingOnWindows

Showing posts with label Use-After-Free. Show all posts
Showing posts with label Use-After-Free. Show all posts

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.

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 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.
Just a note that the control transfer instruction to dereference freed memory is not call that can be seen in v-table bugs but ret.

April 15, 2013

Tracing Thread ID of ModLoad and ModFree Events

This log was created by an experimental Windbg extension that is to trace the thread ID of ModLoad/ModFree events. When a module is being unloaded the extension queries the ID of the current thread and compares to the thread ID that loaded the module. If two different threads used to load and to unload the module the extension issues a notification as seen in yellow below.
ModLoad 59440000 00000454          PRNFLDR
ModFree 59440000 00000454 00000454 PRNFLDR
ModLoad 59440000 00000454          prnfldr
ModLoad 74b90000 00000454          WINSPOOL
ModLoad 5aa30000 00000454          prncache
ModLoad 74950000 00000454          RpcRtRemote
ModLoad 673a0000 00000454          actxprxy
ModLoad 6b180000 00000454          ieproxy
ModLoad 5a9f0000 00000454          thumbcache
ModLoad 5fcc0000 00000454          ieframe
ModLoad 75800000 00000454          api-ms-win-downlevel-ole32-l1-1-0
ModLoad 74490000 00000454          api-ms-win-downlevel-shlwapi-l2-1-0
ModLoad 74470000 00000454          api-ms-win-downlevel-advapi32-l2-1-0
ModLoad 6b250000 00000454          api-ms-win-downlevel-shell32-l1-1-0
ModFree 5aa30000 0000055c 00000454 prncache
-->prncache (5aa30000) is allocated by thread id 454 but freed by 55c
ModLoad 55250000 00000454          NPSWF32_11_7_700_169
ModLoad 771d0000 00000454          urlmon
ModLoad 6c310000 00000454          DSOUND
ModLoad 744a0000 00000454          POWRPROF
ModLoad 735a0000 00000454          mlang
I observed that normally the same thread is responsible to load and to unload the module. However, that's not always the case. If you can force a context switch on the code path of dereference, and to get the unloading thread to trigger ModFree, you could end up to dereference freed memory.

August 20, 2012

Research notes of finding Stale Pointer bugs

Keywords: use-after-free, dangling pointer, stale pointer, invalid pointer dereference, double free, deleted object

In 2009 Mozilla fixed one of the vulnerability (CVE-2009-2467) I reported them. It had allowed to reference freed object leading to code execution. Some time after this in 2010 I got interested researching this class of security bugs. I pursued dynamic approach to discover them but I wanted different approach than feeding the application with fuzzed data. It was also a requirement to discover these problems in binaries without having source code or debug information available.

I thought it would be nice to make it visible if a pointer is dangling. I knew detecting the pointer that is dangling could come with lots of false positives because some of them cannot be referenced from the execution flow.

Anyway, I came up with the following train of thought. malloc() is used to allocate a region of memory on the heap. The pointer referencing to the region of memory can be on the stack or on another region of the heap. So we need to handle the situation in a different way if a pointer is a dangling pointer on the stack or on the heap.

I kept working on this approach and thought we need to maintain a structure what region of memory was allocated and freed. I thought when free() is called we could check if there is a reference to the freed memory. Here is a skeleton of the approach I draw back in 2010 - it's unprofessional and not so important so you might wanna continue reading instead... :)

The solution above wouldn't have worked in practice however. The conceptual problem here is if there is a reference to a freed object it doesn't mean the code would use the pointer is reachable. When a region of memory is freed the reference might exist to the freed object even if you explicitly set it to NULL. This is because the compiler optimizes this out if it cannot be reached. Another conceptual problem is the original idea itself that is we depend on the check for the references only when free() is called.

I had discussed this idea to people how could this be improved but concluded none of the solutions would be practically applicable. Possible improvements involve timing, and applied static analysis. Static analysis in dynamic approach might be an area to explore further but this would require significant research effort and showed only a little benefit that time.

The low-level constructs are complex so I knew we could detect something that indicates the presence of dangling pointer because in a complex environment it's so big the playground. I suspended working on this for a long time, however, with the fact in my mind that I have a solution that show the sign of working. It was just not optimal enough to use it in practice.

Couple of weeks ago I started working on a debugger extension to place data breakpoint on arbitrary size of the memory. I had a huge success and already built two functionalities on it - both of them detect possible security problems. Thought why not give it a try to explore the old dangling pointer project further involving this new approach.

From the previous posts, you might know that it's possible to track data access, and to determine the kind of the access that is either read or write access. By applying hook on malloc() and on free() we can maintain a list of allocated and freed memory blocks. When there is a read data access to a pointer to freed memory we can issue a notification: pointer to freed memory has been read.

Here is an isolated example code that reads pointer to freed memory.
int *read_freed_ptr(void)
{
    int *ptr = (int *)malloc(sizeof(int));

    free(ptr);

    // read pointer to freed memory
    return ptr;
}
When a freed pointer is read it might not cause a crash later on the execution but definitely could do if the pointer is dereferenced. It is possible, for example, a lot of fuzzing cases cause the application to read freed pointer but the bugs remain undetected because they are not dereferenced. I'm particularly interested researching this approach further on JIT emitted code.

Anyway, here is the assembly code for the above C code. I highlighted the area when the pointer to the freed memory is read.
00401000 55                   push        ebp  
00401001 8B EC                mov         ebp,esp  
00401003 51                   push        ecx  
00401004 6A 04                push        4  
00401006 FF 15 A4 20 40 00    call        dword ptr [__imp__malloc (4020A4h)]  
0040100C 83 C4 04             add         esp,4  
0040100F 89 45 FC             mov         dword ptr [ptr],eax  
00401012 8B 45 FC             mov         eax,dword ptr [ptr]  
00401015 50                   push        eax  
00401016 FF 15 9C 20 40 00    call        dword ptr [__imp__free (40209Ch)]  
0040101C 83 C4 04             add         esp,4  
0040101F 8B 45 FC             mov         eax,dword ptr [ptr]  
00401022 8B E5                mov         esp,ebp  
00401024 5D                   pop         ebp  
00401025 C3                   ret
Detecting read of pointer to freed memory is possible and straightforward task to do prototype implementation.

--Attila Suszter (@reon_wi)
  This blog is written and maintained by Attila Suszter. Read in Feed Reader.