CTF
Search…
Hack.lu CTF 2019
Deutschland CTF ist hardt.

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.
solver.py
1
import socket
2
import time
3
import re
4
5
TCP_IP = '31.22.123.49'
6
TCP_PORT = 1905
7
BUFFER_SIZE = 5000
8
9
10
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
11
s.connect((TCP_IP, TCP_PORT))
12
s.send('''POST / HTTP/1.1
13
Host: 31.22.123.49:1905
14
Content-Length: 26
15
16
''')
17
print s.recv(2048)
18
data = s.recv(2048)
19
print data
20
21
guessed_num = re.findall(r'\d\d+', data)[0]
22
print guessed_num
23
24
s.send("guess=" + guessed_num)
25
26
print s.recv(2048)
27
28
print s.recv(2048)
29
30
s.close()
Copied!
And we finally got the flag
1
flag{im_not_addicted_im_patient}
Copied!
Last modified 2yr ago
Copy link