Writeup: FlareOn 2022: 006 - à la mode
1. TLDR
2. Input data
The challenge file is here. Password: flare.
The subjects of the task were PE and txt files:
HowDoesThisWork.dll
'IR chat log.txt'
3. Contents of txt file
I first suspected the contents of the text file:
[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.
4. Analysis of the file as a .NET Assembly file
I verified the file type:
$ file HowDoesThisWork.dll
HowDoesThisWork.dll: PE32 executable (DLL) (GUI) Intel 80386 Mono/.Net assembly, for MS Windows
Seeing that the file was prepared in .NET, I preliminarily analyzed the file using the simple tools Detect-It-Easy:
and exeinfo:
Aside from an unusual entry point (0x181A), the programs returned no relevant information.
Using the CFF Explorer tool, I did a preliminary check to see if there were any resources worth keeping in mind during the analysis. At this stage, I have not identified any such resources.
Using dnSpyEx I decompiled the file:
using System;
using System.IO.Pipes;
using System.Text;
namespace FlareOn
{
// Token: 0x02000002 RID: 2
public class Flag
{
public string GetFlag(string password)
{
Decoder decoder = Encoding.UTF8.GetDecoder();
UTF8Encoding utf8Encoding = new UTF8Encoding();
string text = "";
byte[] array = new byte[64];
char[] array2 = new char[64];
byte[] bytes = utf8Encoding.GetBytes(password + "\0");
using (NamedPipeClientStream namedPipeClientStream = new NamedPipeClientStream(".", "FlareOn", PipeDirection.InOut))
{
namedPipeClientStream.Connect();
namedPipeClientStream.ReadMode = PipeTransmissionMode.Message;
namedPipeClientStream.Write(bytes, 0, Math.Min(bytes.Length, 64));
int num = namedPipeClientStream.Read(array, 0, array.Length);
int chars = decoder.GetChars(array, 0, num, array2, 0);
text += new string(array2, 0, chars);
}
return text;
}
}
}
Unfortunately, it was all code written in C#….
From the code in C#, I knew that a connection to Named Pipe FlareOn
was being established. What I did not know, however, was what creates it…
So I ran the sample in x32dbg thinking that maybe I had missed something. Perhaps someone made a patch of the .NET Assembly file with x86 code? That would explain:
- the sufficient presence of only one file
- the absence of more code in C#, visible in dnSpy
- the information about the unusual entry point.
5. Analysis of the file as a PE file
Running the dll file could have been accomplished by calling rundll32.exe, for example. Due to the 32-bit dll, the 32-bit version of rundll32.exe had to be indicated as well. The file had only Entry Point without additional exports. The run therefore could have looked like the following:
>C:\Windows\SysWOW64\rundll32.exe ".\HowDoesThisWork.dll,0"
After loading the file into the IDA environment, I was overwhelmed for a while by the number of functions. I reasoned that most of them came from code overhead generated when compiling code written in C#.
If a file should create a Named Pipe, it should have called the CreateFileW
function. So I loaded the file into x32dbg and gave the command to add a breakpoint to this function:
bp CreateFileW
After running the file, I captured the moment of creating the file after stopping several times on the breakpoint:
Reading the return address from the stack 100010DA``, I returned to the place where the
CreateFileWfunction was called, i.e. at the address
100010D4``:
Knowing the place of Named Pipe creation in the program code, I went back to the IDA environment and switched to the same address.
A few instructions above I revealed the function that decodes strings via xor 0x17:
In this way, I revealed the loaded and used functions:
CloseHandle
ConnectNamedPipe
CreateNamedPipeA
CreateThread
DisconnectNamedPipe
FlushFileBuffers
GetLastError
GetProcessHeap
lstrcmpA
ReadFile
WriteFile
Continuing my analysis, I came across the mw_process_buffer
function, which processed the data buffer from Named Pipe:
Analysis of the mw_process_buffer
function revealed the fact that the password and flag were encrypted using the rc4 algorithm:
key = 55 8B EC 83 EC 20 EB FE
password = 3E 39 51 FB A2 11 F7 B9 2C
flag = E1 60 A1 18 93 2E 96 AD 73 BB 4A 92 DE 18 0A AA 41 74 AD C0 1D 9F 3F 19 FF 2B 02 DB D1 CD 1A
6. Reading the flag
Therefore, it was enough to decrypt the password and flag. To do this, I wrote code in Python:decrypted using the rc4 algorithm:
import malduck
key = b'\x55\x8B\xEC\x83\xEC\x20\xEB\xFE'
password = b'\x3E\x39\x51\xFB\xA2\x11\xF7\xB9\x2C'
flag = b'\xE1\x60\xA1\x18\x93\x2E\x96\xAD\x73\xBB\x4A\x92\xDE\x18\x0A\xAA\x41\x74\xAD\xC0\x1D\x9F\x3F\x19\xFF\x2B\x02\xDB\xD1\xCD\x1A'
ciphertext = password+flag
plaintext = malduck.rc4(key, ciphertext).decode('latin1')
print(plaintext)
MyV0ic3! M1x3d_M0dE_4_l1f3@flare-on.com
Thus, the password is:
MyV0ic3!
… while the flag is:
M1x3d_M0dE_4_l1f3@flare-on.com