Tuesday, September 6, 2016

FLARE On 2015 - Challenge 10

About:

This is the 10th challenge from FireEye's 2015 "FLARE On" challenge (http://flare-on.com/)


Solution:

The level starts out with an exe file that doesn't seem to do anything when executed from the terminal:



Rather than go straight to IDA, this time I decided to take a look with a common malware sandbox first. The most interesting take away from the output was that the file (allegedly) dropped a few files to the System32 directory:



The strange thing is, I couldn't find those files on my system after execution....

Breaking out ProcessMonitor quickly showed the problem :)



Ok, so re-running the EXE as an administrator gave a much nicer output:




So now let's take a look at the original EXE and those dropped files (ioctl.exe and challenge.sys) in IDA...

It's immediately clear that the original EXE is an AutoIt-compiled script (or something made to look like an AutoIt-compiled script...), but unfortunately I wasn't able to find a decompiler to use...



Another thing that's quickly clear is that challenge.sys is a kernel driver that starts out simple...




... but ends up being quite complex:



ioctl.exe seems to be a simple piece of code that triggers an event and calls DeviceIoControl with an argument that's passed in via the command line:




As it turns out, ioctl.exe requires this argument or it'll crash (first execution below succeeded, second one failed):




Debugging the execution made it clear that the issue was with the call to _strtoul (below) -- so putting two and two together let's us know that it's using this value as the ioctl code that it sends to the kernel driver:




To confirm all this, I took a look through the ProcessMonitor logs from the original execution, and it looks like after the driver & ioctl.exe files are dropped to disk, ioctl.exe is called with the argument "22E0DC" -- this must be our code!



So now we're in a pretty good place as far as our understanding of what's going on.

We still don't know exactly what we're looking for, but a good place to go next would be to try to analyze exactly what happens when the driver is sent the IOCTL with the correct code.

To do this, the three options that first come to mind are:
  1. try to debug the challenge.sys driver as it runs live on the system
  2. look through the disassembly of challenge.sys in IDA and try to determine the behavior via static analysis
  3. hack the driver code to the point where we can run it directly in user-space and debug it as if it were a traditional .exe/.dll (turns out this was done here: http://www.ghettoforensics.com/2015/09/solving-2015-flare-on-challenges.html -- pretty cool...)
I decided to hope that static analysis would be enough and went with (2) but quickly decided to switch and do the full (1) and live-debug the running driver instead.

I hadn't debugged a kernel driver before, but the StackOverflow answer here was very helpful with getting things set up. (You'll need to use msconfig instead of bootcfg to set the boot params on Windows 7 images, though.)

Once I had everything set up and brought up both virtual machines, I wanted to make sure I could detect the loaded challenge.sys driver, so I ran the following:




Woo hoo! That looks pretty good... We're missing the symbols, but that's expected.



Now, ideally we could find a good place in our kernel module, set a break point for it, and live-debug the module's code.

I decided to set a breakpoint the part of the code where all the jump table entries jump to after they call their included subroutine, hoping that the flag might be in memory somewhere after the driver is called with the correct code:


So now we know our offset within the driver (0x29D468), we just need to know the location our driver's been mapped to in memory.

I found this using Process Hacker, within System's modules:



You can see our final address needs to be the location we see in IDA + the base address from Process Hacker - 0x10000 (the default base address IDA used):



So this is good... we can double check that we have the right address by test disassembling the code in that location in WinDBG, too.

Unfortunately, after hitting the breakpoint and checking out the process's memory, it turns out that the flag is NOT present anywhere.... so it looks like there's still a bit more to do.

Let's trace the code to see what function we call when we go through the jump table this time.

It turns out you hit this rather interesting function:



You can see that it seems to be doing bit checks, which, after reversing the logic, ends up being valid for the string: try this ioctl: 22E068

This looks encouraging again!

So now let's retrace our way through the driver code after it's been triggered by the new ioctl.



It turns out we get sent to another monstrous function. This one seems to do some kind of decoding/decryption, however much of the logic doesn't seem to have any global effect.

Tracing down to the end of the function, we can see a reference to the offset byte_29F210 being passed as an argument to what looks like it could definitely be a decryption function, so that's worth watching.

After reviewing parts of the code above that, it becomes clear that many of the jnz's are being triggered off of registers hard-coded to 0:



 This logic causes our global buffer to always be uninitialized.... However what if we patch the code's memory to take the loops instead?

This can be done many ways, however for our purposes we can use WinDBG's .writemem/.readmem.

Replacing the mov [ebp + var_62], 0 instructions with mov [ebp + var_62], 1 initializes the buffer, and if we trace & watch the memory while it's decrypted, we get the following email address:

unconditional_conditions@flare-on.com

Tuesday, August 30, 2016

FLARE On 2015 - Challenge 9

About:

This is the 9th challenge from FireEye's 2015 "FLARE On" challenge (http://flare-on.com/)


Solution:

From hearing what other people had written about this one, it sounded like this was where things start getting pretty difficult.

Challenge 9 was somewhat of a repeat of Challenge 1 & 2, however this one had a number of tricky anti-analysis tricks thrown in.

It starts out by letting you know it's evolved from the first challenge:




Taking a look at the strings, it looks like we may be able to trace back from the spot in the code that uses "You are success" again...



... but after some basic debugging & breakpoint-setting, it becomes clear we don't actually hit that section of the code. Something funny's going on... :-/

(As it turns out, that entire subroutine is a decoy and is not used at all in the validation process...)

Let's break out IDA and take a look:




Almost immediately after we start stepping through the code, we hit some early trickery designed to throw off static analysis by jumping to the middle of an instruction:



This is pretty standard stuff, and since we're going through it with our debugger, it's no problem -- we can just have IDA re-disassemble the instruction, this time starting from the new EIP address.

As we keep going, it becomes clear they're also doing sneaky things by manually crafting/modifying stack frames (as opposed to simple call/return patterns).

After determining things were going to be not simple, I decided to do a execution trace, like so:



This unfortunately ran into issues related to my IDA version being the free version :-(



But it provided enough information to be useful -- it's now clear that they're crafting/assembling tables of some kind based off of static hex values, with lots of anti-analysis crap stuck in between:



Grabbing those tables out of memory and stepping through the program one more time let's us see that the tables are (a) used as XOR key values, (b) used as lookup values, (c) as ROR values, and (d) as the final expected values to validate the email address.

Reversing the logic gives us the final answer:

Is_th1s_3v3n_mai_finul_foarm@flare-on.com

Saturday, August 27, 2016

FLARE On 2015 - Challenge 8

About:

This is the 8th challenge from FireEye's 2015 "FLARE On" challenge (http://flare-on.com/)


Solution:

The 8th challenge was the stego one. Running the initial EXE file doesn't give too much info...





And opening it up in IDA shows there's really not much going on:




Looking through the data embedded in the file, it looks like there is some kind of structured data, however. Possibly Base64:




After using a hex editor to cut out the non-base64 data, I wrote a quick python script to translate the data to un-base64'd form.

This looks good -- Opening the written file in Notepad++ shows it has as PNG header!



Let's see what it looks like:



From here, I tried taking a look at it with StegSolve:



You can see something may be up when you look at the data planes on a per-bit level. Here's the 7th bit in the red plane:



Here are the 0th bits in each of the RGB planes. See the black bar at the top?



It makes sense that there may be some data hidden in there as the 0th bit would affect the picture the least and could easily be used for hiding some additional data.

From here, I pulled it apart with "zsteg", which immediately detected a PE32 executable file and extracted it easily:



Running this EXE file gives you the email for the next level!







FLARE On 2015 - Challenge 7


About:


This is the 7th challenge from FireEye's 2015 "FLARE On" challenge (http://flare-on.com/)


Solution:

Our prompt this time looks like this:



When I was initially working through these challenges during the contest, this was the one I failed out on.

The obfuscation they used here is really nasty, and you can see it below:




Fortunately, this time I'm going to use de4dot to attempt to deobfuscate the code:



Scanning through the cleaned code, ns2's Class3 looks like the best bet for where the application logic resides. 

We can see it starts out with a few bytearrays:



.... and ends with some interesting logic:



So from this, we can guess "bytes" is our "Warning!" message, "bytes2" is our prompt for the correct password, "text" is the value we type in, and "b" is some combination of other values (and is the value our text needs to match in order to succeed...).

Let's take a closer look at smethod_0:



Looks like an xor loop! We know the raw bytes passed in are (31,100,116,97,0,84,69,21,115,97,109,29,79,68,21,104,115,104,21,84,78) and the key is generated from Class3.smethod_2().

So this is good. We know that the data we pass into the prompt has to be equal to (byte_2 xor Class3.smethod_2()) + '_' + Class3.smethod_3().

Can we invoke these functions directly from powershell? Turns out yes, you can.




So now we have everything we need. After doing the xor computation, string concatenation, and entering the resulting value in the prompt, we get this:



Woo hoo!

FLARE On 2015 - Challenge 6


About:


This is the 6th challenge from FireEye's 2015 "FLARE On" challenge (http://flare-on.com/)


Solution:

This one was the first one I got legitimately stuck on.

Off the bat, it's clear that this one is an Android application that takes a string as input and returns "No" or possibly "Yes" when the correct string is entered.

Digging into this one was tricky for a couple reasons, but I was pretty quickly able to extract/decompile the Android code and see that the app was quite simple and seemed to use a native library to perform the main "checking" functionality.





Based on the function that triggers the call into the library being named "validateEmail", it seems pretty likely that we just need to find what string will cause an "OK" output and that'll be our email address.

The full path of the library where our function is implemented is lib/armeabi/libvalidate.so, so let's open this up in IDA. Here we can see the part where it chooses between "No" and "That's it!":



From here, it looks like we just need to work backwards to find out what will make us go to the green code block.

Looking to the left a bit, we can see a particular section of memory referenced that seems to contain a list of prime numbers...



Strange....  Although when we look at how the string we pass in is validated, it looks like an integer value (coming from two bytes of the string) are decomposed into its prime factors, and these factors are compared against static lists of values. For example, here is one that says we should have two of the fifth prime (11), one of the seventh (17), etc.:



If we go through the list of all expected prime numbers, generate the composite numbers from them, and convert these integer values into two-byte strings, we get the following email address:

Should_have_g0ne_to_tashi_$tation@flare-on.com

Thursday, August 25, 2016

FLARE On 2015 - Challenge 5


About:


This is the 5th challenge from FireEye's 2015 "FLARE On" challenge (http://flare-on.com/)


Solution:

Challenge 5 is different again from the ones before. 

This time we get an exe file called "sender" and a pcap file called "challenge.pcap", so it seems likely we'll need to reverse-engineer the exe to understand some piece of data hidden in the pcap.

Let's take a quick look at the pcap:


For better or worse, it looks like the only data transmitted went out via HTTP POST requests, where the only data sent was 4 bytes in each packet (here: UDYs).

The server responds with simple "1"s. 

So we have it, the full data transmitted in hex was:

55445973314437624e6d6445316f3367356d733156365272594356764f444a46314470784b5478414a3978755a573d3d

In binary this looks like:

UDYs1D7bNmdE1o3g5ms1V6RrYCVvODJF1DpxKTxAJ9xuZW==

Base64?? Un-base64'd it looks like:

P6,\xd4>\xdb6gD\xd6\x8d\xe0\xe6k5W\xa4k`%o82E\xd4:q)<@'\xdcne

Hmmm.... Alright let's break open the exe file with IDA:



Right off the bat, it looks like we're reading a key file "key.txt". So first guess, maybe this will send off the key.txt file after it's been encrypted/encoded and our task is to recover the original file?

Jumping ahead into the part of the code where the imported HTTP-related libraries are used, we get this:



Ok this is looking pretty good & simple. If we explore the calling tree a bit more, we come across what looks like a pretty straightforward XOR loop:



It seems to be using the "flarebearstare" string as a fixed key.

Once we notice that the base64 routine uses a custom, case-swapped alphabet ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/"), it looks like we may be getting pretty close to being done....


Writing out a python3 routine to take the data sent over the network interface, decode it using the special base64 alphabet, and then decrypt it with the constant key XOR, we get something like this:


from base64 import b64decode

KEY = 'flarebearstare'

def decrypt(str):
    result = ""
    for i, b in enumerate(str):
        result += chr(b - ord(KEY[i % len(KEY)]))
     
    return result

data = b64decode('UDYs1D7bNmdE1o3g5ms1V6RrYCVvODJF1DpxKTxAJ9xuZW=='.swapcase())

print(decrypt(data))


Running this code, we see the following printed out:

Sp1cy_7_layer_OSI_dip@flare-on.com

Woo hoo!