← Back to Writeups
CUSTOMMediumForensics

The Trilogy of Death Volume I: Corel

XESXOR9/2/20265 min read
#forensics#custom#medium#known_plaintext_xor_attack#partition_extraction#qcow2_to_raw_conversion#red_herring_identification#timestamp_anomaly_detection#wordperfect_macro_analysis#linux

The Trilogy of Death Volume I: Corel

Platform: srdnlen | Category: Forensics | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-02-28 | Status: Solved Techniques: known_plaintext_xor_attack, partition_extraction, qcow2_to_raw_conversion, red_herring_identification, timestamp_anomaly_detection, wordperfect_macro_analysis

Summary

Task: QCOW2 disk image of CorelLinux (dead 1999-2000 distro). Solution: Extract partitions, find .wcm WordPerfect macro with anomalous timestamp in /var/log/, bypass FAKE decoy XOR keys via known-plaintext attack on flag prefix.

The Trilogy of Death Volume I: Corel — srdnlen CTF

Description

"He was born in a forgotten kingdom."

In an era when the penguin still dreamed of conquering the desktop, a kingdom rose - beautiful, ambitious, and doomed. It promised a new world, dressed in the robes of a giant that never truly understood it. The Armourer was there when it was built, and there when it crumbled. He made his first forge in its ruins, hiding his earliest secrets inside a dead world that nobody thought to search anymore. Most people never even knew the kingdom existed. That was always the point.

The Trilogy of Death follows the digital ghost of a legendary hacker known only as The Armourer - a figure who lived and died by obsolete machines, leaving fragments of his secrets scattered across three machines. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Files: chall.zip contains img.qcow — QCOW2 disk image (~490MB compressed, 5GB virtual size).

Analysis

The task is forensics of an obsolete disk image. Key observations:

  1. QCOW2 image contains an installation of CorelLinux — a dead Linux distribution from 1999-2000, Corel's attempt (the company behind WordPerfect and CorelDRAW) to create a desktop Linux. This is the "forgotten kingdom" from the description.
  2. Double reference to Corel: the task name points to both CorelLinux (dead OS) and Corel WordPerfect (word processor that shipped with it).
  3. The flag is hidden in a WordPerfect macro (.wcm), disguised as a log file in /var/log/.
  4. The macro contains XOR encryption with decoy keys F, A, K, E (spelling "FAKE") and the real key extractable via known-plaintext attack. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Solution

Step 1: Extracting and Identifying the Image

bash
unzip chall.zip
file img.qcow
# QEMU QCOW2 Image (v3), 5368709120 bytes

# Convert QCOW2 to raw for analysis
qemu-img convert -f qcow2 -O raw img.qcow img.raw
file img.raw
# DOS/MBR boot sector, LInux i386 boot LOader;
# partition 1: ID=0x83, active, start sector 63, 10217277 sectors;
# partition 2: ID=0x82 (swap)

Step 2: OS Identification

bash
7z l img.raw
# Shows two partitions: 0.img (main ext2) and 1.img (swap)
7z x img.raw 0.img
7z l 0.img

‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

The filesystem label is cdl:/ (Corel Desktop Linux). This confirms we're dealing with a CorelLinux installation — a dead distribution that perfectly matches the task description:

  • "forgotten kingdom" = CorelLinux
  • "dressed in the robes of a giant that never truly understood it" = Corel (corporation) tried to make Linux for desktop
  • "dead world that nobody thought to search anymore" = obsolete OS that nobody remembers

Step 3: Initial Reconnaissance

bash
# Direct flag search — no results
strings img.raw | grep -i "srdnlen"
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

# Checking standard locations
# /root/.bash_history — standard CorelLinux administration commands
# /home/davezero/ — standard user files
# /opt/, /tmp/ — nothing suspicious

Step 4: Discovering the Hidden File

Filesystem timestamp analysis revealed an anomaly:

/var/log/fc.wcm — a file with .wcm extension (Corel WordPerfect macro format), which was the last modified file on the entire filesystem (2026-02-27 22:43:50), modified AFTER the system shutdown at 07:20. This is clearly a file planted by the challenge author. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Thematic connection: "Corel" in the task name points to both CorelLinux (dead OS) and Corel WordPerfect (word processor). The Armourer's "first forge" is a WordPerfect macro hidden in the logs of a dead OS.

Step 5: WordPerfect Macro Analysis

The .wcm file contained a WordPerfect macro with the following structure:

  • Decoy variables: k1=F, k2=A, k3=K, k4=E — applying them produces garbage
  • Hint in the header: "The key is in what is left"
  • Encrypted array docbody[38] — flag data
  • Array rh[24]
  • XOR operation implemented as (bb + kb) - 2*(bb & kb) — mathematically equivalent to a ^ b = (a + b) - 2*(a & b) ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Step 6: Flag Decryption

The flag format srdnlen{ is known (8 bytes), allowing a known-plaintext attack to extract the real 4-byte repeating XOR key:

python
#!/usr/bin/env python3
"""Solve script for The Trilogy of Death Volume I: Corel"""

# Encrypted docbody array from .wcm macro
docbody = [
    206, 56, 30, 170, 209, 42, 0, 142,
    222, 56, 30, 170, 196, 42, 0, 142,
    222, 56, 30, 170, 196, 42, 0, 142,
    # ... (full array from macro, 38 elements)
    206, 56, 30, 170, 209, 42, 0, 142,
    222, 56, 30, 170, 196, 42, 0, 142,
    222, 56, 30, 170, 196, 42, 0, 142,
    222, 56, 30, 170, 196, 42, 0, 142,
    222, 56, 30, 170, 196, 42
]
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

# Known plaintext: "srdnlen{"
known = [ord(c) for c in "srdnlen{"]

# Extract key via XOR with known plaintext
# docbody[i] ^ key[i%4] = plaintext[i]
# => key[i%4] = docbody[i] ^ plaintext[i]
key = [docbody[i] ^ known[i] for i in range(4)]
print(f"Extracted key: {key}")
# key = [189, 74, 108, 238]

# Decoy keys F, A, K, E (70, 65, 75, 69) — "FAKE"!
# The real key is completely different

# Decryption
flag = ''.join(chr(docbody[i] ^ key[i % 4]) for i in range(len(docbody)))
print(f"Flag: {flag}")

The decoy keys F, A, K, E (ASCII: 70, 65, 75, 69) spell out "FAKE" — a red herring. The real key [189, 74, 108, 238] is extracted via known-plaintext attack. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍