Buffer Overflow in CFF Explorer

First off I love CFF Explorer, its a solid Windows PE viewer I use extensively when researching malware. Naturally when you use a program extensively you may discover a bug or two. I found a buffer overflow vulnerability in the MultiByteToWideChar call that this app makes. I found it has already has been patched (a while ago) after I was 2 days into my development (another reason to always use the latest version of things, dont waste your exploit dev time). Since this probably isnt going anywhere, im cashing in this work as a blog post to help people who want to learn exploit development or even just understanding low level Windows.

A while back, I found odd behavior when opening a dumped exe from memory with invalid Import Tables. I noticed a crash happen in the app, which I made a mental note of to go back to and investigate once I had more time (next month). Next month happens, and I’m terribly disorganized and no longer have the binary that caused it so I thought this would also be a good opportunity to write a fuzzer to reproduce the error. I already had an idea of what causes the crash: strange import table. So I tailored my fuzzer to that, making it what they call a “Smart Fuzzer”.

Planning out the fuzzer code I first just develop a way to start CFF Explorer with an argument to an exe to load. This was harder than I thought… Looking at the shell registry I can see how it normally loads exes/dlls when you right click on and load:

reg

but NO! its not that simple. CFF Explorer uses 8.3 filenames and my file had a space in the path (https://en.wikipedia.org/wiki/8.3_filename), so once I corrected that I stopped banging my head against the wall. So now lets code the first few lines of the fuzzer:

createProc.png

Im creating a process of CFF Explorer with command line argument to start a binary in my User folder, doesnt matter what binary right now because we will later be modifying it to make new input.

To make the fuzzer fast we cant be creating proccess/terminating process everytime we want to give new input, so we need to reverse engineer the CFF Explorer application to create some sort of binding for fuzzing input. Lets see how binaries are loaded by CFF Explorer:

virtalloc.png

Here is after it opens the exe file as an argument…Its basically just allocates space (creating a new memory segment) and writing the bytes of the exe to it by passing the allocated space to ReadFile. The take away here for creating a fuzzer binding is: creating a new memory segment. This is good to know because now we have some sort of thing to look for in CFF Explorer’s memory and then modify since this is essentially the application’s input.

I use VirtualQueryEx to enumerate memory segments of CFF Explorer and return the spot that the exe is located in memory. I can know where this is by seeing what memory segment starts with “MZ” and is marked “RW” not “E” (meaning a PE file in a non-executable segment).

 

I now have to get a window handle of CFF explorer so I use EnumWindows to find the main window. This is necessary because after Reverse Engineering CFF Explorer, it turns out that the “import analysis” code (which is what I suspect crashes) is only ran if the user “clicks” on the module name in the GUI. Understandable..

importclick.png

This means if I change the loaded file while its running, I will need to trigger this “import analysis” code in the application every time I change something. I originally looked at getting a “raw” binding to “import analysis” function and call it directly. I avoided this for 2 reasons:

  1. I would have had to really understand and hunt for all the object pointers and fluff to correctly pass to the function and perfectly execute it (extremely increasing potential bugs caused by me)
  2. Contrary to what developers typically strive for..fuzzing is often (not always) better automating at higher levels (in this case, going through the Windows GUI). When you work to bypass too much fluff, you miss out on exploitable fluff.

So I simply need to find a way to get Windows Messages sent to this window to emulate the “click” or “select” of the module name in order to get the “import analysis” code to run

 

I do this by enumerating windows and finding “CFF Explorer.exe” that I started.enumwindow

I then enumerate its child windows to get a Window handle on the “Import Table” window (which is the viewport in the application that shows the module names you click on).

enumchild.png

 

So we now have a handle to this child window. This will allow us to send Windows Messages to it and make it think a user is clicking or selecting the module names. (Windows Messages is how the OS tells a window that input is happening to it. We will spoof this).

win32.png

We are sending “down arrow” commands to the child window, making it select each module in the grid layout one by one (triggering the “import analysis” code of CFF Explorer for each module name selected).

Now we have the ability to get the memory segment of the exe that CFF Explorer loads in memory and the ability to trigger “import analysis” calls on in an automated quick fashion. Now we need to FUZZ.

We read the bytes in CFF Explorer’s memory segment of the loaded exe file using ReadProcessMemory at the address we obtained using our VirtualProtect search.We read the entire sement which means we now have the same exact file CFF Explorer is looking at. Being that our area of interest is “Import Tables”, I just randomize the newly read buffer’s (exe) import tables.

fuzz

I randomize each  IMAGE_IMPORT_DESCRIPTOR objects in the buffer I read and then write it back to CFF Explorer’s memory that holds the exe its analyzing at.

This code is looped with the windows message spoofing so its constantly analyzing my new input I write to its process memory.

..Thats it. Just run it and see what we catch.

….an hour passed we got something: an app crash

crash.png

This is where we reverse engineer the bug we found to see what it is..

int3.png

An actual buffer overflow. We have the “crashable file” saved off by the fuzzer. Lets load it and see what went wrong….ok we see what went wrong and it was the “Name” field of the image_import_descriptor (which points to a function name). CFF Explorer is using MultiByteToWideChar on this Name field, but if the Name field is too large, the buffer passed to the function cant support the size. The name was too long because I generated bad address bytes that pointed the “Name” field to another part in the exe that was not null terminated (soon enough). This causes a buffer overflow when processed. Lets intentionally cause it now.

AAAA.png

Load the file, crash, debug:

AAoverflow.png

This is looking good. All we need to do is the classic “overwrite EIP” which is on the stack below (technically above) all my 41414141. Unfortunately we encounter:

canary.png

Looking at this, I can tell this is a “stack canary” aka “stack cookie” aka “/GS”.

Brief explaination: Stack canaries are used when programs compile with stack canaries. The compiler will modify all functions that do “buffer modifications” to have integrity checks before and after the function executes. The before part XORs the stack pointer with a value on the stack and after the function the value is compared with the original calculated result. It essentially does a stack integrity check that will be flagged if we overwrite it (at [rsp+360]) This is a problem for us because to overwrite EIP on the stack we need to get to [rsp+370]. The following will just throw ideas at getting past canaries:

  1. Check entropy of the stack canary. If the value that XORs rsp is predictable, then we can possibly overwrite [rsp+360] with the correct canary.. Lets log the entropy with some C code… We do this by finding where the cookie is calculated. I debugged the binary and found the global variable thats initialized with the calculated cookie (near program start). I just need to be able to read this location from memory each time I create/kill the CFF Explorer process so see if there is weak entropy on each time its calculated.

.cookies Good enough amount of entropy. While the first 2 bytes look predictable, the rest are not. However, they do have somewhat of a pattern (getting larger). Its out of scope to even look further into this. After seeing how the cookies are calculated they are using GetTickCount/etc as part of the calculation. Something I cant predict at runtime.

 

2. Corrupt things BEFORE [rsp+360]. Stack canaries ONLY protect memory corruption after the cookie. It doesnt know if you corrupt things before, and with 360 bytes of stack space, thats a lot of local variables I can modify and overwrite. While we are at the end of the function (meaning local variables are about to be discarded) corruption could still occur. I have seen function stacks created that do not initialize their local variables, meaning they will just use what ever is on the stack created at the time. If we can modify these bytes, its possible a following function would allocate stack space and use our buffer data that has since been uninitialized, resulting in unexpected behavior. Or it is possible that I can modify memory that will be passed back to the caller (either by reference or value).

I can quickly check #2 possibility by making my buffer of ‘A’ just short of [rsp+360]. This means we will have overwrote the stack, but not the canary. Meaning IF anything we overwrote is used, we will possibly know if it crashes again….do it….run it…..no crash 🙁

I have heard of alternate results such as overwriting the SEH. If this is possible, then when the stack cookie violation occurs, it will look for a user defined exception to handle the exception, if you’re able to register one before you trigger the overflow you can make execution return to where ever you define your handler (sounds more like a CTF challenge).

 

At face value perhaps what this is is not RCE. You can develop the flaw in other ways. Such as a way to hide an executable’s import table from analysis. Or even DOS CFF Explorer from being able to be used on your binary. This is a good example to be cautious even when opening non-executable files on your host machine. You never know whats possible.

Leave a Reply

Your email address will not be published. Required fields are marked *