Headless Horseman - Buckeye CTF 2021
I only had a go at the rev challenge headless_horseman
.
We’re originally given an ELF called headless_horseman
and three files that have something to do with bodies. They look like ELF
files also, with the header missing…
headless_horseman
runs and will decrypt extra files for us if we’re able to provide a correct number, one that satisfies the following requirements:
(x & 0xFFFF0000) >> 16 == 0xDEAD
x << 16 == 0xFACE0000
Thus, x
== 0xDEADFACE
, or 3735943886.
After receiving the correct number it decrypts 6 “heads”, and implies that we should figure out which bodies to stitch them to. I stitched every head to every body and ran ls | xargs -n1 file
dessicated_head_bloated_body.corpse: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, too large section header offset 546785024
dessicated_head_decomposing_body.corpse: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, BuildID[sha1]=c96a5a55d131a48d6e034236330d1925e890f360, for GNU/Linux 3.2.0, not stripped
dessicated_head_rotting_body.corpse: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, missing section headers
...
From the output you can see that file
knows when an ELF is malformed. Just search for any lines without errors…
We end up with
dessicated_head_decomposing_body.corpse: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, BuildID[sha1]=c96a5a55d131a48d6e034236330d1925e890f360, for GNU/Linux 3.2.0, not stripped
moldy_head_bloated_body.corpse: ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), statically linked, BuildID[sha1]=fb3ef826027d1a22e0926cd609bc9453dab03662, for GNU/Linux 3.2.0, not stripped
shrunken_head_rotting_body.corpse: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=46ee2457ce9871242b7ad74249a3a19091cd0c52, for GNU/Linux 3.2.0, not stripped
Note the different architectures…
Each binary asks for some input as verification I’ve reversed it, and then prints a third of the flag. Other than in the ARM binary the input check doesn’t have any effect on the decryption scheme, just whether it’s called. Each decryption is reasonably straight forward so it can all be done statically (sorry QEMU).
File Parts | Architecture (32 bit) | Input Check | Decryption Scheme | Flag Part |
---|---|---|---|---|
moldy_head_bloated_body.corpse | MIPS | Enter string “GUNPOWDER” | Base64 decode | flag{the_horseman_just_ |
dessicated_head_decomposing_body.corpse | ARM | - | XOR against “Sleepy Hollow” | really_loves_ |
shrunken_head_rotting_body.corpse | Intel | Intentionally overflow integer check | Add bytes against key | pumpkin_pie} |
Flag: flag{the_horseman_just_really_loves_pumpkin_pie}