OverTheWire - Narnia Writeups

Narnia: Level 0 Writeup​

ssh [email protected] -p 2226
password: narnia0

Narnia içerisinde bulunan sorulara erişmek için /narnia dizinine gitmemiz gerekmektedir…

b1cac7ac309e6127275c599db12089ad7b839234.png


İlgili dizine geldiğimiz zaman tüm soruların C kodlarını ve derlenmiş hallerini burda görebiliyoruz.

Madem kodlarını görmemize müsade etmişler o zaman inceleyelim bakalım bizi neler bekliyormuş :)

code


Hmm klasik stack tabanlı buffer overflow zafiyeti var gibi gözüküyor. Bilmeyen arkadaşlar için olayı kısaca anlatacak olursak eğer local bir değişkenimiz var ve bunun içerisinde 0x41414141 yazmakta. Ayrıca bir adette 20 karakter uzunluğunda bir buffer alanı var. Bizden istediği şey ise bu 20 karakterlik buffer alanını taşırarak 0x41414141 değerini 0xdeadbeef olarak güncellememiz. Eğer bu şekilde değiştirebilirsek eğer bize narnia1 kullanıcı olarak bir shell açacağını söylemiş.

Evet temel olarak bu şekilde işte. Hemen deneme amaçlı birşeyler girelim programımıza

1


Gördüğünüz üzere 20 karakterlik buffer alanını A karakterleri ile doldurduktan sonra yazdığımız B karakterleri val değişkenine yazıldı. O halde B karakterlerinin olduğu yere 0xdeadbeef yazabiliriz. Ama dikkat etmemiz gereken şey bunun little-endian olarak yazılması gerektiği (yani tersten)

2


narnia1:efeidiedae

Narnia: Level 1 Writeup​

ssh [email protected] -p 2226
password: efeidiedae

code


EGG isminde bir ortam değişkeni arıyor. Eğer boş ise bu ortam değişkeninin içerisine çalıştırabileceğim birşeyler koy diyor. Eğer içi doluysa da içindekini çalıştırıyor.

Durum böyle olunca aklımıza hemen bir shellcode bulup bunu EGG isimli bir ortam değişkenine yüklemek geliyor

Shellcode : Linux/x86 - execve(/bin/sh) - 28 bytes 2

f32e50554268076889547bb1b25ccdcdccac3058.png


narnia2:nairiepecu

Narnia: Level 2 Writeup​

ssh [email protected] -p 2226
password: nairiepecu

code


128 byte’lık bir buffer alanımız var. Bu buffer alanını taşırarak EIP registerına shellcode’umuzun olduğu adresi yazacağız.

Öncelikle EIP registerına müdahale edebilmek için kaç karakter girmemiz gerekiyor onu bulalım.

e178177f9e491a9b1b8e6a92a8f86f9723c32996.png


Offset değerimiz 132 karaktermiş. O halde main fonksiyonumuzdaret işleminin olduğu kısma bir breakpoint koyalım ve offset+shellcode gönderelim

1


ESP'nin gösterdiği yerde shellcode’umuzun başlangıcını görüyoruz. Bu şekilde direk çalıştıramayacağımız için shellcode’u biraz ileriye taşıyıp daha sonra shellcode’un başlangıç adresini ESP'nin gösterdiği yere yazacaz

2


Hmm burda birşeyler oldu sanırım. ESP registerının adresi değişti. Önceden 0xffffd52c adresindeyken şuan 0xffffd50c adresini göstermekte. O halde bizde payloadımızdaki adresi güncelleyelim o zaman

3


Adresi güncelledik ve stack durumunu kontrol ettik. Herhangi bir sıkıntı görmediğimiz için devam ederek shellcode’umuzu çalıştırmış olduk. Ancak dikkat etmemiz gereken birşey var ki o da şuan narnia3 kullanıcı yetkilerine sahip değiliz yani password dosyasını okuyamayacağız. Bunun için gdb aracından çıkıp direk çalıştırmamız gerekecek.

4


İlk çalıştırdığımızda ufak bi hata aldık. Muhtemelen stack içerisinde gene bir kayma durumu oldu. Bunun için aradaki NOP karakterleri biraz daha arttırdık ve başarılı bir şekilde shellimizi aldık.

narnia3:vaequeezee

Narnia: Level 3 Writeup​

ssh [email protected] -p 2226
password: vaequeezee

code


Öncelikle kodumuzu hızlıca bir inceleyip ne yaptığını bir anlayalım. İki tane değişkenimiz var ve içlerinde birşey yok. 3 adet de buffer’ımız mevcut. Birinin içerisine /dev/null yazılmış diğerlerinin ise içi boş. Eğer yeterli sayıda argüman girmezsek bize nasıl kullanılacağına dair bir mesaj yazıyor.

Buraya kadar herhangi birşey yok gibi. Burdan sonra ise girmiş olduğumuz argümanı strcpy fonksiyonu ile ifile buffer alanının içerisine yazıyor (Yani burda bir adet zafiyetimiz mevcut, yazalım bir kenara devam edelim).

Daha sonra bir if bloğu ile karşılaşıyoruz. open fonksiyonu ile ofile içerisinde yazan dosyada tam yetkimiz olup olmadığına bakıyor. Eğer yoksa bu dosyayı açamadım diyor ve çıkış yapıyor. Yetkimiz var ise devam ediyor ve bu sefer ifile içerisinde yazan dosyada okuma iznimiz olup olmadığını kontrol ediyor. İznimiz yoksa programdan çıkış yapıyor.

Tüm bu süreçler geçtikten sonra bizim argüman olarak girmiş olduğumuz dosyayı (ifile) okuyor ve ofile içerisinde yazan dosyanın içerisine yazıyor.

İlk open işlemine bir breakpoint atalım ve rastgele 32 karakterden daha uzun bir dosya dizini girelim

19e176a518e5a5b912e77c3a5f2e64086efedac0.png


Normalde /dev/null tutan buffer alanını bozduk ve istediğimiz bir dizini yazabildik. Artık outputfile (ofile) yani içerisine birşeyler yazacağımız dosyayı değiştirebiliyoruz.

Şimdi ikinci aşamayı test etmek için hızlıca bir dosya oluşturalım ve bakalım nasıl birşey ile karşılaşıcaz

narnia3@narnia:/narnia$ mkdir /tmp/denemedizini
narnia3@narnia:/narnia$ touch /tmp/denemedizini/test
narnia3@narnia:/narnia$ chmod +777 /tmp/denemedizini/test

1


Hmm girmiş olduğumuz argümandaki dizine giderek ordaki dosyayı okumaya çalışıyor. O halde benim yazmak istediğim dosyada okumak istediğim dosyada /tmp dizini altında olması lazım.

2


Bu şekilde /tmp/012345678901234567890123456 ile 32 byte uzunluğuna ulaşmış oluyoruz. Bundan sonra yazdığımız /tmp/pass bizim outputfile değeri olacak. Böylelikle /tmp/012345678901234567890123456/tmp/pass dosyası inputfile olacak (okunacak olan dosya) ve /tmp/pass'de outputfile olacak (yazılacak olan dosya).

inputfile 'ı da eğer /etc/narnia_pass/narnia4 ile bağlarsam narnia4 kullanıcısına ait parolayı okuyup daha sonrada yazdırabilirim.

3


narnia4:thaenohtai

Narnia: Level 4 Writeup​

ssh [email protected] -p 2226
password: thaenohtai

code


Level 2 'ye benzer bir soru…

c06f8a5b43b095705ab42c6f1a3699e3b417b7ab.png


264 karakterden sonra EIP registerı üzerine yazabiliyoruz.

1


Ana fonksiyonumuzun bittiği noktaya bir breakpoint koyalım

2


Stack içerisinde shellcode’un hangi adrese geldiğini bulalım ve EIP üzerine yazalım

3


Stack içerisinde gene ufak bir kayma oldu. EIP üzerine yazacağımız adresi güncelleyelim.

4


Ve shell geldi. Şimdi gdb’den çıkalım ve programımızı bu argüman ile çalıştıralım

5


narnia5:faimahchiy

Narnia: Level 5 Writeup​

ssh [email protected] -p 2226
password: faimahchiy

code


Bizden istediği şey i değişkeninin değerini 1 iken 500 yapmamız. Burda kullanacağımız zafiyet ise buffer overflow değil format string zafiyeti olacak.

Öncelikli emin olmak için zafiyetimizi bir tespit edelim

810dcc96a09c76e6320e1eed65dd9d46d01f4bb7.png


Evet format string zafiyetimiz mevcut. Girdiğimiz değer ise ilk sırada yerini alıyor :) Yerini bulmakla uğraşmayacağız anlaşılan

1


2


Segmentation fault hatası alıyoruz çünkü henüz hangi adrese yazmak istediğimizi belirtmedik. Yazmamız gereken adresi ise programı çalıştırdığımız zaman programın kendisi bize veriyor.

Bu adresi öğrendikten little-endian olarak yazıyoruz. %1$n ifadesi ile stackten okuduğumuz ilk adresin içerisine yazacaz demek oluyor. (Yazdığımız adres eğer stack içerisinde adres okurken ilk sırada değil başka bir sırada olsaydı ona göre bu kısmı farklı şekilde yazmamız gerekirdi). Bizden 1 sayısını 500 yapmamız istiyor. Yazdığımız adres 4 byte uzunluğunda. 500 - 4 = 496 karaktere daha ihtiyacımız var ki onuda %496x , %496d vs kullanarak halledebiliriz.

3


narnia6:neezocaeng

Narnia: Level 6 Writeup​

ssh [email protected] -p 2226
password: neezocaeng

code


9d086d1cd9d047f77a014809ed96805f7b0b1e5f.png


İki tane argüman alıyor ve bunları sırasıyla b1 ve b2 içerisine kopyalıyor. Ancak sadece ilk argümanı ekrana yazdırıyor. (fp değişkeni puts() fonksiyonunu işaret ediyor, b1'i göndererek sadece ilk argümanı yazdırmış oluyor)

Bu noktaya bir adet breakpoint koyalım ve stack içerisinde neler oluyormuş bir bakalım.

1


lea komutu ile eax içerisine bizim ilk argümanımızın olduğu adresi yüklüyoruz. Daha sonrada bu adresi stack içerisine gönderiyoruz. Böylece ilk argümanımızın adresini kaybetmemiş olacağız ki buda puts fonksiyonu çağrıldığında kullanılacak.

Daha sonra eax içerisine tekrardan birşeyler yükleniyor ve call fonksiyonu ile çağrılıyor. Demek ki bu bir fonksiyon. Yani yani bizim puts fonksiyonumuz

3


Çalıştırıp stack alanı içerisine baktığımız zaman herşey daha iyi oturacaktır sanırım. Stack de en başta bizim ilk argümanımızın adresi bulunmakta. Ayrıca eax registerına yüklenen ebp-0xc konumundaki adrese baktığımız zamanda puts işlemini görebiliyoruz.

O halde ebp-0xc konumundaki adres eax'a yüklenip call ediliyorsa bizde oraya istediğimiz bir adresi yazarak istediğimiz şeyi çalıştırmış olabiliriz.

4


eax'a istediğimiz şeyi yazabildik. O zaman son aşamaya geçebiliriz.

Hatırlayacağınız üzere girdiğimiz ilk argümanın adresini stack’e pushluyorduk ve mevcut durumda stack’in en üstünde bu adres kalıyordu. O halde eğer ben ilk argüman olarak /bin/sh; stringini verirsem (8 karakter yapıyor :D ) daha sonrada system func adresini girersem (ki o da tam olarak eax değerinin alındığı yere denk geliyor) herhangi bir shellcode yazmadan kolay bir şekilde shell alabilirim. Tabi programın çalışması için rastgele bir ikinci argüman girmemiz lazım

5


Evet gdb üzerinde çalıştırdık. Sırada programımızı normal çalışma akışında manipüle etmeye geldi.

./narnia6 $(python -c 'print "/bin/sh;" + "\x50\xc8\xe4\xf7"+ " BBBB"')

6


narnia7:ahkiaziphu

Narnia: Level 7 Writeup​

ssh [email protected] -p 2226
password: ahkiaziphu

code


4 tane fonksiyonumuz mevcut. main fonksiyonumuz argüman sayısını kontrol ettikten sonra bizi vuln isimli fonksiyona yönlendiriyor. Bu fonksiyonumuz ise goodfunction adresini alarak bizi oraya yönlendiriyor. Ancak o fonksiyonun içerisinde işimize yarayacak bişi yok. Eğer hackedfunction isimli fonksiyonu çalıştırabilirsek direk shell alabiliyoruz.

Bunun içinde dikkatimizi çeken format string zafiyetini kullanacağız.

4d8c947288e69e17e58c9bcaad3b4dc9f9020d68.png


Girmiş olduğumuz argümanı herhangi bir çıktı olarak bize vermiyor. Haliyle biraz bodoslama şekilde ilerlememiz gerekecek. (bize çıktı vermediği için format string zafiyetini kullanarak stack içerisindeki adresleri yazdıramıyoruz)

Ama genede bize ipucu vermiş. Çalıştırmak istediğimiz hackedfunction isimli fonksiyonun adresinin ne olduğunu, goodfunction isimli fonksiyonun adresinin ne olduğunu ve bunu tutan pointer adresinin ne olduğunu gösteriyor. O halde ben bu pointer adresinin olduğu yeri bulsam ve bunun içerisine hackedfunction adresini yazsam nasıl olur. Bence güzel olur
:joy:


>>> 0x8048724
134514468
>>> 0x8048724 - 0x4
134514464

hackedfunction adresinin decimal karşılığını öğrendikten sonra öncesine 4 byte’lık bir adres yazacağımız için 4 çıkartıp not ediyoruz. Böylece 4 byte'lık adres + 134514464 = 134514468 (0x8048724) olmuş olacak

Daha sonra girdiğimiz argümanın tam olarak kaçıncı sıraya yerleştiğini bilmediğimizden sırasıyla %1$n, %2$n … şeklinde deneyeceğiz.

1


Neyseki çok uğraştırmadı ve 2. sırada denk geldi :)

narnia8:mohthuphog

Narnia: Level 8 Writeup​

ssh [email protected] -p 2226
password: mohthuphog

code


Bu soruda da main fonksiyonumuzun pek bir işlevi yok o yüzden func isimli fonksiyonumuzun içerisindeki printf'in olduğu kısıma bir breakpoint koyalım.

499cbc9ed4fcb2e53566d5b32fce2c29396839c7.png


Şimdi buffer alanımız 20 karakter olduğu için önce 20 byte gönderelim stack durumuna bakalım ve 24 byte gönderip tekrar bakalım

1


Dikkatimizi çeken iki şey var. ilk 20 byte gönderdiğimizde stack içerisinde iki tane 0xffffd7b1 olduğunu görüyoruz. Bir de 24 byte gönderdiğimiz zaman sadece 1 byte’ı değiştirebiliyoruz.

Bu adrese eğer bakacak olursak içerisinde bizim girmiş olduğumuz input değerini tuttuğunu görebilirsiniz. Evet herneyse 20 byte’dan sonra yazdığımız her byte için bu adresin değeride 1 azalıyor. Yani 20 byte gönderdiğimiz zaman 0xffffd7b1 olan adres 20 byte + 8 byte 'lık birşey girdiğimiz zaman 0xffffd7b1 - 0x8 = 0xffffd7a9 olacaktır.

Bu neden bize lazım. Çünki devam edip ebp ve eip değerlerini değiştirmek için önce buranın aynı kalması lazım. Yani buraya, 28 byte lık değer geldiği zaman sahip olacağı adresi yazmamız lazım.

2


Gördüğünüz üzere adresi doğru tahmin ettik ve ebp üzerine yazabildik. Eğer dikkat ederseniz ebp'den bir önceki adres ile iki sonraki adres aynı değerlere sahip.

Şimdi EIP üzerine yazalım

3


Ve başarılı bir şekilde EIP adresinide değiştirebildik. Şimdi sisteme local env olarak bir shellcode ekleyelim ve adresini öğrenelim. Bu adreside EIP üzerine yazarak shellcode’umuzu çalıştıralım

4


#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
char* ptr = getenv("SHELLCODE");
printf("%p\n", ptr);
}

SHELLCODE 1’a burdan ulaşabilirsiniz…

export SHELLCODE=$(printf "\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89\xe1\xcd\x80")

Şimdi stack içerisinde tahmin etmemiz gereken o adresin ne olduğunu bulalım. Daha sonra 12 byte çıkaralım ve payloadımıza ekleyelim. Daha sonra ebp'ye yazmak üzere önemsiz bir 4 byte ve ardından EIP üzerine yazmak için shellcode adresini ekledik mi payloadımız hazır olacaktır.

5


Ve bu seviyeyide başarıyla tamamlayarak NARNIA macerasınıda tamamlamış olduk :)

narnia9:eiL5fealae
 
Üst