FlareOn-9 Writeups 06 à la mode

chall 06 banner

Introduction

Description:

FLARE FACT #824: Disregard flare fact #823 if you are a .NET Reverser too. We will now reward your fantastic effort with a small binary challenge. You’ve earned it kid!

This time, we’ll be looking at a Windows library named HowdoesThisWork.dll.

A text file called IR chat log.txt is also provided:

[FLARE Team]  Hey IR Team, it looks like this sample has some other binary that might 
              interact with it, do you have any other files that might be of help.
			  
[IR Team]     Nope, sorry this is all we got from the client, let us know what you got.

The .NET rabbit hole

We can immediately understand what this text file is referring to by opening the library in dnSpy: a la mode dnspy

From what we can observe, this library only have a single namespace FlareOn, with a single method called GetFlag().

This function is basically taking a password as input, send it to the local named pipe FlareOn and returns the answer from what’s on the other end of the pipe.

This is great, but we are obviously missing a key component of the application here.

Taking a step back on the challenge can help us understand that something is wrong. The binary is 77 KB in size, which is way larger than what’s needed to store this small method.

And if we observe the program in a hex editor, we stumble upon some interesting stuff: a la mode cpp strings

Here is a bunch of string that are typical of a C++ compiled binary.

We also have some sections names that are not detected in dnSpy: a la mode cpp strings

Looks like this binary is more than it pretend to be, and that a C++ program is somehow hidden in it.

Loading it in IDA as a PE file, not as a dot net module, reveal a set of new functions!

Once again, we got tricked by the challenge description that forces us to assume that this was a dot net binary :)

Hidden entrypoint

The technique used to hide the entrypoint and act as a valid dot net module while being able to execute raw C/C++ code is described in this article.

Basically, a new entry was added into the dll_dispatch function, which is part of the .Net CRT (DllMainCRTStartup), that is not going to raise any suspicions: a la mode dll_main

We can observe this entry in the dispatcher at 0x1000174F: a la mode hidden entry

By using this “hidden” additional entrypoint, the code is able to act as a valide .Net binary, without having any references to the protected code.

That’s also a smart way to backdoor a dot net application, even if the fact that something is off is pretty obvious in this particular case.

API hashing

Opening up the first function from our new entrypoint display something that some trained eyes can instantly recognize: a la mode api hash

API hashing is a popular technique used by a lot of malware authors to hide external API references by resolving them at runtime. The classic way of dynamically resolving an API in Windows is by using LoadLibrary to map the desired library in our process, then to utilize GetProcAddress to obtain a handle to an arbitrary function from the library. That way, instead of calling a suspicious API, the malware is calling a bunch of variables that does not make any sens when taking a first quick look.

Unfortunately, this way of operating is not stealthy as the library and the function name must be referenced by string:

typedef int(WINAPI *InternetOpenUrl_proc)(HINTERNET, LPCTSTR, LPCTSTR, DWORD, DOWRD, DWORD);

HANDLE lib = LoadLibraryA("Wininet.dll");
InternetOpenUrl_proc hInternetOpenUrl = (InternetOpenUrl_proc)GetProcAddress(hModule, "InternetOpenUrl");
hInternetOpenUrl([...]);

This small example show that a simple dynamic resolve of the desired API is not stealthy at all, and is in fact even more suspicious and easily noticeable.

That where the API hashing technique comes into place.

Its goal is to perform the same task, without leaking the names of the target functions.

Hiding the name of the target DLL is a matter of encoding / encryption / obfuscation and is not technically part of the API hashing routine.

To retrieve a pointer to our external function, the goal is to get rid of the GetProcAddress API. The main way of doing so is to manually walk down the loaded library list (available from the PEB under InMemoryOrderModuleList), loop on each loaded library export table until we found the desired one. This can be done with a simple comparison, or by storing a “hash” (most of the time a CRC + XOR, or some variations of that as the operation should stay lightweight) of the desired function, and using the same algorithm used to produce this hash against the library exports.

By doing this, an analyst has to reverse the hashing mechanism before starting the actual reverse-engineering of the malware (In reality, this is easy to deal with once used to it).

Here we have multiple hints that this function is resolving a bunch of function for a later use. First, a list of continuous DWORD are initialized, and there cross-references show that they are called later: a la mode api xref

Then, we can aslo recognize a pattern in the use of the sub_100014AE function, which takes two encoded strings as parameters: a la mode api xref

And by tracing the result of this function, it is used in sub_1000125C as a parameter along with a second constant parameter v0.

We can emit the hypothesis that the first function is decoding / decrypting the name of the external function to resolve, when the second one is locating it in the target library. v0 being a handle to that said library.

We can confirm this by taking a look at sub_100012DB, which indeed returns a pointer to kernelbase.dll by locating it from the PEB (FS register + 0x30, no need to resolve any external library this time): a la mode kernelbase address

Finally, the function that we suspected to resolve the external function names is performing a xor between the two given argument, returning a function name.

After a bit of renaming and cleaning, we obtain the following: a la mode api resolved

We can immediately spot the CreateNamedPipeA function, indicating that we are closer to the missing “server” component from the .Net file.

From now, with the resolved imports, the analysis will be simplified.

Analysis

The next function is launched as an independent thread through CreateThread. The thread entrypoint is listening for an input on the \\.\pipe\FlareOn named pipe: a la mode threat entry

When something is received, the function sub_10001000 is called. As a reminder, the received input is the one sent by the .Net component. So we can assume that this function is the one in charge of checking the validity of the password.

This function is straight forward. It is a simple RC4 decryption of a blob of data followed by a comparison on the input password.

Exactly as in the 4th challenge, we can identify the RC4 algorithm through its KSA and PRGA phases (which are optimized by the compiler this time): a la mode RC4 algo

The comparison function, which is straighforward do deal with, is the following: a la mode RC4 algo

As the RC4 key is simply stored as a byte array, we can dump it along with the encrypted password, and decrypt it to reveal the flag to validate the challenge:

“M1x3d_M0dE_4_l1f3@flare-on.com”

a la mode flag