CodeFest CTF 2017 - Ricks’ Secure Scheme Writeupby
September 23, 2017
Capture United States - Ricks’ Secure Scheme
The schwifty_service that runs under the port 10987 of the addressed server presents us a menu interface with some options given:
1. Login with the password (*) 2. View the secret contents (#). 3. View the usage logs. 4. Exit. * => It’s theoretically impossible that you can login # => Requires login.
To view the secret content we must login first.
At first let’s search the login procedure in IDA Pro. Decompiling the code in the only function called by main, we can find:
So let’s go have a look at
This function looks like a decryption function! We can notice that it initializes the random seed with
time() and then xores the first 34 chars of the password with the random value obtained each time with
The decrypted password is then passed to the
strncmp function, against the bytes at address 400E60
At that address there are
bytes = [0x33, 0x12, 0x46, 0x67, 0xF6, 0x2B, 0x5A, 0x2E, 0x5B, 0x7E, 0xD6, 0xF7, 0xA2, 0x33, 0xD5, 0x7A, 0x87, 0x39, 0x5F, 0x92, 0x73, 0xF5, 0xB1, 0xA5, 0x81, 0xB0, 0x6A, 0x84, 0x38, 0xCD, 0x9B, 0xEA, 0x99, 0xDA] followed by the string
'Welcome to my...\x00'
So how can we pass the check? If we could obtain the same seed and then xor the
bytes with the same pseudo-random sequence, then we will have a string, that, when re-xored in the function, will produce the original bytes!
time() function has a granularity of 1 second, so we have this whole second to compute the string and pass it to the server.
Let’s make a script:
from pwn import * import ctypes import hashlib libc = ctypes.CDLL("libc.so.6") passwd = [0x33, 0x12, 0x46, 0x67, 0xF6, 0x2B, 0x5A, 0x2E, 0x5B, 0x7E, 0xD6, 0xF7, 0xA2, 0x33, 0xD5, 0x7A, 0x87, 0x39, 0x5F, 0x92, 0x73, 0xF5, 0xB1, 0xA5, 0x81, 0xB0, 0x6A, 0x84, 0x38, 0xCD, 0x9B, 0xEA, 0x99, 0xDA] def genPassword(time): libc.srand(time) s = "" for i in xrange(34): s += chr(passwd[i] ^ (libc.rand() % 255)) return s s = genPassword(1505768803) + 'Welcome to my...\x00' print s quit() #p = process("./schwifty_service") p = remote("18.104.22.168",10987) while True: print p.readuntil("Requires login."); p.sendline("1") print p.readuntil("Enter the password: "); s = genPassword(libc.time(0)) s+= 'Welcome to my...\x00' #REMEMBER TO CONCATENATE THE REST OF THE STRING p.sendline(s) print " password sended", s l = p.readline() print l if l == "I told you you couldn't login!\n": continue break p.interactive()
import ctypes we are sure that we are using the same implementation of
rand() as the libc to get the same sequence.
Let’s run it, and… It works!
What?!?!?! How?!!!! Anyway, you've successfully logged in!
Printing the secret will give us an epoch integer, and the md5 of that integer will give us the flag!