PlaidCTF 2017 - SHA-4

I heard SHA-1 is broken, so I think it’s probably time we move to SHA-4.

Writeup

This challenge provided two forms, one which allowed to post comments and a textarea which parses an hex encoded, ans1 enveloped input.

Solution tl;dr

local file read, hash collision, template injection, race condition

Directory Traversal

It is trivial to find a directory traversal by using the file:// uri scheme instead of the intended http:// or https:// ones. Once we obtain file-reading access, we can find the directory of the python webapp /var/www/sha4 by getting the system version from file:///etc/issue and the cmdline from file:///proc/self/cmdline.

Template Injection

Since the webapp uses Flask, we can grab the code needed from Exploring SSTI in flask which hashes the following requirements to achieve Command Execution:

upload a python reverse shell payload

inject {{config.from_pyfile('/var/tmp/comments/<hash>.file')}} in the render_template() function

The first part is simple, we just need to upload the file using the upload form and calculate its path with the sha4 function.
The second part is the hard one.
If we take a closer look at the comments() function we can notice there’s something a little unusual: why would the programmer write the input to disk, check if it’s safe and read it back? It is already in the out_text variable!

This seems coded to purposely create a race condition situation and make the challenge solvable.
So basically, to exploit the template injection we need to:

find a sha4 hash collision between two ASN.1 encoded strings: one containing {{config.from_pyfile('/var/tmp/comments/<hash>.file')}} and a safe one (which means without {} and /)

send both requests as fast as we can to have enough luck to exploit the race condition by overwriting the file /var/tmp/comments/<collided hash>.txt with the malicious payload while the script has passed the is_unsafe() check on the safe payload

Collision!

We find out that finding a collision is pretty easy.
For every char there is a colliding one for each position in the DES key (see sha4.py file).

We then calculate each colliding char for each forbidden char ({}/) with this small snippet

Finally, the Flag

Once we have the colliding payloads we just have to send both requests as fast as we can, possibly using multiple threads; so from a server with a fast connection we can simply open multiple tmux sessions, running one of the following command in each