Skip to content

Headless Horseman - Buckeye CTF 2021

Published:

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:

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 PartsArchitecture (32 bit)Input CheckDecryption SchemeFlag Part
moldy_head_bloated_body.corpseMIPSEnter string “GUNPOWDER”Base64 decodeflag{the_horseman_just_
dessicated_head_decomposing_body.corpseARM-XOR against “Sleepy Hollow”really_loves_
shrunken_head_rotting_body.corpseIntelIntentionally overflow integer checkAdd bytes against keypumpkin_pie}

Flag: flag{the_horseman_just_really_loves_pumpkin_pie}


Next Post
bcactf 2021