$ cat writeup.md…
$ cat writeup.md…
hackthebox
Our cybercrime unit has been investigating a well-known APT group for several months. The group has been responsible for several high-profile attacks on corporate organizations. However, what is interesting about that case, is that they have developed a custom command & control server of their own.
Our cybercrime unit has been investigating a well-known APT group for several months. The group has been responsible for several high-profile attacks on corporate organizations. However, what is interesting about that case, is that they have developed a custom command & control server of their own. Fortunately, our unit was able to raid the home of the leader of the APT group and take a memory capture of his computer while it was still powered on. Analyze the capture to try to find the source code of the server.
TrueSecrets.raw — 200MB Windows memory dump (extracted from ZIP with password hackthebox)Used Volatility3 windows.info to identify the system:
python3 -m volatility3 -f TrueSecrets.raw windows.info
Ran windows.pslist and identified key processes:
| PID | Process | Significance |
|---|---|---|
| 2128 | TrueCrypt.exe | TrueCrypt disk encryption — the challenge name hint |
| 2176 | 7zFM.exe | 7-Zip, opened backup_development.zip |
| 3212 | DumpIt.exe | Memory acquisition tool |
python3 -m volatility3 -f TrueSecrets.raw windows.pslist
Ran windows.filescan and found two critical files:
| Offset | File |
|---|---|
| 0xbbf6158 | \Users\IEUser\Documents\backup_development.zip |
| 0xc50c550 | \Users\IEUser\Documents\development.tc |
Extracted backup_development.zip (304KB) from memory:
python3 -m volatility3 -f TrueSecrets.raw windows.dumpfiles --virtaddr 0xbbf6158
Unzipped to get development.tc — a 300KB TrueCrypt encrypted container.
This is the critical step. TrueCrypt caches passwords in process memory as a struct:
Dumped TrueCrypt process memory (PID 2128):
python3 -m volatility3 -f TrueSecrets.raw windows.memmap --pid 2128 --dump
This produced a 69MB process dump. Wrote a Python script to scan for the cached password pattern:
#!/usr/bin/env python3 """Scan TrueCrypt process memory for cached password struct.""" import struct with open("pid.2128.dmp", "rb") as f: data = f.read() for i in range(len(data) - 68): length = struct.unpack_from("<I", data, i)[0] if 4 <= length <= 30: candidate = data[i+4:i+4+length] padding = data[i+4+length:i+68] if all(32 <= b < 127 for b in candidate) and padding.count(b'\x00') > len(padding) * 0.9: print(f"Offset {i:#x}: length={length}, password={candidate.decode()}")
Recovered password: X2Hk2XbEJqWYsh8VdbSYg6WpG9g7
No TrueCrypt CLI available, so wrote a custom Python decryption script implementing the full TrueCrypt decryption chain:
#!/usr/bin/env python3 """Custom TrueCrypt container decryption (AES-256-XTS).""" from Crypto.Cipher import AES from Crypto.Protocol.KDF import PBKDF2 from Crypto.Hash import SHA512, HMAC import struct password = b"X2Hk2XbEJqWYsh8VdbSYg6WpG9g7" with open("development.tc", "rb") as f: container = f.read() # TrueCrypt header structure: # Bytes 0-63: Salt # Bytes 64-511: Encrypted header salt = container[:64] enc_header = container[64:512] # Derive header key: PBKDF2-HMAC-SHA512, 1000 iterations, 128 bytes output header_key = PBKDF2( password, salt, dkLen=128, count=1000, prf=lambda p, s: HMAC.new(p, s, SHA512).digest() ) # Decrypt header with AES-256-XTS (first 64 bytes of derived key) key1 = header_key[:32] # AES key key2 = header_key[32:64] # XTS tweak key cipher = AES.new(key1 + key2, AES.MODE_XTS) dec_header = cipher.decrypt(enc_header) # Verify: first 4 bytes should be "TRUE" assert dec_header[:4] == b"TRUE", "Decryption failed!" # Extract master key (64 bytes at offset 192) master_key = dec_header[192:256] # Volume metadata from header data_offset = struct.unpack_from(">Q", dec_header, 28)[0] # 131072 data_size = struct.unpack_from(">Q", dec_header, 36)[0] # 45056 # Decrypt data area sector-by-sector (512-byte sectors) data_area = container[data_offset:data_offset + data_size] decrypted = bytearray() mk1 = master_key[:32] mk2 = master_key[32:64] for sector_num in range(len(data_area) // 512): sector_data = data_area[sector_num * 512:(sector_num + 1) * 512] tweak = struct.pack("<QQ", sector_num, 0) # 16-byte tweak cipher = AES.new(mk1 + mk2, AES.MODE_XTS, tweak=tweak) decrypted.extend(cipher.decrypt(sector_data)) with open("decrypted_volume.img", "wb") as f: f.write(decrypted)
The decrypted volume was identified as a FAT12 filesystem.
Used 7-Zip to extract the FAT12 image:
7z x decrypted_volume.img
Contents:
malware_agent/
AgentServer.cs # C2 server source code (C#)
sessions/
5818acbe-68f1-4176-a2f2-8c6bcb99f9fa.log.enc
c65939ad-5d17-43d5-9c3a-29c6a7c31a32.log.enc
de008160-66e4-4d51-8264-21cbc27661fc.log.enc
AgentServer.cs is a C# TCP C2 server listening on port 40001:
AKaPdSgV (8 bytes)QeThWmYq (8 bytes).log.enc files#!/usr/bin/env python3 """Decrypt C2 session logs (DES-CBC + Base64).""" from Crypto.Cipher import DES import base64 import os KEY = b"AKaPdSgV" IV = b"QeThWmYq" def decrypt_line(b64_line): ct = base64.b64decode(b64_line.strip()) cipher = DES.new(KEY, DES.MODE_CBC, IV) pt = cipher.decrypt(ct) # Remove PKCS7 padding pad_len = pt[-1] return pt[:-pad_len].decode('utf-8', errors='replace') for logfile in sorted(os.listdir("sessions")): if not logfile.endswith(".log.enc"): continue print(f"\n=== {logfile} ===") with open(f"sessions/{logfile}") as f: for line in f: line = line.strip() if line: print(decrypt_line(line))
Results:
| Session | User | Commands | Finding |
|---|---|---|---|
| 1 | john | hostname, whoami, dir | No interesting files |
| 2 | paul | hostname, whoami, dir | No interesting files |
| 3 | greg | hostname, whoami, dir, type flag.txt | FLAG found! |
Session 3 (greg) contained:
> type c:\users\greg\documents\flag.txt
HTB{570r1ng_53cr37_1n_m3m0ry_15_n07_g00d}
Memory dump (TrueSecrets.raw)
|
v
Volatility3: pslist -> find TrueCrypt.exe (PID 2128)
|
v
Volatility3: filescan -> find backup_development.zip & development.tc
|
v
Volatility3: dumpfiles -> extract backup_development.zip -> development.tc
|
v
Volatility3: memmap --pid 2128 -> dump TrueCrypt process memory
|
v
Pattern scan -> recover cached password: X2Hk2XbEJqWYsh8VdbSYg6WpG9g7
|
v
Custom PBKDF2-HMAC-SHA512 + AES-256-XTS decryption -> FAT12 volume
|
v
7z extract -> AgentServer.cs (C2 source) + encrypted session logs
|
v
Source code analysis -> DES-CBC key/IV: AKaPdSgV / QeThWmYq
|
v
DES-CBC + Base64 decrypt session logs -> flag in greg's session
Use these techniques when you see:
.tc file extension — TrueCrypt encrypted containerThe flag message "storing secret in memory is not good" (570r1ng_53cr37_1n_m3m0ry_15_n07_g00d) reinforces the core vulnerability: TrueCrypt caches the volume password in process memory while the container is mounted. A memory dump captures this cached password, allowing full decryption of the container without brute-forcing. This is a fundamental limitation of full-disk encryption when the system is powered on.
$ cat /etc/motd
Liked this one?
Pro unlocks every writeup, every flag, and API access. $9/mo.
$ cat pricing.md$ grep --similar