From LNK Payload to Infostealer Source Code

montysecurity
4 min readNov 2, 2023

--

Introduction

As I have so creatively named this blog post, we are starting with a ZIP/LNK payload and, with some luck, we will end up identifying the infostealer that is being dropped and its source code. Starting with the zip file shown below.

Analysis

Using the VT link to get the payload, we see a ZIP archive containing multiple files, most notably the 3 LNKs and 1 text document.

Contents of the Zip File

Starting with the LNK files, all of them are the same, they all execute SafetyTest.txt using cmd.exe

LNK Contents

It should be noted, parselnk is the following bash function I use for analysis.

parselnk() {
lnkinfo "$1" | grep -e 'Relative path' -e 'Command line arguments' | grep -Eo ': .*' | sed 's/^..//g' | tr '\n' ' '; echo
}

Looking at SafetyTest.txt it looks to be a Windows executable. Next, I calculate its SHA256 and look for it in VT.

Calculate EXE Hash

Looking at the file info, it appears to have been created by PyInstaller, as noted by the info under DetectItEasy.

VT File Info

Having used PyInstaller before, I started looking around for ways to convert the compiled binary back to the libraries that PyInstaller used to make the file. I ended up using this tool and it worked great!

Extracting the PyInstaller files

After extracting them, I focused on the Python bytecode files, and two stood out. (Also, if you are following along and have a different output, I have ls aliased to “ls -lh”)

All PYC files

Initially, Creal.pyc and struct.pyc look different from the rest. Starting with struct.pyc since it is smaller, it shows some code that appears to be part PyInstaller (although I have not confirmed this).

Contents of Struct.pyc

Looking at Creal.pyc, it shows a lot of strings. So I used grep to search for my 2 favorite patterns in quick static analysis. One looks for long strings (.{10}) and the other looks for any string with “http”. Here we see a link to the Creal Stealer on the 8th line of the output.

Contents of Creal.pyc

From there we can get the source code for the infostealer and see the code similarities to the output from the grep shown above.

Hunts

It does appear to have a hard coded user agent throughout the script. But this may also be different in the compiled payload since it is trivial to change.

It does use Discord as it’s C2 so checking network traffic may be a way to hunt for this.

DeviceNetworkEvents
| where RemoteURL has_all ("discordapp.com", "webhooks")

Also, since it executes a text file, looking for cmd.exe with an argument containing “.txt” is another way.

DeviceProcessEvents
| where FileName =~ "cmd.exe"
| where ProcessCommandLine has ".txt"

And lastly, the process tree for an LNK spawning powershell.exe which in turn spawns cmd.exe. (I actually show LNK process trees using a lab in my “Hunting Lazarus Group’s TTPs” post)

DeviceProcessEvents
| where InitiatingProcessParentFileName =~ "explorer.exe"
| where InitiatingProcessFileName =~ "powershell.exe"
| where FileName =~ "cmd.exe"

--

--