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 :)


References