Skip to content

Latest commit

 

History

History
116 lines (65 loc) · 3.96 KB

hack.lu-ctf-2019.md

File metadata and controls

116 lines (65 loc) · 3.96 KB
description
Deutschland CTF ist hardt.

Hack.lu CTF 2019

Foreword

We were still in 3rd place (eligible for prize) 30 minutes before the contest ended

But life sucks, WE_0WN_YOU surpassed us with 300pts. Fuck it. If I could solve this challenge (482pts) then we would have the prize.

But there is no such thing as magic in life.

And I want to thank organizer for keep hosting such a great CTF. Hack.lu is awesome as always!

Gambling Future

We were given a link and a Rust binary file.

Even though the challenge was rated easy, but there are only 8 teams solved it during 48 hours.

The link was lead us to the site where we can submit a number and the server will check if it's matched with the one that generated by the server. If it's matched, then server will give you the flag

So it seems that we have to find out the generated value. Now it's time to take a look at the Rust binary

Firstly, the program try to bind to 127.0.0.1 at port 8080 and wait for incoming connection. If there is incoming connection, it then create a new thread to handle. So basically, this is multi-thread tcp server

First, no matter what is your request method, it will always return an custom constant response header.

Then it will check for request method, it only accept two method : GET and POST. If your request is a GET request, it will return a html page as above. If it's not GET method, then it gonna check if the request method is POST. If the method request is not GET or POST, it will return "Error method not allowed..." and call begin_panic(). If it's POST request, it will generate a random number by calling rand::random() and later on, this number will be compared with our input number

****Quickly skip through hundred lines of parsing and converting, we easily realize that it will compare that randomly generated number with our input number.

So it's pure random. We have to find another bug.

Then during the CTF, we was tried to take a look at Rust's random book (https://rust-random.github.io/book/) and other stuff but no luck. And then @sae realize when you make a post request with netcat to the server, it will return immediately the number that was generated.

Few days after contest ended, I decided to take a look at it again. I decided to read carefully few hundreds line that I have skipped through. And then I realize the server parse the Content-length in request header

Basically, the server will wait until it read exact the length defined in Content-length. So, we just have to define the Content-length to make the server wait for us to fill the request's body. But before the server stop and wait for us, it already sent us the generated number. That's the bug here.

{% code title="solver.py" %}

import socket
import time
import re

TCP_IP = '31.22.123.49'
TCP_PORT = 1905
BUFFER_SIZE = 5000


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send('''POST / HTTP/1.1
Host: 31.22.123.49:1905
Content-Length: 26

''')
print s.recv(2048)
data = s.recv(2048)
print data

guessed_num = re.findall(r'\d\d+', data)[0]
print guessed_num

s.send("guess=" + guessed_num)

print s.recv(2048)

print s.recv(2048)

s.close()

{% endcode %}

And we finally got the flag

flag{im_not_addicted_im_patient}