The goal
I always wanted to learn how to use requests
library in Python3. It’s very helpful in daily life or in CTF…
And actually, there is EuropeanCyberWeek
CTF, so let’s try to do something useful: Auto flag submitter
State of the art
First of all, I need the requests structure, to get this information, just open BurpSuite
(if you’re a bit stupid like me), or you’re Firefox web console
and request the chosen challenge (Drone Wars 3
for example).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| POST /chal/19 HTTP/1.1
Host: challenge-ecw.fr
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://challenge-ecw.fr/challenges
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 143
Cookie: session=<JSON Web Token>
Connection: close
key=test&nonce=a36e189c9edf96b7ff561b1dc65bf6e0715af51eb5cb46f36a63d45c57665a24859242501669a17cac47eec04e1dc4e3f1646abd028d32a4e629929f1d0e816d
|
We have few interesting things:
- Request: challenge-ecw.fr/chal/19
- URL:
https://challenge-ecw.fr/challenges#DroneWars%20(3/3)
- Cookie: JSON Web Token
- key: The submitted flag (here is
test
) - nonce: Random number to avoid CSRF vulnerability
Python requests
Ok, now we know how to do our script. Start to install the desired library:
1
| $ pip install --user Requests
|
Initialize a Session()
object, this object will get all headers and after you can do GET
or POST
requests normally.
I had to do a little trick to get the nonce
random:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| >>> import requests
>>> import re
>>> s = requests.Session()
>>> cookie = {'session':'.eJwNz0FrgzAUwPGv[...]52miEJF5lBEfaqEd1dHs'}
>>> url = 'https://challenge-ecw.fr/challenges#DroneWars%20(3/3)'
>>> html = s.get(url, cookies=cookie).text.split('\n')
>>> for i in html:
>>> if re.search('nonce', i):
>>> nonce=i.split('=')[4][:-1]
>>> print(nonce)
36e189c9edf96b7ff561b1dc65bf6e0715af51eb5cb46f36a63d45c57665a24859242501669a17cac47eec04e1dc4e3f1646abd028d32a4e629929f1d0e816d
|
It works! Now we just have to do a little POST
requests with our key
and nonce
.
1
2
3
4
5
6
| >>> data = {'key':'ECW{Bite de poulet}', 'nonce':nonce}
>>> print(s.post('https://challenge-ecw.fr/chal/19', cookies=cookie, data=data).text)
{
"status": "2",
"message": "Incorrect."
}
|
I flagged a challenge to see if the message was different, and it was. Instead of “Incorrect”, you got “Correct” (CTFd
guys are very smart :D).
Full code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
| #!/usr/bin/python3
import requests
import re
import time
s = requests.Session()
cookie = {'session':'.eJwNz0FrgzAUwP[...]JF5lBEfaqEd1dHs'}
url = 'https://challenge-ecw.fr/challenges#DroneWars%20(3/3)'
html = s.get(url, cookies=cookie).text.split('\n')
for i in html:
if re.search('nonce', i):
nonce=i.split('=')[4][:-1]
data = {'key':'ECW{Bite de poulet}', 'nonce':nonce}
g = open('counter.txt', 'r')
j = int(g.read().split('\n')[0])
g.close()
while(1):
coucou = s.post('https://challenge-ecw.fr/chal/19', cookies=cookie, data=data)
nope = coucou.text
if nope.split('"')[7] == "Incorrect":
j = j+1
f = open('counter.txt', 'w')
f.write(str(j)+'\n')
f.write(str(nope))
f.close()
else:
f = open('counter.txt', 'a')
f.write(str(nope))
f.close()
exit()
time.sleep(600)
|
I know, mine has more features… But I got a new status
:O
1
2
3
4
5
| $ ./coucou.py
{
"status": "3",
"message": "You are banned."
}
|
Maybe the flag was ECW{MD5(Bite de poulet)}
…
Conclusion
To conclude this little blog post, from a personal point of view, I found ECW CTF
boring. CTF are used to learn things, useful or not, nevermind. Here, we have guessing and bruteforce challenge…
Well, I’m actually banned, have fun. But don’t overuse my little spammer, try to be eligible for the final it’s really interesting, I did it last year (2017).
Thanks reading this, take care of yourself <3