polygl0ts

EPFL's CTF team

Hackover CTF 2018: military-crypto

Description

We take security seriously so instead of shipping our own crypto we simply use proven military grade technology for our firmware updates.

nc military-crypto.ctf.hackover.de 1337

Solution

When connecting to the interface we’re presented with a menu:

====================================================
    == secure update service

    we didn't roll our own, powered by the
    best crypto known to humanity
====================================================
1) Update firmware    3) Current firmware
2) Download firmware  4) Quit

Clearly the goal here is to provide a new firmware and a signature to trick the server into running it. So let’s inspect the code of the server and see how the verification is done.

update_firmware() {
   cat <<EOF
====================================================
    1) send update binary as base64
    2) finish with an empty line
    3) send detached signature as base64
    4) finish with an empty line
====================================================
EOF
   echo 'Reading firmware...'
   touch update.bin.b64
   while IFS='' read -r firmware; do
       if [ -z "$firmware" ]; then break; fi
       echo "$firmware" >> update.bin.b64
   done
   base64 -d update.bin.b64 > update.bin
   rm update.bin.b64

   echo 'Reading detatched signaure...'
   touch update.bin.sig
   while IFS='' read -r signature; do
       if [ -z "$signature" ]; then break; fi
       echo "$signature" >> update.bin.sig.b64
   done
   base64 -d update.bin.sig.b64 > update.bin.sig
   rm update.bin.sig.b64

   if ! gpg --verify update.bin.sig; then
       set +x
       echo '!!!!!!!!!!!!!!!!!!!!!!!'
       echo '!! INVALID SIGNATURE !!'
       echo '!!!!!!!!!!!!!!!!!!!!!!!'
       exit 1
   else
       chmod +x update.bin
       echo 'Updating....'
       ./update.bin
       echo 'Rebooting....'
       exit 0
   fi
}

The firmware is verified with gpg --verify update.bin.sig.

From man gpg:

--verify
              Assume that the first argument is a signed file and verify it
              without generating any output.

              ...

              gpg may assume that a single argument is a file with a detached
              signature, and it will try to find a matching data file by
              stripping certain suffixes. Using this historical feature to
              verify a detached signature is strongly discouraged; you should
              always specify the data file explicitly.

It seems that when --verify can both be used to verify signed files (where the contents and the signature are in the same file) and files with a detached signature (where the signature is in a separate file).

The server expects a detached signature for update.bin but if we instead send a self-contained signed message, gpg will think that we’re trying to verify the contents of that file and ignore update.bin. The Current firmware command conveniently sends back exactly that.

For the final exploit we can simply send a shell script that launches /bin/bash as the new firmware and the output of Current firmware as the signature.

Flag: hackover18{r0ll_y0_0wn_crypt0_w1th_pgp}