✅ MALWARE - Snake Eater II
Writeup by: @goproslowyo
Tags
- medium
Files:
Description
Author: @HuskyHacks
Snake Eater II - Revenge of the Snake Eater The Threat Actor must have gotten word that you had no trouble dissecting Snake Eater. They said this one is a bit more… involved. Archive Password: infected
NOTE, this challenge is based off of a real malware sample. Windows Defender will probably identify it as malicious. It is strongly encouraged you only analyze this inside of a virtual environment separate from any production devices. Download the file(s) below.
Writeup
This challenge was revenge from the first Snake Eater challenge. It’s another PyArmor-obfuscated self-extracting PyInstaller Windows executable. Let’s just skip the whole pyinstxtractor / pycdc hullaballoo and jump straight into reversing this thing.
For starters, just running snake_eaterII.exe
and viewing it in Sysinternals Process Monitor
showed some really interesting things. First thing I noticed is that it looks like it was randomly choosing a folder under %APPDATA%
. Next, it was calling WriteFile on a file called tmp.txt
one byte in size followed by flag.txt
thirty-eight bytes in size. Aha, flag sized! But then we can see it immediately deletes the file. Hmm.
Let’s set some filters to clean up the output.
I’d normally try debugging/reversing in cutter but it doesn’t have the ability to follow child processes and in this case the binary actually calls CreateProcess
and we’d really like to debug that process.
So, let’s go over to WinDbg and load the executable for debugging.
Next, we’ll use .childdbg 1;gc
to enable debugging child processes and continue the execution.
Next, we’ll break on WriteFile
in kernel32.dll and just echo it out. We want to inspect the registers on our second break (if you recall the WriteFile
calls we saw previously in the ProcMon
screenshots).
Now, let’s take a second to learn about (or recall) what we know about x64 calling conventions and the WriteFile
function and what parameters are which. What is important to see here is that the registers used for storing the parameters to the function call are RCX
, RDX
, R8
, R9
.
The next important thing to check is the parameters to WriteFile
. We’re interested in RDX
which is lpBuffer
and R8
which is nNumberofBytesToWrite
. Do you see how those line up? Great.
Knowing this information, the next time we come around to the breakpoint we can inspect the registers R8
should contain 0x26
which is the 38 bytes
or the size of our flag and RDX
should literally contain the raw flag bytes.
The flag:
flag{be47387ab77251ecf80db1b6725dd7ac}
We can use this series of WinDbg commands to print the flag with basically a one-liner:
.childdbg 1;gc;bp KERNELBASE!WriteFile ".echo 'WriteFile called, breaking...'";gc;gc;r;da rdx L26;