Emdee five for life Writeup

14 December 2022 #CTF #HTB #chall #easy #misc

First Look

After launching the instance, we have access to a simple web page:

web page of challenge

One quick note: MD5 is actually a hashing algorithm, which is different from an encryption algorithm. 🤓

With that being said, let's do it:

$ echo 5rO1gBWPq6pTRDoxxfwL | md5sum
ebada27ff4b872dcb076cf75304a5e69  -

But when we submit it, it says we are too slow:

too slow!

:(

Automation

We may be too slow, but our computer isn't. That's why we will automate the process using python.

Get random string

The first step is to get the string we have to hash:

import requests

url = 'http://157.245.35.145:31538'

r = requests.get(url)
print(r.text)

Let's execute it:

$ python chall.py
<html>
<head>
<title>emdee five for life</title>
</head>
<body style="background-color:powderblue;">
<h1 align='center'>MD5 encrypt this string</h1><h3 align='center'>NYdJS0qhLeRNznBsNadK</h3><center><form action="" method="post">
<input type="text" name="hash" placeholder="MD5" align='center'></input>
</br>
<input type="submit" value="Submit"></input>
</form></center>
</body>
</html>

As we can see it works, but we just want the random string, not the whole HTML...

We could do some regex magic to extract the string we want but there is a much better (and easier) solution: BeautifulSoup (yeah weird name, I know).

pip install beautifulsoup4 to install it if it isn't already.

Firstly, we should look at the source of the page to see how we'll parse out the random string:

HTML source

It is inside a <h3> tag. That's what we'll use.

Let's update our script:

import requests
from bs4 import BeautifulSoup

url = 'http://157.245.35.145:31538'

# get random string to hash
r = requests.get(url)
soup = BeautifulSoup(r.text, 'html.parser')
to_hash = soup.find('h3').string
print(to_hash)

We feed r.text to BeautifulSoup which is the raw HTML of the response, then we use the find() function to get the first occurence of a <h3> tag. The string attribute contains only what's inside of this tag.

Let's see if it works:

$ python chall.py
9UN0MihEQmpH3y2cXDnJ

It does!

Hash string

The next step is to hash this string. We'll use the hashlib module to do that:

import requests
from bs4 import BeautifulSoup
import hashlib

url = 'http://157.245.35.145:31538'

# get random string to hash
r = requests.get(url)
soup = BeautifulSoup(r.text, 'html.parser')
to_hash = soup.find('h3').string

# use MD5 to hash the string
hashed = hashlib.md5(to_hash.encode()).hexdigest()
print(hashed)

The md5 function wants bytes as parameter, so we encode() the random string first. hexdigest() returns the hexadecimal representation of the hash.

Here we go again:

$ python qwe.py
81ae42a25f0b7f0cd919668ab27b96c7

Nice.

POST hashed string

The final step is to actually send the hashed string to the server and get our well deserved flag.

But before that, we need to know how we should send it. We can once again take a look at the HTML of the page:

form in HTML

Here we see the input field in which we enter the hash has its 'name' attribute set to 'hash'. This value will be used as the parameter name in the POST request.

Let's update our script one more time:

import requests
from bs4 import BeautifulSoup
import hashlib

url = 'http://157.245.35.145:31538'

# get random string to hash
r = requests.get(url)
soup = BeautifulSoup(r.text, 'html.parser')
to_hash = soup.find('h3').string

# use MD5 to hash the string
hashed = hashlib.md5(to_hash.encode()).hexdigest()

# send POST request to submit the hashed string
r = requests.post(url, data={'hash': hashed})
soup = BeautifulSoup(r.text, 'html.parser')
flag = soup.find('p').string
print(flag)

We simply use requests.post to perform the POST request and we specify the 'hash' parameter in data as a dictionary. BeautifulSoup is used again to display the content of the paragraph that says if we are too slow (for fun).

$ python chall.py
Too slow!

What? Too slow? How? If we take a closer look at the website, we can see a cookie is set:

cookie

The random string might be linked to the session (and the cookie, by extension) so we need to use the same as the one we got with the first request (just a wild guess, I don't actually know).

We can use requests.session() to take care of that (it will send the cookie for us).

We'll edit the script one last time (i swear):

import requests
from bs4 import BeautifulSoup
import hashlib

url = 'http://157.245.35.145:31538'
s = requests.session()

# get random string to hash
r = s.get(url)  # start a session
soup = BeautifulSoup(r.text, 'html.parser')
to_hash = soup.find('h3').string

# use MD5 to hash the string
hashed = hashlib.md5(to_hash.encode()).hexdigest()

# send POST request to submit the hashed string
r = s.post(url, data={'hash': hashed})  # reuse the existing session
soup = BeautifulSoup(r.text, 'html.parser')
flag = soup.find('p').string
print(flag)

We just replaced requests.get and requests.post by s.get and s.post to use our session object.

This time we should be good:

$ python chall.py
HTB{N1c3_ScrIpt1nG_B0i!}

Key Takeaways