CyCTF 2025 Quals — DFIR Write-up
This year I played CyCTF 2025 Quals and managed to solve two DFIR challenges. Because of mid-term exams I only finished one of them…
CyCTF 2025 Quals — DFIR Write-up
This year I played CyCTF 2025 Quals and managed to solve two DFIR challenges. Because of mid-term exams I only finished one of them during the CTF itself and wrapped up the other one afterwards.

Challenge: HiddenInPlainSight
Link: Download challenge
We’re given a logical image of the C: drive and a short description that basically says:
there’s a malicious PDF that was downloaded and executed.
So the first thing I wanted to answer was, what did the user actually run?

To get a list of executed binaries, I parsed Prefetch with PECmd:
PECmd.exe -d "C:\Users\mm370\OneDrive\Desktop\Hiddeninplain\C\Windows\Prefetch" --csv "C:\Users\mm370\OneDrive\Desktop\Hiddeninplain" --csvf "prefetch.csv"
Prefetch tells us:
- Which executables were actually run on the system?
- How many times they were run.
- When they were first and last executed (timestamps).
- Sometimes extra details like paths and referenced files.
So by opening the csv using Timeline Explorer we found

During this review, I noticed a suspicious entry:
- Executable Name:
EMPLOYEE_ONBOARDINGDR_EXE.PDF - Run Count:
2
That name is… not normal. It has EXE inside the name and then ends with .PDF. That’s a classic trick: make it look like a document while it’s actually an executable.
Seeing it in Prefetch with a run count of 2 is good evidence that the user actually launched this fake “PDF” at least twice, so I treated it as the initial phishing payload.
While reviewing the Windows system files in Autopsy, I examined the contents of the C:\Windows\System32\Tasks directory, which stores Task Scheduler definitions.
During this review, I noticed a task with a suspicious name:
***MicrosoftOfficeOffice Feature Updates***
The name is trying to imitate a legitimate Microsoft Office update task, but the duplicated word “OfficeOffice” is a red flag.

There is an Encoded Command
After decoding using CyberChef,

The scheduled task does not contain the full malicious code itself; instead, it acts as a loader for a payload hidden in the WMI repository. Specifically, it queries:
- Namespace:
root\cimv2 - ClassName:
windowsupdate - Filter:
Name="MyHiddenPayload"
From this WMI object it retrieves an obfuscated command, decodes it, and then uses PowerShell to execute the resulting script directly in memory, providing a stealthy, largely fileless execution and persistence mechanism.
Then I located the Windows WMI repository under
C:\Windows\System32\wbem\Repository.
The directory contained the standard WMI database files: INDEX.BTR, MAPPING1.MAP, MAPPING2.MAP, MAPPING3.MAP, and OBJECTS.DATA.
Those files together are basically the WMI database. Roughly:
OBJECTS.DATA→ where the actual classes/instances/properties liveINDEX.BTRandMAPPING*.MAP→ how WMI keeps track of where things are inside the file
Since the persistence clearly used WMI, I grabbed this whole folder and moved it to my lab box.
I used a small PowerShell helper script to load the CTF WMI repository into a live Windows environment and extract the hidden payload.
The script stops the Winmgmt service, backs up the original WMI repository, and temporarily replaces C:\Windows\System32\wbem\Repository\ with the CTF Repository files (OBJECTS.DATA, INDEX.BTR, and the mapping files).
After restarting Winmgmt, it queries root\cimv2 for the windowsupdate class instance named MyHiddenPayload, reads its EncodedCommand property, XOR-decodes it with the key 0x45, and Base64-decodes the result to recover the final PowerShell payload, which is printed and saved to decoded_payload.txt for analysis. Finally, the script restores the original repository from backup and restarts Winmgmt, returning the system to its normal state.
Here is the script:
PS C:\Users\mm370\OneDrive\Desktop\trust> # Run as Administrator
>>
>> Stop-Service -Name Winmgmt -Force
>>
>> $backupPath = "C:\Users\mm370\OneDrive\Desktop\Hiddeninplain\wmi_backup\"
>> New-Item -ItemType Directory -Path $backupPath -Force
>> Copy-Item "C:\Windows\System32\wbem\Repository\*" $backupPath -Force
>>
>> $ctfRepoPath = "C:\Users\mm370\OneDrive\Desktop\Hiddeninplain\C\Windows\System32\wbem\Repository\"
>> Copy-Item "$ctfRepoPath\*" "C:\Windows\System32\wbem\Repository\" -Force
>>
>> Start-Service -Name Winmgmt
>>
>> $instance = Get-CimInstance -Namespace 'root\cimv2' -ClassName 'windowsupdate' -Filter 'Name="MyHiddenPayload"'
>> if ($instance) {
>> Write-Host "Found hidden WMI instance!" -ForegroundColor Green
>> Write-Host "Instance details:"
>> $instance
>>
>> Write-Host "`nEncoded Command data:"
>> $encodedData = $instance.EncodedCommand
>> $encodedData
>>
>> $key = 0x45
>> $decodedBase64Bytes = foreach ($byte in $encodedData) { $byte -bxor $key }
>> $decodedBase64String = [System.Text.Encoding]::ASCII.GetString($decodedBase64Bytes)
>> $decodedPayload = [System.Convert]::FromBase64String($decodedBase64String)
>> $finalScript = [System.Text.Encoding]::ASCII.GetString($decodedPayload)
>>
>> Write-Host "`nDECODED PAYLOAD:" -ForegroundColor Yellow
>> Write-Host $finalScript
>>
>> $outputPath = "C:\Users\mm370\OneDrive\Desktop\Hiddeninplain\decoded_payload.txt"
>> $finalScript | Out-File -FilePath $outputPath -Encoding ASCII
>> Write-Host "`nPayload saved to: $outputPath" -ForegroundColor Green
>> } else {
>> Write-Host "No hidden instance found" -ForegroundColor Red
>> }
>>
>> Stop-Service -Name Winmgmt -Force
>> Copy-Item "$backupPath\*" "C:\Windows\System32\wbem\Repository\" -Force
>> Start-Service -Name Winmgmt
>>
>> Write-Host "`nOriginal WMI repository restored" -ForegroundColor Green
>>
- The full
EncodedCommandvalue returned by PowerShell is
$encodedData = [byte[]](
36,18,19,113,12,6,45,39,16,118,41,63,33,2,19,49,
9,41,23,41,32,13,20,48,23,18,112,47,39,119,23,53,
39,40,33,33,10,47,53,19,19,0,28,113,9,46,33,41,
33,3,11,117,38,40,41,48,31,60,34,42,36,29,33,60,
12,2,45,117,33,13,4,115,9,60,124,116,38,2,23,45,
33,2,19,63,9,40,116,53,28,118,15,51,38,63,7,40,
33,6,112,47,39,119,117,115,10,1,4,113,8,6,124,50,
28,29,15,117,8,22,124,12,8,18,20,61,39,40,38,61,
39,41,7,54,28,17,3,48,20,63,3,11,16,63,3,43,36,
13,20,51,31,40,41,54,31,22,112,50,38,63,0,34,9,
19,19,63,31,16,15,45,38,119,41,47,16,2,3,60,38,
119,41,48,31,60,46,48,20,119,124,48,33,2,19,48,33,
6,46,53
)

- From here we obtain part 1 of the flag:
Part 1 →
H1d1ng1nPla1nC1MS1ght
→ Moving on to part two, I examined the **Microsoft-Windows-Bits-Client/Operational** log.
- This is a Windows event log that records background transfer jobs created by the system and by applications, including the remote URLs they contact and the files they transfer.

Part 2
→Final flag:
**CyCTF{H1d1ng1nPla1nC1MS1ght_ALittleBITSofData}**
Challenge: Trust Leak

We have C logical files that we should investigate.
We found that the attacker didn’t remove the CryptnetUrlCache, which is a Windows folder that stores cached certificate validation data, such as CRL and OCSP responses used by applications to verify websites and signed programs.
Honestly, I guessed they would use a tool like certutil — and that was right — and CryptnetUrlCache was the place where its cache was stored. That directory contains two subfolders: Content and Metadata.


By investigating the Metadata, I found the download link:
https://download.informer.com/win-1192693607-c5308488-66c7422f-27868c05d6c0543f17-aff9fe3f5b80d0e2e-6412598663-1188631454/accessdata_ftk_imager.exe
→ SHA1 hash: 4621cdc24718ed95bd6271e26b0e28307f159b32

MEGA
Here you will see that the attacker used MEGA for data exfiltration. This is well known among hackers.

So, by viewing the MEGALogs folder we got the time window, and it seems that the attacker used DemonSlayer.mp4 as the exfiltration container to hide the data.
“DemonSlayer.mp4” was the new name. To know the real file, I parsed the $J (USN Journal), then opened it with Timeline Explorer, searched for “demon,” and grabbed the timestamp of the renaming process.
Update Timestamp Parent Path Name Extension Update Reasons
2025-09-21 10:26:08 DemonSlayer.mp4 .mp4 RenameNewName
After searching by 10:28 and sorting by time, we got:
Update Timestamp Parent Path Name Extension Update Reasons
2025-09-21 10:26:08 ntds.dit .dit RenameOldName
2025-09-21 10:26:08 DemonSlayer.mp4 .mp4 RenameNewName
2025-09-21 10:26:08 DemonSlayer.mp4 .mp4 RenameNewName|Close
→ So the original name was ntds.dit.
Combining the observed tool (Certutil), the recovered hash (4621cdc24718ed95bd6271e26b0e28307f159b32), the sensitive source (ntds.dit), the staged archive name (DemonSlayer.mp4), the exfiltration destination (MEGA), and the transfer completion time (2025–09–21 10:50:28)
We constructed the final flag: CyCTF{Certutil_4621cdc24718ed95bd6271e26b0e28307f159b32_ntds.dit_DemonSlayer.mp4_MEGA_2025–09–21 10:50:28}
……………..
I hope you enjoyed this write-up and found everything easy to follow. Let me know if you have any feedback!
………………
메타데이터
- post_id
- 96a208eb7d8f
- slug
- cyctf-2025-quals-dfir-write-up-96a208eb7d8f
- url
- https://medium.com/@MAb0EL3TA/cyctf-2025-quals-dfir-write-up-96a208eb7d8f
- canonical_url
- https://medium.com/@MAb0EL3TA/cyctf-2025-quals-dfir-write-up-96a208eb7d8f
- author_url
- https://medium.com/@MAb0EL3TA
- status
- ok
- fetched_at
- 2026-06-23 17:05:31