Last week we played the Cyber Apocalypse CTF 2022 - Intergalactic Chase with my team. This article serves as a writeup for the Reflection forensic challenge.

Cyber Apocalypse CTF Logo

Pretty fun challenge and relevant to the previous articles on this blog. If you haven’t already, go take a look at them (PE format and especially Reflective loading). Enjoy!

The actual writeup

Introduction

As a quick introduction to the challenge, we get this few lines of text:

You and Miyuki have succeeded in dis-empowering Draeger’s army in every possible way. Stopped their fuel-supply plan, arrested their ransomware gang, prevented massive phishing campaigns and understood their tactics and techniques in depth. Now it is the time for the final blow. The final preparations are completed. Everyone is in their stations waiting for the signal. This mission can only be successful if you use the element of surprise. Thus, the signal must remain a secret until the end of the operation. During some last-minute checks you notice some weird behaviour in Miyuki’s PC. You must find out if someone managed to gain access to her PC before it’s too late. If so, the signal must change. Time is limited and there is no room for errors.

We download the challenge and start poking around.

$ ls -lah memory.raw

-rwxrwxrwx 1 skrix skrix 1.0G Apr 20 13:06 memory.raw
$ file memory.raw 

memory.raw: data

It appears to be a memory dump. Let’s get cracking.

Analysis

To perform the analysis, I’ll be using the well known Volatility3. Clearly the best tool out there atm to perform memory analysis.

Let’s begin to gather information about the dump. As the challenge was called Reflection, I assumed the challenge was about Reflective loading (I wonder, where I could read more about that particular subject? cough cough..).

As we might be dealing about reflective loading in this challenge, I suspected the image to be a Windows memory dump. And in fact it is:

$ python3 vol.py -f ../memory.raw windows.info.Info

Volatility 3 Framework 2.2.0
Progress:  100.00       PDB scanning finished
Variable    Value

Kernel Base 0x8281c000
DTB 0x185000
Is64Bit False
IsPAE   True
layer_name  0 WindowsIntelPAE
memory_layer    1 FileLayer
KdDebuggerDataBlock 0x82947c68
NTBuildLab  7601.18939.x86fre.win7sp1_gdr.15
CSDVersion  1
KdVersionBlock  0x82947c40
Major/Minor 15.7601
MachineType 332
KeNumberProcessors  1
SystemTime  2022-04-20 11:06:10
NtSystemRoot    C:\Windows
NtProductType   NtProductWinNt
NtMajorVersion  6
NtMinorVersion  1
PE MajorOperatingSystemVersion  6
PE MinorOperatingSystemVersion  1
PE Machine  332
PE TimeDateStamp    Wed Jul 22 16:46:25 2015

Where to now chief?
Well, according to my first huntch we are looking for an injected PE or DLL file somewhere. My first guess was to run malfind to see if anything stood out.

(The outputs of Volatility3’s commands can get fairly long, most of them in this article are truncated.)

According to the Volatilty3’s documentation:

The malfind command helps find hidden or injected code/DLLs in user mode memory, based on characteristics such as VAD tag and page permissions.

Scrolling through the results of malfind, some of the data immediately stands out as weird. Why?

python3 vol.py -f ../memory.raw windows.malfind.Malfind

[...]
3244    notepad.exe 0xb0000 0xb3fff VadS    PAGE_EXECUTE_READWRITE  4   1   Disabled    
00 00 90 00 03 00 00 00 ........
04 00 00 00 ff ff 00 00 ........
b8 00 00 00 00 00 00 00 ........
40 00 00 00 00 00 00 00 @.......
00 00 00 00 00 00 00 00 ........
00 00 00 00 00 00 00 00 ........
00 00 00 00 00 00 00 00 ........
00 00 00 00 d0 00 00 00 ........    
0xb0000:    add byte ptr [eax], al
0xb0002:    nop 
0xb0003:    add byte ptr [ebx], al
0xb0005:    add byte ptr [eax], al
0xb0007:    add byte ptr [eax + eax], al
0xb000a:    add byte ptr [eax], al

3244    notepad.exe 0x170000    0x170fff    VadS    PAGE_EXECUTE_READWRITE
53 89 e3 83 e4 f0 b9 00 S.......
00 0b 00 ba 01 00 00 00 ........
b8 00 00 00 00 50 52 51 .....PRQ
b8 50 12 0b 00 ff d0 89 .P......
dc 5b c3 00 00 00 00 00 .[......
00 00 00 00 00 00 00 00 ........
00 00 00 00 00 00 00 00 ........
00 00 00 00 00 00 00 00 ........    
0x170000:   push    ebx
0x170001:   mov ebx, esp
0x170003:   and esp, 0xfffffff0
0x170006:   mov ecx, 0xb0000
0x17000b:   mov edx, 1
0x170010:   mov eax, 0
0x170015:   push    eax
0x170016:   push    edx
0x170017:   push    ecx
0x170018:   mov eax, 0xb1250
0x17001d:   call    eax
0x17001f:   mov esp, ebx
0x170021:   pop ebx
0x170022:   ret 
0x170023:   add byte ptr [eax], al
[...]

Well, we have two memory ranges in notepad.exe that are flagged PAGE_EXECUTE_READWRITE. This is quite unusual. Having a memory space flagged as such could indicate injection in the process.

But that is not all.

If we take a look the disassembled asm code for the 0x170000 range. A few things stand out:

[...]
0x170000:   push    ebx
0x170001:   mov ebx, esp
[...]
0x17001f:   mov esp, ebx
0x170021:   pop ebx
0x170022:   ret 
[...]

These few lines sure look like an asm function prologue and epilogue to me.

In assembly language programming, the function prologue is a few lines of code at the beginning of a function, which prepare the stack and registers for use within the function. Similarly, the function epilogue appears at the end of the function, and restores the stack and registers to the state they were in before the function was called.

We might be looking at some sort of malicous code here.

Another thing should have drawn your attention.

[...]
0x170018:   mov eax, 0xb1250
0x17001d:   call    eax
[...]

The value 0xb1250 is moved into EAX and is called. Interesting. If you recall the malfind output, there is another memory section (0xb0000-0xb3fff) that is also PAGE_EXECUTE_READWRITE.

Let’s dump both sections using VadInfo (we could also have used malfind to acheive that):

python3 vol.py -f ../memory.raw windows.vadinfo.VadInfo --pid 3244 --dump --address 0xb0000
python3 vol.py -f ../memory.raw windows.vadinfo.VadInfo --pid 3244 --dump --address 0x170000

According to the function we just analysed, something tells me that what we are looking for is in the memory section @0xb0000.

$ file pid.3244.vad.0xb0000-0xb3fff.dmp

pid.3244.vad.0xb0000-0xb3fff.dmp: data

Nothing using the file command.

Quick hexdump to check what this file is:

$ hexdump -C pid.3244.vad.0xb0000-0xb3fff.dmp | head

00000000  00 00 90 00 03 00 00 00  04 00 00 00 ff ff 00 00  |................|
00000010  b8 00 00 00 00 00 00 00  40 00 00 00 00 00 00 00  |........@.......|
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 d0 00 00 00  |................|
00000040  0e 1f ba 0e 00 b4 09 cd  21 b8 01 4c cd 21 54 68  |........!..L.!Th|
00000050  69 73 20 70 72 6f 67 72  61 6d 20 63 61 6e 6e 6f  |is program canno|
00000060  74 20 62 65 20 72 75 6e  20 69 6e 20 44 4f 53 20  |t be run in DOS |
00000070  6d 6f 64 65 2e 0d 0d 0a  24 00 00 00 00 00 00 00  |mode....$.......|
00000080  81 2d 03 c5 c5 4c 6d 96  c5 4c 6d 96 c5 4c 6d 96  |.-...Lm..Lm..Lm.|
00000090  d1 27 6c 97 c6 4c 6d 96  c5 4c 6c 96 c7 4c 6d 96  |.'l..Lm..Ll..Lm.|

There it is. This section seems to contain a binary file, but the magic bytes (0x4D5A - MZ) of the file have been stomped (meaning overwritten for obfuscation purposes).
That is also why the file output did not detect the binary file!

Before extracting the file and throwing it at Ghidra, I usually try out commands such as strings or hexdump to see what I can quickly gather before moving on to heavier analysis.

Looking at the hexdump output, we observe this section:

$ hexdump -vC pid.3244.vad.0xb0000-0xb3fff.dmp

[...]
00001000  55 8b ec 83 ec 78 c6 45  88 70 c6 45 89 6f c6 45  |U....x.E.p.E.o.E|
00001010  8a 77 c6 45 8b 65 c6 45  8c 72 c6 45 8d 73 c6 45  |.w.E.e.E.r.E.s.E|
00001020  8e 68 c6 45 8f 65 c6 45  90 6c c6 45 91 6c c6 45  |.h.E.e.E.l.E.l.E|
00001030  92 20 c6 45 93 2d c6 45  94 65 c6 45 95 70 c6 45  |. .E.-.E.e.E.p.E|
00001040  96 20 c6 45 97 62 c6 45  98 79 c6 45 99 70 c6 45  |. .E.b.E.y.E.p.E|
00001050  9a 61 c6 45 9b 73 c6 45  9c 73 c6 45 9d 20 c6 45  |.a.E.s.E.s.E. .E|
00001060  9e 2d c6 45 9f 65 c6 45  a0 6e c6 45 a1 63 c6 45  |.-.E.e.E.n.E.c.E|
00001070  a2 20 c6 45 a3 5a c6 45  a4 51 c6 45 a5 42 c6 45  |. .E.Z.E.Q.E.B.E|
00001080  a6 6a c6 45 a7 41 c6 45  a8 47 c6 45 a9 67 c6 45  |.j.E.A.E.G.E.g.E|
00001090  aa 41 c6 45 ab 62 c6 45  ac 77 c6 45 ad 41 c6 45  |.A.E.b.E.w.E.A.E|
000010a0  ae 67 c6 45 af 41 c6 45  b0 45 c6 45 b1 67 c6 45  |.g.E.A.E.E.E.g.E|
000010b0  b2 41 c6 45 b3 56 c6 45  b4 41 c6 45 b5 42 c6 45  |.A.E.V.E.A.E.B.E|
000010c0  b6 43 c6 45 b7 41 c6 45  b8 48 c6 45 b9 73 c6 45  |.C.E.A.E.H.E.s.E|
000010d0  ba 41 c6 45 bb 5a c6 45  bc 41 c6 45 bd 42 c6 45  |.A.E.Z.E.A.E.B.E|
000010e0  be 73 c6 45 bf 41 c6 45  c0 47 c6 45 c1 77 c6 45  |.s.E.A.E.G.E.w.E|
000010f0  c2 41 c6 45 c3 63 c6 45  c4 77 c6 45 c5 42 c6 45  |.A.E.c.E.w.E.B.E|
00001100  c6 66 c6 45 c7 41 c6 45  c8 47 c6 45 c9 4d c6 45  |.f.E.A.E.G.E.M.E|
00001110  ca 41 c6 45 cb 4e c6 45  cc 41 c6 45 cd 42 c6 45  |.A.E.N.E.A.E.B.E|
00001120  ce 75 c6 45 cf 41 c6 45  d0 46 c6 45 d1 38 c6 45  |.u.E.A.E.F.E.8.E|
00001130  d2 41 c6 45 d3 59 c6 45  d4 67 c6 45 d5 41 c6 45  |.A.E.Y.E.g.E.A.E|
00001140  d6 7a c6 45 d7 41 c6 45  d8 46 c6 45 d9 38 c6 45  |.z.E.A.E.F.E.8.E|
00001150  da 41 c6 45 db 61 c6 45  dc 41 c6 45 dd 41 c6 45  |.A.E.a.E.A.E.A.E|
00001160  de 30 c6 45 df 41 c6 45  e0 48 c6 45 e1 49 c6 45  |.0.E.A.E.H.E.I.E|
00001170  e2 41 c6 45 e3 5a c6 45  e4 41 c6 45 e5 42 c6 45  |.A.E.Z.E.A.E.B.E|
00001180  e6 66 c6 45 e7 41 c6 45  e8 48 c6 45 e9 51 c6 45  |.f.E.A.E.H.E.Q.E|
00001190  ea 41 c6 45 eb 4d c6 45  ec 41 c6 45 ed 42 c6 45  |.A.E.M.E.A.E.B.E|
000011a0  ee 66 c6 45 ef 41 c6 45  f0 47 c6 45 f1 59 c6 45  |.f.E.A.E.G.E.Y.E|
000011b0  f2 41 c6 45 f3 4d c6 45  f4 51 c6 45 f5 42 c6 45  |.A.E.M.E.Q.E.B.E|
000011c0  f6 75 c6 45 f7 41 c6 45  f8 47 c6 45 f9 51 c6 45  |.u.E.A.E.G.E.Q.E|
000011d0  fa 41 c6 45 fb 66 c6 45  fc 51 c6 45 fd 41 c6 45  |.A.E.f.E.Q.E.A.E|
000011e0  fe 3d 6a 00 8d 45 88 50  ff 15 00 20 0b 00 8b e5  |.=j..E.P... ....|
[...]

This resembles base64 in a wierd way. We can also see a byte sequence (“0xc6 0x45”) repeated in the quite a few times. If you know your x86 opcodes, you might know that 0xc6 is a mov instruction.

I extracted the hexadecimal values and headed on to https://defuse.ca/online-x86-assembler.htm to disassemble it.

Defuse CA disassemble

I love this website because it automagically know what to do with you input.

In the disassembled result, we observe a very large ASCII array instanciation:

3:      83 ec 78                sub    esp,0x78
6:      c6 45 88 70             mov    BYTE PTR [ebp-0x78],0x70
a:      c6 45 89 6f             mov    BYTE PTR [ebp-0x77],0x6f
e:      c6 45 8a 77             mov    BYTE PTR [ebp-0x76],0x77
12:     c6 45 8b 65             mov    BYTE PTR [ebp-0x75],0x65
16:     c6 45 8c 72             mov    BYTE PTR [ebp-0x74],0x72
1a:     c6 45 8d 73             mov    BYTE PTR [ebp-0x73],0x73
1e:     c6 45 8e 68             mov    BYTE PTR [ebp-0x72],0x68
22:     c6 45 8f 65             mov    BYTE PTR [ebp-0x71],0x65
26:     c6 45 90 6c             mov    BYTE PTR [ebp-0x70],0x6c
2a:     c6 45 91 6c             mov    BYTE PTR [ebp-0x6f],0x6c
[...]
1ba:    c6 45 f5 42             mov    BYTE PTR [ebp-0xb],0x42
1be:    c6 45 f6 75             mov    BYTE PTR [ebp-0xa],0x75
1c2:    c6 45 f7 41             mov    BYTE PTR [ebp-0x9],0x41
1c6:    c6 45 f8 47             mov    BYTE PTR [ebp-0x8],0x47
1ca:    c6 45 f9 51             mov    BYTE PTR [ebp-0x7],0x51
1ce:    c6 45 fa 41             mov    BYTE PTR [ebp-0x6],0x41
1d2:    c6 45 fb 66             mov    BYTE PTR [ebp-0x5],0x66
1d6:    c6 45 fc 51             mov    BYTE PTR [ebp-0x4],0x51
1da:    c6 45 fd 41             mov    BYTE PTR [ebp-0x3],0x41
1de:    c6 45 fe 3d             mov    BYTE PTR [ebp-0x2],0x3d

Let’s grab the ASCII values and head on to CyberChef:

Decode from hex

powershell -ep bypass -enc ZQBjAGgAbwAgAEgAVABCAHsAZABsAGwAcwBfAGMANABuAF8AYgAzAF8AaAA0AHIAZABfAHQAMABfAGYAMQBuAGQAfQA=

A PowerShell encoded command, almost there!

Let’s run that again in Cyberchef:

Base64 decode

And there it is boyz, the flag for the challenge.

HTB{dlls_c4n_b3_h4rd_t0_f1nd}

Conclusion

In a real forensics investigation, we would have spent more time looking at processes, network information and other artifacts to determine what really happened on this device. However in a CTF scenario, our goal is to find the flag as fast as possible to continue on with other challenges.

It was a very fun challenge to solve and I was eager to share my solution. Thanks for reading.
Byeeeeeeeeeeeeee.

Useful Links

https://github.com/volatilityfoundation/volatility3
http://ref.x86asm.net/coder32.html
https://defuse.ca/online-x86-assembler.htm
https://gchq.github.io/CyberChef/