Hello hackers! Today we'll cover a quick and fun scripting challenge using python. This is the first challenge on the Intro to Dante track on Hack The Box which is described as:
"Practice machines and challenges to help you prepare for the Dante Pro Lab."
Introduction
For this challenge, we're met with a website that presents us with a prompt and field. The field says "MD5" in it, suggesting that we're expected to submit the MD5 hash version of the text.
Methodology:
I looked up an MD5 hash generator website to complete the challenge. I inputted the string, copied the hash, and I was met with an unfavorable response:
The site changed the text provided and told me I was "Too slow!". Since I didn't appreciate it's teasing, I decided to boost my speed with a bespoke solution to this challenge.
Identifying the template
First, I need to see what a normal raw response looks like from this server, so I'm able to parse out the relevant data, hash it, and submit a response programmatically. For that reason, I don't think burp suite will help me here, as it won't give me a view of how it needs to be parsed. I think python will get the job done well.
Grabbing the response
I opened up the greatest editor of all time and wrote:
import requests
response = requests.get('http://134.209.176.83:30536') # change this for your instance!
print(response.content)
It's extremely simple, but it did the trick. Running this code gave me a response like the following:
b'<html>\n<head>\n<title>emdee five for life</title>\n</head>\n<body style="background-color:powderblue;">\n<h1 align=\'center\'>MD5 encrypt this string</h1><h3 align=\'center\'>c3WOTbjAmW4hFDHQpCjZ</h3><center><form action="" method="post">\n<input type="text" name="hash" placeholder="MD5" align=\'center\'></input>\n</br>\n<input type="submit" value="Submit"></input>\n</form></center>\n</body>\n</html>\n'
I ran it a few more times to make sure I had a good understanding of the format.
Great! Now all I need to do is pluck out the relevant information in the response.
Parsing the output
I tried parsing the output using classic python methods like .split()
, but I ran into the following.
TypeError: byte indices must be integers or slices, not str
Turns out this was still raw bytes, instead of a proper string type.
The following update to my code fixed this issue:
import requests
response = requests.get('http://134.209.176.83:30536')
res = response.content
res = res.decode('utf-8')
print(res)
Now our output is a properly formatted string:
<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'>pV0iSaxkboFU0E07UayP</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>
Grabbing specific output
Now it's time to shave our output down to only the text we need. We can use any parsing method, but I found This stack overflow answer to be most helpful.
import requests
response = requests.get('http://104.248.160.75:31480')
res = response.content
res = res.decode('utf-8')
mystr = res
search = "3 align='center'>"
start = mystr.index(search)+len(search)
stop = mystr.index("</h3>", start)
res = (mystr [ start : stop ])
print(res)
Now we have the raw "word."
Now let's hash it!
Hashing the word
According to stack overflow, we can use the following lines to make an MD5 hash of the word:
import hashlib
print(hashlib.md5(res.encode('utf-8')).hexdigest())
Using the following code should yield a valid MD5 hash:
import requests
import hashlib
response = requests.get('http://178.128.167.10:31790')
res = response.content
res = res.decode('utf-8')
mystr = res
search = "3 align='center'>"
start = mystr.index(search)+len(search)
stop = mystr.index("</h3>", start)
res = (mystr [ start : stop ])
print(res)
print("MD5 version:")
print(hashlib.md5(res.encode('utf-8')).hexdigest())
Output should look something like this:
fJHiQK1isKuPYxbEulUH
MD5 version:
80ed60f85b4fbbc982b5816912b1ba6a
Don't forget! We can always verify the validity with an online tool:
That looks correct! now, we can focus on sending the hashed message back to the server!
Sending the hash
In the original response, we saw that the HTML field name was called "hash" so we'll use that field name to submit our response. After a bit of reading, the syntax became extremely straightforward for the requests
library. We just need a dictionary to hold our data and submit our response. With that added, our code now looks like the following:
import requests
import hashlib
# Grabbing and decoding
url = 'http://178.128.167.10:31790'
response = requests.get(url)
res = response.content
res = res.decode('utf-8')
# Parsing out the word
mystr = res
search = "3 align='center'>"
start = mystr.index(search)+len(search)
stop = mystr.index("</h3>", start)
res = (mystr [ start : stop ])
print(res)
# Hashing as MD5
print("MD5 version:")
hash = (hashlib.md5(res.encode('utf-8')).hexdigest())
print(hash)
# Sending the hash
payload = {"hash":hash}
response = requests.post(url, data=payload)
res = response.content
flag = res.decode('utf-8')
print("\n\n" + flag)
Everything looks ready to use, so let's run it!
Output:
Our flag... Or not?
LSByV3cfj4CH7ufR5G2a
MD5 version:
46b323c4923e460759346454210adb8f
<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'>OLWB7P9EqGd03jHmmXRN</h3><p align='center'>Too slow!</p><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>
It seems we're too slow.
I thought we'd be fast enough, but maybe our code was too inefficient. We'll have to find a way to speed it up, but first we'll need to find out how fast we currently are!
Clocking our code
Let's see how fast our code is running.
We can use the time
command to clock it
time python3 payload.py
yields us:
real 0m0.690s
user 0m0.173s
sys 0m0.017s
Why it didn't work:
After reading a blog post about this challenge, I found out why this wouldn't work properly:
Knowing this, I rewrote my code to use a single coherent session
rather than sending random disjointed requests.
Our code now looks like this:
import requests
import hashlib
# Grabbing and decoding
url = 'http://161.35.166.224:32511'
session = requests.session()
response = session.get(url)
res = response.content
res = res.decode('utf-8')
# Parsing out the word
mystr = res
search = "3 align='center'>"
start = mystr.index(search)+len(search)
stop = mystr.index("</h3>", start)
res = (mystr [ start : stop ])
print(res)
# Hashing as MD5
print("MD5 version:")
hash = (hashlib.md5(res.encode('utf-8')).hexdigest())
print(hash)
# Sending the hash
payload = {"hash":hash}
response = session.post(url, data=payload)
res = response.content
flag = res.decode('utf-8')
print("\n\n" + flag)
Only a few small changes, but it made a huge difference!
Output:
C7RrJ4GN4f2tMK51Z8JZ
MD5 version:
d185f72466f92c697b6c9ed3ca496ebe
<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'>C7RrJ4GN4f2tMK51Z8JZ</h3><p align='center'>HTB{N1c3_ScrIpt1nG_B0i!}</p><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>
Lessons learned
It's times like this that remind me that it's okay to use writeups, even the best people in the field do it to learn!. If I hadn't have stopped and read a writeup, I wouldn't have understood why I needed to use requests.session()
, and I wouldn't have been able to progress. It's easy to get frustrated while learning new things, but there's no point in staying frustrated if you're stuck.
Thanks for reading! Be sure to come back to read my writeup on "Heist"!
Top comments (0)