← Back to Writeups
HTBEasyForensics

Unfinished File

D3v0o0Nu119/2/20263 min read
#forensics#htb#easy#crdl_file_format_analysis#embedded_zip_extraction#single_byte_xor_known_plaintex

Unfinished File

Platform: Tjctf | Category: Forensics | Type: Challenge | Difficulty: Easy | OS: NA | Author: D3v0o0Nu11 | Date: 2026-05-16 | Status: Solved Techniques: crdl_file_format_analysis, embedded_zip_extraction, single_byte_xor_known_plaintext

Summary

Task: analyze a Chrome .crdownload incomplete download file containing embedded data. Solution: extract embedded ZIP archive, recover XOR-encrypted flag using known-plaintext attack with flag prefix.

Recon

Port scan

bash
nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
PortServiceVersionNotes
<PORT><SVC><VER><notes>

Enumeration highlights

  • Event: tjctf | ID: 20260516_tjctf_unfinished_file
  • Tags: zip, known_plaintext, xor, file_format, crdownload, single_byte_xor, chrome_download
  • Indicators: crdownload file extension (Chrome incomplete download), CRDL magic bytes at file start, embedded PK (ZIP) signature inside binary blob, XOR-encrypted data with known flag prefix enabling key recovery, small file size suggesting manual analysis over automated tools
  • Source: 20260516_tjctf_unfinished_file.md

Foothold

Vulnerability / Misconfiguration

  1. crdl_file_format_analysis
  2. embedded_zip_extraction
  3. single_byte_xor_known_plaintext
bash
<command>

Exploitation

  • See original writeup content for detailed exploitation.

Privilege Escalation

Enumeration

bash
sudo -l
find / -perm -4000 2>/dev/null
getcap -r / 2>/dev/null
cat /etc/crontab
ps aux

Exploitation

  1. N/A for challenge-type writeup; see exploitation above.
  2. Flag obtained via challenge solve.
bash
<command>

Flags

FlagLocationValue
flagREDACTED

Key Takeaways / Lessons

  • crdl_file_format_analysis
  • embedded_zip_extraction
  • single_byte_xor_known_plaintext
  • Tags: zip, known_plaintext, xor, file_format, crdownload, single_byte_xor, chrome_download

Original Writeup

<details><summary>Click to expand original content</summary>

Description

"my stupid friend tried downloading this file before i shut my laptop down, what was he trying to do?"

Attachment: secret_archive.zip.crdownload (463 bytes) — a Chrome incomplete download file.

Analysis

The .crdownload extension is Chrome's format for incomplete downloads. At only 463 bytes, this file is small enough for manual binary analysis.

Examining the file structure revealed three distinct regions:

  1. CRDL header (offset 0x00): Magic bytes CRDL, version info, and the source URL https://example.com/secret_archive.zip
  2. XOR-encrypted blob (offset 0x47): Encoded data with preceding control characters
  3. Embedded ZIP archive (offset 0x100): Standard PK signature (ZIP magic bytes)

The embedded ZIP contained two files:

  • readme.txt — decoy text: "This file is incomplete. Keep looking..."
  • hidden/.flagdata — 47 bytes of XOR-encrypted data

The .flagdata hex content:

36 28 21 36 24 39 2c 71 34 71 30 1d 2e 71 36 1d
72 36 2a 27 30 1d 32 71 72 32 2e 27 1d 36 72 37
21 2a 1d 37 30 1d 21 72 2f 32 37 36 27 30 3f

Solution

Known-plaintext attack on single-byte XOR

The flag format tjctf{ provides 6 known plaintext bytes. XORing the first encrypted byte with the expected plaintext reveals the key:

0x36 ^ 0x74 ('t') = 0x42 ('B')

Verifying against all 6 prefix bytes:

EncryptedExpectedXOR result
0x36t (0x74)0x42 ✓
0x28j (0x6A)0x42 ✓
0x21c (0x63)0x42 ✓
0x36t (0x74)0x42 ✓
0x24f (0x66)0x42 ✓
0x39{ (0x7B)0x42 ✓

All 6 bytes produce the same key 0x42 — confirmed single-byte XOR with key B.

Decryption

python
#!/usr/bin/env python3
data = bytes.fromhex(
    '3628213624392c71347130'
    '1d2e71361d72362a2730'
    '1d3271723227'
    '1d36723721'
    '2a1d37301d2172'
    '2f323736273'
    '03f'
)

# Cleaner version with exact bytes
data = bytes([
    0x36, 0x28, 0x21, 0x36, 0x24, 0x39, 0x2c, 0x71,
    0x34, 0x71, 0x30, 0x1d, 0x2e, 0x71, 0x36, 0x1d,
    0x72, 0x36, 0x2a, 0x27, 0x30, 0x1d, 0x32, 0x71,
    0x72, 0x32, 0x2e, 0x27, 0x1d, 0x36, 0x72, 0x37,
    0x21, 0x2a, 0x1d, 0x37, 0x30, 0x1d, 0x21, 0x72,
    0x2f, 0x32, 0x37, 0x36, 0x27, 0x30, 0x3f
])

key = 0x42
flag = ''.join(chr(b ^ key) for b in data)
print(flag)
# tjctf{REDACTED}
</details>

signed by XESXOR