LabyREnth Capture the Flag (CTF): Windows Track 7-9 Solutions



Category: Events

Welcome back to our blog series where we reveal the solutions to LabyREnth, the Unit 42 Capture the Flag (CTF) challenge. We’ll be revealing the solutions to one challenge track per week. Next up, the Windows track challenges 7 through 9. 

Windows 7 Challenge: Some guy found this pcap and executable. Ready, set, go!

Challenge Created By: Josh Grunzweig @jgrunzweig

For this challenge, users were given both a PCAP and a Windows executable file. Taking a quick look at the PCAP file, we see there are a number of individual connections from 172.16.95.1 to 172.16.95.190, each about the same size.

windows_2_1

Figure 1 Connections in G0blinKing pcap file

Looking at a specific connection, we see that each one is transferring a single byte of data at a time.

windows_2_2

Figure 2 Data in stream 0 for G0blinKing pcap file

Presumably, we can come to the conclusion that some data is being sent from one host to another, one byte at a time. To determine what data has been generated, we need to look at the Windows executable file.

Opening the file, we see a minor Easter egg, where the pdb string was overwritten.

windows_2_3

Figure 3 Overwritten pdb path

Unfortunately for this file, it doesn’t disassemble terribly well, and we see a number of functions that simply jump to the actual function containing the relevant code. This is just a byproduct of how the file was compiled. Looking through the code, however, we can see that the actual core functionality of the code starts at a function at offset 0x412300.

Performing a quick triage of the sample and the functions that are called, we can get a high-level overview of what is going on. Note that I’ve renamed a few of the functions in the figure below based on guesses as to what the functions may be doing.

windows_2_4

Figure 4 Main function of executable

So, we can safely conclude that some form of encryption is being performed against the data contained in file.txt, it’s then being encoded, and then sent across the network, where the PCAP was generated from. At this point we simply need to identify what is happening during encryption and encoding respectively.

For encryption, we track down a function that looks to be primarily responsible. We also identify a string aptly named ‘AWildKeyAppears!’, which is most likely going to be the key used for encryption. Looking at the beginning of this function, we identify a number of constants as seen in the following figure.

windows_2_5

Figure 5 Encryption function

A number of these constants turn out to be red herrings. However, if we look at the constant of 0x9E3769B9, we see that this constant is used in the TEA/XTEA encryption algorithms. Further review of this function shows us that we’re simply dealing with XTEA, with a few red herrings thrown in. The following original source code shows what it looked like prior to compilation.

Now we can move onto the encoding function. At a quick glance, it looks to be base64. However, if we look at the alphabet, it does not look to be standard. The following is the traditional base64 alphabet.

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

This is the alphabet discovered within the Windows executable.

qtgJYKa8y5L4flzMQ/BsGpSkHIjhVrm3NCAi9cbeXvuwDx+R6dO7ZPEno21T0UFW

Knowing this, we can now create a script that will both parse the PCAP file and decrypt the contents sent across the wire. The following script was created to accomplish this.

Running this script against the provided PCAP file, we’re presented with the following output.

PAN{did_1_mention_th0se_pupp3ts_fr34ked_m3_out_recent1y?}

Windows 8 Challenge: Prepare for windows kernel debugging! (smile)

Challenge Created By: Esmid Idrizovic @xedi25

Initial analysis

When we open the file revloader.exe in a PE viewer we see that it’s a PE64 file. The file contains three unencrypted resources in the RCData directory.  We extract all three resource files to look at what’s in these files.

windows_2_6

Resources of revloader.exe

Resource 101

This file is also a PE64 and contains some version information strings, which tells us that it’s DSEFix. DSEFix is a tool that can bypass the driver signature enforcement in Windows by using an exploit in a signed VirtualBox driver. By using DSEFix, you can disable DSE and load any driver you want. So it looks like we’ll solve this challenge by using an unsigned windows driver.

windows_2_7

Resource 102

This is the driver itself. It’s also a PE64 and uses FLTMGR.SYS. In version information, we can see that it’s a windows driver with the internal name revhunt.sys. We can also see that the file is not signed, so it makes sense that revloader.exe is going to use DSEFix to load the revhunt.sys.

Resource 103

This is an INF file for the driver. We can see that it’s a mini file filter driver and that it uses the altitude 31337.

Revloader

Let’s start with revloader.exe to verify that it’s going to drop DSEFix driver and run DSEFix to disable windows driver signature enforcement. We can take a look at the import table to find important functions that might be used for this kind of work.

windows_2_8

  • LookupPrivilegeValueW/AdjustTokenPrivilege: to acquire the missing rights to load a driver (“SeLoadDriverPrivilege”).
  • LoadResource/FindResource: to find a resource and map it to memory.
  • CreateFileW: to create or access a file on the disk.
  • WinExec: to execute a file.
  • FilterLoad/FilterUnload: to load and unload a mini filter driver.

Following cross-references to FilterLoad we can see that the function to load the driver is at 0x140001800. That function uses InstallHinfSectionW with arguments “DefaultInstall 132 <filename.inf>” to install the driver and then uses FilterLoad to load the driver. If we follow that function back, we can see that this function has been called from main function and we can see that there are a few more interesting calls:

windows_2_9

We can see that the function at 0x140001FD0 will be called with argument 101, 102, and 103. That means this function is probably accessing the embedded resources. If we look into that function we will see that it uses FindResourceW, SizeofResource, LoadResource, CreateFileW and WriteFile. We can rename that function to DropResource. After these three calls, it will call WinExec.

That means that revloader is dropping the resources to current directory (resource 101, 102, 103) and then executing dsefix.exe (resource 101) after it loads the mini file filter driver (resource 102 + 103).

Let’s run revloader.exe to load the driver into kernel and see if it works.

windows_2_10

We can see the “Welcome to revhunt x86-x64”. Now let’s analyze the driver and try to find the flag.

Revhunt

Opening revhunt.sys in IDA Pro we can see that in DriverEntry function there is a jump to 0x140007000. That looks like the real main function.

windows_2_11

We can see that the driver is using some kernel anti-debugging functions like KdDebuggerNotPresent and KdDisableDebugger. That means if we attach a kernel debugger to our virtual machine, the function KdDisableDebugger will disconnect us. We would have to patch KdDebuggerNotPresent and KdDisableDebugger with NOP instruction or, since the driver is not signed, we can also patch the calls in the driver itself.

We can also see that the driver uses FltRegisterFilter and FltStartFiltering. Let’s take a look at definition of FltRegisterFilter:

FltRegisterFilter takes a FLT_REGISTRATION structure as a second argument that contains information (flags, callback routines, etc.) for the registration of the mini file filter driver. The second argument for FltRegisterFilter in this case is:

We can go to IDA Pro and set a structure at 0x140003140 as FLT_REGISTRATION but before we do that we have to load the correct type library: Windows Driver Kit 8 (kernel mode) – wdk8_km. You can also take any newer DDK libraries. Now we can set the correct structure:

windows_2_12

Using that we can quickly identify what each sub-function is used for. We can also see that the flags for the structure are set to 0x02, which is FLTFL_REGISTRATION_SUPPORT_NPFS_MSFS. According to MSDN that means that the driver supports named pipes and mailslot requests as normal file events.

windows_2_13

Now let’s do the same with OperationRegistration and set a structure of FLT_OPERATION_REGISTRATION:

windows_2_14

Checking quickly for PreOperation and PostOperation code, we can see that the really interesting code is going on in the PostOperation function, so let’s analyze that.

PostOperation callback

Before we start, we should set a new function definition in IDA Pro to the correct definition like in MSDN, it will make our analysis a lot easier (and if you use the Hex-Rays Decompiler it will decompile a lot better). So let’s change the function definition to:

By loading the correct type libraries, we can simplify the analysis because that code looks easier to read:

windows_2_15

We can see that the function is checking if the current FileObject is a mailslot event (FO_MAILSLOT), if the current file name of the object is 18 characters long, if “\gsrt.txt”, and if the current event is opening the file. If that’s the case, then it will use FltReadFile to read from the file and compare the content with encrypted data:

windows_2_16

So let’s quickly decode that using a python script:

That means, we have to create a file named “\gsrt.txt” with the content “labyrenth.com” and then open the file. After that we can see there is another byte array initialized on the stack and decode it using the same technique as before:

windows_2_17

Let us write that to our script and decode also that string.

That looks like a hint that tells us that we could have used Interprocess Communications (IPC) to do the same. If we scroll up again we will see that the sample was comparing the current FileObject.Flags with FO_MAILSLOT. That means if there was any Mailslot event it would have directly jumped to 0x140001405, which looks like an initialization function.

If we take a look into that function, we will see that it will allocate a memory address using ExAllocatePoolWithTag and save the result at 0x140004020, which I have named lpszBuffer.

windows_2_18

If we take a look at the cross-references to lpszBuffer, we will see that it’s used in four functions: PostOperation, InitBuffer, 0x14000181C, and Unload. We will look into 0x14000181C a little later but now let’s go back to the PostOperation function and see what happens next.

After the InitBuffer call, it will check the filename of the FileObject again and compare it with “\pan.flag”. If that’s correct, it will call the function 0x14000181C and it will print the flag using DbgPrint. That means that the decrypting routine is at 0x14000181C and that lpszBuffer will contain the decoded flag.

windows_2_19

Now let’s take a look into the function at 0x14000181C. I have renamed that function to TestFlag.

Analyzing flag testing function

At the beginning of the function we can see that it uses FltReadFile again to read the content of the given FileObject. We can also see that it reads 58 bytes. The first four bytes are compared with “PAN{“.

windows_2_20

After that we can see first set of XOR data. It will take the next four bytes and XOR them with 0x1A1B1C1D and compare the result with 0x366C734A. It’s time to start writing our decoder.

Looks good so far…

Let’s move on to the next characters. The next code segment is doing some shifting and XOR based on the result of KdDebuggerNotPresent. Function KdDebuggerNotPresent should return 1 if there is no debugger attached. We also have to reverse the order to get the correct key:

windows_2_21

The result is a space character (0x20 in hex). We can move on to the next character but we have to reverse the order again to get the correct character (instead of add, we have to use sub, etc.):

windows_2_22

Now we just have to continue to slowly decode the whole flag but it gets trickier with a call to 0x140001AFC. At this function it will try to access characters at different offsets and do weirder calculations:

windows_2_23

For example, at 0x140001B41 it will load the fourth character and subtract 0x20 from it and multiply it with 3 [rax+rax*2] and then it will compare it with 0xC3. Optimizer can do some pretty cool stuff sometimes.

After analyzing the whole function and its sub-functions, we get the following decoder script:

Testing the flag

Now we’ll test the flag to confirm if everything is correct. We have to do following steps:

  • Create a file named “gsrt.txt” with content “labyrenth.com”
  • Open “gsrt.txt” to raise a FILE_OPEN event to initialize the buffer
    • We can also create a mailsot event instead of these two steps (we can use CreateMailslot + WriteFile)
  • Create a file named “pan.flag” with our flag “PAN{…}”
  • Open “pan.flag” to raise a FILE_OPEN event to call the analyzing function
  • Attach with DbgView to see the kernel debug output

The solution with creating a file is easier because we can make a batch file to do the job for us:

We run revloader.exe and run our solution batch file and see what happens:

windows_2_24

And we can see in the last screenshot that the flag is correct and it gets printed out.

Windows 9 Challenge: I think some holy dude wrote that crypter.

Challenge Created By: Esmid Idrizovic @xedi25

Initial analysis

When we run the final challenge, we see a dialog where we have to enter 30 characters. We can also see that the icon is different and that it’s the default Delphi 7 executable icon. If we enter any text and press enter we see that the label changes to “Wrong”. That means that we have to enter the correct flag and press enter to verify it.

windows_2_25

If we open that sample in a PE viewer, we see that it’s using an unknown EXE crypter to hide its code (actually that crypter is Morphine 2.7 which is also written in Delphi). We can see that by looking at the import table there are just LoadLibraryA, GetProcAddress, and the PE sections.

windows_2_26

We can solve this challenge pretty fast if we know what we have to look for. We want to identify the routine that is checking for a valid flag. We can start our analysis at the function which sets the status to “Wrong”, but before we can do that we have to dump the executable so we can load it in IDA Pro.

Dump the executable

We can use Scylla x86 to dump the process, so let’s execute the challenge and run Scylla. Select “DelphiChallenge.exe”, press “IAT Autosearch”, after that press “Get Imports” and Scylla should be able to find the imports.  You can already see the correct imports in next screenshot:

windows_2_27

We can save the PE dump using “Dump” and “Fix dump” functions in Scylla. We can’t run that dumped file but it’s enough for a static analysis in IDA Pro. We can dump the file correctly but it takes a few extra steps (see extra part).

Static analysis

Now open the file in IDA Pro and go directly to “strings window” by using Shift+F12. Search in strings window for “Wrong” and you should see these 5 entries:

windows_2_28

If we follow the first string using cross-references, we can see that it’s referenced in sub_4C17BC and there is one more interesting string:

If byte_4C4C5C is nonzero then it will show “Correct!! You are so g00d”. Following byte_4C4C5C we can see that its set to 1 at offset 0x004C127F and that function starts at offset 0x004C0E1C. This function looks like our testing flag routine.

windows_2_30

We have identified pretty quickly the routine which is checking for the correct flag, now we have to analyze that function. It’s pretty similar to Windows track challenge 8. We know that the flag must start with “PAN{“ and we can see that the function is checking for that at the beginning:

windows_2_31

We have to follow the function and revert the calculations again like in Windows challenge 8. The final decoder script would look like this:

We can now test and verify if that flag is correct.

windows_2_32

Extra: Manual unpacking

If we want do dump the process correctly we can use OllyDbg and OllyDump. To identify the original entry point (OEP) we can use the “set hardware breakpoint at current ESP” technique. For that we have to run the first instruction, go to the dump window and jump to the ESP. Then we can set a “Hardware, on access” breakpoint at current address.

windows_2_33

If we press F9 a few times we will reach the original entry point. Now we have to do some calculations and dump it to a new file.

windows_2_34

For calculating the real OEP we need to know at which address the executable has been loaded.

windows_2_35

Now we just have to subtract these offsets and we get the correct offsets for OllyDump.

Now let’s fill that data into OllyDump and dump the file as “dumped.exe”:

windows_2_36

But something is still wrong if we try to execute the unpacked sample:

something-wrong

It’s probably the import table that causes problems, but we can use Scylla to fix that for us. For that we have to run DelphiChallenge.exe again (new process) and search for the import table. We also have to enter the correct entry point + image base:

Now we can use “Fix dump” and fix the dumped.exe executable:

windows_2_38

Scylla has created a new import table and now we can run the unpacked executable. Yey.

windows_2_39

Leave a comment below to share your thoughts about these challenges. Be sure to also check out how other threat researchers solved these challenges:

Windows 7:

Windows 8: 

Windows 9:

Got something to say?

Get updates: Unit 42

Sign up to receive the latest news, cyber threat intelligence and research from Unit42


SUBSCRIBE TO RSS