piątek, 29 listopada 2019

From 0 to 0day - quick fuzzing lesson

In most time the question(s) you're asking me via blog or twitter is: "how to prepare a fuzzing lab" or "how to perform an analysis of the crash we found". I decided to spent last few days for preparing a small example for you to give you the answer(s) for both of the questions. Below you will find the details. Here we go...
We will start here:

As you can see I started the fuzzer against the application called Free Photo Viewer. As far as I remember I found it here. But first things first...


Depends on what you would like to do (/"fuzz") ;)

In case of webapps or web servers - sometimes I'm using Burp Suite [1, 2]. But for cases similar to the one we have here (FreePhotoViewer) I will recommend you to install:
- clean Windows 7 (I used 32bit)
- Immunity Debugger
- mona.py from Corelan Repository
- HxD (but you can use any hex editor you like)
- target app (in our case - FreePhotoViewer)
- FOE2 - "Failure Observation Engine".

Installation of FOE2 should be easy but remember to read the funky manual anyway! ;)

For example: you will find the place to edit in the source code to get some more detailed results:

As you can see (red frame - cdb_command): here you can put your favourite (Windbg) commands.
I like to add there also: u eip-1; u eip; kb and other similar commands. ;)

I assume that your VM LAB is prepared and FreePhotoViewer is installed. So it's time to prepare a config for the FOE2 fuzzer.


Installed (target) app is located in "C:\Program Files\Free Photo Viewer":

We will need it soon.  Foe2 default installation directory is c:\FOE2\. There you will find config, seeds and results:

Let's copy default config file (foe.yaml) to 01-freephotoviewer.yaml. Next open it and edit like it is presented on the screens below:

As you can see we are changing the name of our 'fuzzing campaign'. Next (red frame) is to place a full path to the target we want to fuzz. 3rd red frame - I just deleted NUL because we will not use any other argument.

Next thing to check in the config - location of our files. In default FOE will store all files (seeds, results) in C:\FOE2\ directory. Edit the location (path) of your 'sample' (seed) file(s):

Next thing nice to check in the config is called 'Fuzzer options'. We will not discuss it today (to keep it simple;)) but you should definitely try to play the options available:

So config file is ready. Now it's time to prepare a sample file. :)

In c:\foe2\seedfiles\example\ you will find a lot of files to try with FOE2. I like to get 2 or 3 (or 8 ;)) and change it a little bit in HxD. In most cases - for example I will take BMP file - I will:
- leave one original BMP file
- take a copy of it and add (for example a lot of) AAAAAA...AAAA in the end of the file
- copy original file but only header (few first lines in HxD) and then I'm adding "a lot of A's" ;)

In this case from 1 sample seed file I will have a 3 files:

Example file (roughly;)) changed:

Save the seedfile(s and your config) and run FOE2 in cmd.exe, like this:


In usual it should take no longer than few hours to find 'first crash'. But for example for Outlook[1, 2] or Access[3] it took 2 months on my small laptop to finally crash the application. ;)

Anyway... after let's say "3 days"... "you found it! There is a crash!" ;] Cool but what to do next?

Of course "depends on the crash". ;) But for most Windows cases (read: as far as I saw so far) it will be: malformed heap, SEH overflow or Unicode (SEH) overflow. Let's try to identify "the one" from our target app:

As you can see there are 'few' bugs to check... I believe you will have some fun. ;)

Now let's open our target app in ImmunityDbg. As an argument we will use the path to the poc-file generated by FOE2. We should be somewhere here:

As we can see SEH is malformed, so probably we will have to exploit SEH overflow bug. Cool. :)

I used HxD to open the poc file to (hopefully) see if there will be our value from SEH chain:

Great! Next step: change nSEH, right?

So far, so good. ;) Next I used mona.py to get POP, POP, RET:

Next I restarted the target app and after initial run (F7) I added a breakpoint on the location found with "!mona seh" (ppr), for example:

(After the jump to ppr value asm will change, so don't worry ;))

This was a time when the 'tricky part' started. I was sure it is 'easy overflow' and I need to change the 'poc file' simply by adding more AAAA letters... Well, nope. ;] If I added new letters - file structure was changed. :|

So the only way was to create a 'valid shellcode' with 39 characters. :)

First of all I tried to use some MsgBox shellcodes I found online but almost all of them were 'bigger than 39characters', so I failed again.

Next day ;) I realized that one time during some private talk mzer0 and @M4tisec already told me what can I do to exploit bug(s) like this one.

TL;DR: We will create a small shellcode ;] to:
- put calc.exe in memory
- run it using WinExec

Simple enough? "We gotta try":

I played a little bit more with the target app to see what shoud I do to manipulate the flow:

As you can see below, the file is not so long so there is a small space to put our shellcode:

I changed 43434343 to poppopret. Next we can see that we can jump to our NOP's and CCCC-shellcode:

So after a while (and a lot of reading and searching online) I created this nasty shellcode ;P

In 2nd and 3rd PUSH you will find ".exe" and "calc" (see ESP below), next is WinExec function.

Final results you will find on the screen below:

That's all ;)

I hope now it will be easier to find some new bugs. In case of any questions - feel free to mail me or ping me @twitter. ;)

If you like the post and you would like to donate (or just buy me a coffee;)) - on the top (right) you will find a Paypal button.

See you next time! ;)


2 komentarze:

  1. "TL;DR: We will create a small shellcode ;] to:
    - put calc.exe in memory
    - run it using WinExec"

    I assume that WinExec function was in 39bytes shellcode.
    But how did you put calc.exe in memory?

    1. Hi, in a very same way: as you can see (on screens) winexec was 'added' by editing asm in immunitydbg. so preparing a file (contains the same shellcode) should do the job.

      2nd: thanks for watching! ;)