Emdee five for life is a bit old and easy challenge but still useful to earn some scripting skills.
In short: the challenge serve a website which tells you to md5 encrypt the given string.
Although it seems easy, when you submit the hash the website responses “too slow!”.
So in order to make it fast you’ll need to use kind of automation to scrape the string, compute his MD5 hash and submit it.
Note: There are more than one method to solve this challenge.
I chose to use python sockets.
Getting started
When getting into the website, there is given string and expected to get his md5 hash:
When attempting to submit the hash the website response “Too slow!”:
So in order to make it faster, I used Python to create a script that scraped the string from the website, computed his MD5 hash, and submitted it.
Creating the python script
Let’s get into the python script:
Packages
#!/bin/python3
import re
import hashlib
import socket
To solve this lab I used 3 python packages :re
— useful to extract certain strings from text using regex.hashlib
— to compute the md5 hash with the given string.socket
— Used to communicate with the web server via HTTP
Socket
host = '209.97.140.29'
port = 30032
socket_connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_connection.connect((host,port))
socket.socket()
is a function that creates new socket object.
The arguments that socket.socket
receives are constants used to specify the address family and socket type:
AF_INET
is the internet address family for IPv4.SOCK_STREAM
means the socket will transport the messages over the transport layer protocol TCP.
socket_connection.connect
is the function to establish the TCP connection to the target and initiate the three-way handshake.
three-way handshake
This Photo demonstrate socket TCP connection to the challenge web server using sniffing tool called Wireshark, on the right side of each packet you can see the flags:
[SYN] , [SYN, ACK] , [ACK]
GET Request
Now we are ready to send our GET request:
# Sending the GET request
get_request = (
f"GET / HTTP/1.1\r\n"
f"Host: {host}\r\n"
f"\r\n"
)
socket_connection.send(get_request.encode())
The request is formatted according to the HTTP/1.1 protocol, specifying the method GET and the version of the HTTP protocol.
The get_request
string is encoded using the encode()
method to convert it into bytes.
response = socket_connection.recv(4096).decode()
This line receives data up to 4096 bytes which is the maximum amount of data (in bytes) that the recv
method attempts to receive from the socket in a single call and decodes it using the decode()
method.
Extracting the string from the response
After getting the response we will need to extract the PHP Session cookie and the string for the hash.
Looking on the GET response:
Understanding the GET response structure can help building the regex to extract the PHPSESSID
and the string to hash.
# Extracting the string and the cookie from the get response using regex
try:
cookie = re.search('PHPSESSID=(.*);',response).group(1)
string_to_hash = re.search('<h3 align=\'center\'>(.*)</h3>',response).group(1)
except:
print('[-] Failed')
exit()
The purpose of the regex expression is to capture the substring between two specified strings:
(.*)
: This capturing group matches any sequence of characters.group(1)
: Refers to the first parenthesized subgroup.
The following expressions are used:
re.findall('PHPSESSID=(.*);', response).group(1)
to extract the PHPSESSID Cookie for use in the subsequent request.re.findall('<h3 align=\'center\'>(.*)</h3>', response).group(1)
to extract the specified string.
String to MD5 hash
# Hashing the string
print('[+] Computing the hash..')
hash = hashlib.md5(string_to_hash.encode('utf-8')).hexdigest()
print(f'[+] String encrypted: {string_to_hash} ---> {hash}')
This code used to compute the MD5 hash of the string.
POST Request
We have everything we need we just need to send the post request and grab the flag from the response.
# Preparingthe POST request
body = f"hash={hash}".encode()
post_request = (
f"POST / HTTP/1.1\r\n"
f"Host: {host}\r\n"
f"Cookie: PHPSESSID={cookie}\r\n"
f"Content-Type: application/x-www-form-urlencoded\r\n"
f"Content-Length: {len(body)}\r\n"
f"\r\n"
)
In this snippet, the POST request is constructed:
- Body: The request body is prepared before the headers to calculate its length.
- Cookie: The PHP Session cookie is included in the request header.
- Content-Type: Specifies the form content as
application/x-www-form-urlencoded
. - Content-Length: Specifies the length of the created body.
# Sending the POST request
print(f'[+] Sending the MD5 Hash - {hash}')
socket_connection.send(post_request.encode() + body)
response = socket_connection.recv(4096).decode()
The combined request is sent to the server using send
.
Like before, getting the response using recv
and decoding the response using decode
.
Extracting the flag
flag = re.search('HTB{(.*)}',response).group(0)
if flag:
print(f'[+] Success - {flag}')
else:
print('[-] Failed')
After getting the response of the web server we can extract the flag with the similar regex expression as mention before, but instead of using group(1)
used group(0)
to get the entire match.
Closing the socket
socket_connection.close()
Running the complete script
chmod +x Emdee_five_for_life.py
./Emdee_five_for_life.py
Got the Flag!
Final script
The final script to solve this challenge:
Thanks for reading :)