Énoncé
Remember Bruh 1,2 ? This is bruh 3 : D login with admin:admin and you will get the flag :*
Author : abdoghazy
Aperçu
Pour ce challenge web, le code source nous est fourni :
Nous pouvons voir que les langages utilisé coté serveur sont le PHP et le Python. Nous avons deux applications web, une accessible directement depuis l’extérieur (app php) et une qui ne l’est pas (app python). En effet pour communiquer avec l’app web python, il faut obligatoirement passer par celle en php.
Si nous regardons le script app.py
, nous pouvons voir qu’il faut se “connecter” au compte admin pour accéder au flag :
@app.route('/login', methods=['POST'])
def handle_request():
try:
username = request.form.get('username')
password = hashlib.md5(request.form.get('password').encode()).hexdigest()
# Authenticate user
user_data = authenticate_user(username, password)
if user_data:
return "0xL4ugh{Test_Flag}"
else:
return "Invalid credentials"
except:
return "internal error happened"
Cependant dans le fichier index.php
, la fonction Check_Admin()
empêche cela :
function Check_Admin($input)
{
$input=iconv('UTF-8', 'US-ASCII//TRANSLIT', $input); // Just to Normalize the string to UTF-8
if(preg_match("/admin/i",$input))
{
return true;
}
else
{
return false;
}
}
Résolution
En résumé, pour résoudre ce challenge il faut se connecter au compte admin, malgré le bloquage de celui-ci par la fonction php Check_Admin()
.
HTTP Parameter Pollution
La vulnérabilité à utiliser pour accéder au compte admin est une HPP. En effet le programme index.php
va lire le paramètre username
de la requête HTTP, pour vérifier si l’utilisateur essai de se connecter au compte admin. Puis si ce n’est pas le cas, les paramètres de la requête seront utilisé pour en faire une sur la route /login
de app.py
(http://127.0.0.1:5000/login).
function send_to_api($data)
{
$api_url = 'http://127.0.0.1:5000/login';
$options = [
'http' => [
'method' => 'POST',
'header' => 'Content-Type: application/x-www-form-urlencoded',
'content' => $data,
],
];
$context = stream_context_create($options);
$result = file_get_contents($api_url, false, $context);
if ($result !== false)
{
echo "Response from Flask app: $result";
}
else
{
echo "Failed to communicate with Flask app.";
}
}
if(isset($_POST['login-submit']))
{
if(!empty($_POST['username'])&&!empty($_POST['password']))
{
$username=$_POST['username'];
$password=md5($_POST['password']);
if(Check_Admin($username) && $_SERVER['REMOTE_ADDR']!=="127.0.0.1")
{
die("Admin Login allowed from localhost only : )");
}
else
{
send_to_api(file_get_contents("php://input"));
}
}
else
{
echo "<script>alert('Please Fill All Fields')</script>";
}
}
Cependant index.php
va vérifier si le paramètre username
correspond au regex /admin/i
seulement pour le dernier paramètre username
de la requête. Tandis que app.py
va vérifier le premier paramètre username
pour l’authentification au compte.
Exploitation
Pour exploiter la vulnérabilité il faut donc envoyer deux paramètres username
, le premier doit être égal à admin car il sera utilisé par app.py
et le deuxième différent de la valeur admin.
Flag : 0xL4ugh{M1cr0_Serv!C3_My_Bruuh}