FlareOn13.doc

  • Category: rev

“As part of our testing protocols, we need to assess your level of stress when examining a simple document file.”

flareon13.doc is not a document — it is a six-way polyglot. The same bytes parse simultaneously as a DOS COM executable, a PDF, a raw 2352-byte-per-sector CD image (with UDF inside), a Mach-O fat binary, a ZIP archive, and a fixed-size VHD. Each container hides one phrase, and a Mach-O slice buried in the file is the checker: it wants all six phrases as argv, validates each by MD5, and only then decrypts the flag. The “stress test” is that every layer is a different file-format rabbit hole.

Solution

1. Enumerate the containers

Carving the file apart, the interesting fat Mach-O has two arm64 slices: an Odin slice and a Crystal slice (click_me, cpusubtype 3). The Crystal slice is the real gatekeeper — it reads six command-line arguments, MD5s each, compares against a stored set of six digests (kept at 0x100035e30 as 0x80 | nibble values), and if all six match, RC4-decrypts the ciphertext at 0x100035ef0. The RC4 key is the XOR of SHA-256(phrase) across all six phrases. So the whole challenge reduces to recovering the six phrases from the other five containers plus the Odin slice.

2. Phrase 1 — the COM stub (EICAR)

The file’s very start is a runnable DOS COM stub: a self-patching variant of the EICAR antivirus test string. Executed, it prints FLARE-STANDARD-ANTIVIRUS-TEST-FILE! — phrase one.

3. Phrases 2 & 3 — inside the PDF

The PDF layer is RC4-40 encrypted with an empty user password, so it opens without a prompt. Two things are hidden in it:

  • Invisible text rendered in EBCDIC cp037, which decodes to mainframe_ebcdic_ghost.
  • An off-page JBIG2 image (the fax-compression codec), giving jbig2_fax_geometry.
4. Phrase 4 — the CD image / UDF

Treated as a raw 2352-byte/sector CD-ROM image, the file contains a UDF filesystem. The phrase lives in the Implementation Use Volume Descriptor’s LVInfo2 field: udf_tagged_descriptor.

5. Phrase 5 — the ZIP (Reduce, not Deflate)

The ZIP’s flag.txt is protected with legacy ZipCrypto and, unusually, compressed with PKZIP Reduce rather than Deflate — which is itself the hint (reduce_not_deflate). ZipCrypto falls to a known-plaintext attack with [bkcrack]; the Reduce format’s fixed follower-set table (all-zero here) serves as the known plaintext to recover the keys and extract the phrase reduce_not_deflate.

6. Phrase 6 — the Odin slice

The other Mach-O slice is an Odin-language binary. Its status-line text is hashed/XORed before display; reversing that step yields Ødin_373rn4l_fl4r3 (bytes \xc3\x98d1n_373rn4l_fl4r3).

7. Derive the key and decrypt

With all six phrases in hand, confirm them against the stored MD5 set, build the RC4 key as the XOR of their SHA-256 digests, and decrypt:

PHRASES = [
    b"FLARE-STANDARD-ANTIVIRUS-TEST-FILE!",
    b"mainframe_ebcdic_ghost",
    b"jbig2_fax_geometry",
    b"udf_tagged_descriptor",
    b"reduce_not_deflate",
    b"\xc3\x98d1n_373rn4l_fl4r3",
]
key = bytearray(32)
for p in PHRASES:
    for i, b in enumerate(hashlib.sha256(p).digest()):
        key[i] ^= b
# standard RC4 over the 40-byte ciphertext with `key`

Full script (with the MD5 check and ciphertext): solve.py.

Flag: Ju$7_4_l177l3_7r34$ur3_HUN7@flare-on.com