
Démo éducative d'exploitation pour CVE-2018-1263 (phpMyAdmin RCE/LFI). Inclut la configuration d'un environnement vulnérable via Docker et un guide pas à pas d'attaque pour apprendre l'exploitation d'applications web.
Ce guide vous aidera à installer le composant vulnérable et à réaliser l'attaque liée au bug de phpMyAdmin mentionné dans CVE-2018-1263.
Cet exploit est lié à un problème découvert dans phpMyAdmin version 4.8.x avant 4.8.2. En exploitant ce problème, un attaquant peut exécuter du code à distance et inclure des fichiers locaux sur le serveur. La vulnérabilité provient de la partie du code responsable de la redirection et du chargement des pages dans phpMyAdmin. Le code comporte un test défectueux pour les pages autorisées qui rend l'attaque possible. Un attaquant doit être authentifié, sauf dans le cas "$cfg['AllowArbitraryServer'] = true" (où un attaquant peut spécifier n'importe quel hôte qu'il contrôle déjà et exécuter du code arbitraire sur phpMyAdmin) et le cas "$cfg['ServerDefault'] = 0" (qui contourne l'obligation de connexion et exécute le code vulnérable sans aucune authentification).
La vulnérabilité est causée par un contournement de validation dans la fonction de vérification du chemin vulnérable. Cette vulnérabilité permet à un attaquant distant authentifié d'exécuter du code PHP arbitraire sur le serveur.
Il y a une inclusion de fichier dans index.php de phpMyAdmin qui peut être déclenchée en fournissant un paramètre nommé target dans l'URL et la partie du code qui valide le paramètre target ressemble à ceci
$target_blacklist = array (
'import.php', 'export.php'
);
// If we have a valid target, let's load that script instead
if (! empty($_REQUEST['target'])
&& is_string($_REQUEST['target'])
&& ! preg_match('/^index/', $_REQUEST['target'])
&& ! in_array($_REQUEST['target'], $target_blacklist)
&& Core::checkPageValidity($_REQUEST['target'])
) {
include $_REQUEST['target'];
exit;
}
// ...
Dans ce code, une fois que la condition if est satisfaite, il exécute include $_REQUEST['target'];. Nous devons donc simplement contourner la condition if pour exécuter ce que nous voulons.
Examinons la condition if
$target_blacklist
$target_blacklist est défini juste avant la condition if et inclut import.php et export.php, ce qui signifie que tout sauf ces deux pages est autorisé.Core::checkPageValidity($_REQUEST['target']).
checkPageValidity supprime tout ce qui se trouve après ? dans $page et vérifie s'il se trouve dans la liste blanche. La chaîne après ? ne fait pas partie du chemin URL. Un exemple de liste blanche est également montré dans l'extrait de code.public static function checkPageValidity(&$page, array $whitelist = [])
{
// ...
$_page = mb_substr($page, 0, mb_strpos($page . '?', '?'));
// example $whitelist == array('db_sql.php', 'sql.php', ...)
if (in_array($_page, $whitelist)) {
return true;
}
// ...
return false;
}
$page, car il provient directement de $_REQUEST['target'].Comme mentionné précédemment, l'attaquant a un contrôle total sur $page dans la fonction checkPageValidity via le paramètre $_REQUEST['target'] dans l'URL. Imaginons que l'attaquant envoie quelque chose comme ceci en utilisant le paramètre $_REQUEST['target'] vers $page
$page = 'db_sql.php?/../../../../../../../../etc/passwd'
La fonction checkPageValidity effectue alors les opérations suivantes
? et attribue la première partie à $page. Donc dans cet exemple, la valeur de $page = db_sql.php.$_page, c'est-à-dire db_sql.php, est dans la liste blanche ou non. Comme il est dans la liste blanche, la fonction renvoie True et retourne à index.phpComme la condition if dans index.php est maintenant True, elle exécute la ligne suivante comme montré dans l'extrait de code index.php ci-dessus
include $_REQUEST['target'];
Ce qui se passe ensuite est
$_REQUEST['target'], ce qui signifie que ce qui suit est exécuté
GET /index.php?target=db_sql.php?/../../../../../../../../etc/passwd
db_sql.php existe ou non, le /../../../../../../../../etc/passwd est exécuté et le contenu du fichier /etc/passwd est renvoyé dans la réponse à l'attaquant.Nous pouvons maintenant utiliser cela pour effectuer une inclusion de fichier local ou même une exécution de code à distance pour obtenir un reverse shell. Chaque fois que nous exécutons une requête dans phpMyAdmin, il crée un fichier de session et le stocke dans le répertoire /tmp avec le contenu de la requête. Le fichier de session est nommé sess_< SESSION ID >. L'ID de session peut être facilement trouvé dans le cookie en utilisant l'option d'inspection du navigateur.
Donc si nous exécutons la requête suivante dans phpMyAdmin
SELECT '<?php phpinfo();exit;?>'
Elle sera stockée dans le fichier de session. Imaginons que notre ID de session pour phpMyAdmin soit e15cffd3ab25a631136611fba9ca2042
Ensuite, si nous déclenchons l'adresse suivante dans le navigateur
http://your-ip:8080/index.php?target=db_sql.php?/../../../../../../../../tmp/sess_e15cffd3ab25a631136611fba9ca2042
Ensuite, phpMyAdmin essaiera de charger la page de session et comme la page contient le code PHP fourni par la requête, le code PHP sera exécuté et dans cet exemple particulier, nous verrons phpinfo dans la page chargée par le navigateur. En utilisant cette technique, nous pouvons exécuter n'importe quel code arbitraire sur le serveur distant.
L'infrastructure de l'exploit nécessite une version vulnérable de phpMyAdmin et de mysql. Nous utiliserons des conteneurs Docker pour installer les composants nécessaires. Pour la version vulnérable de phpMyAdmin, nous utiliserons un environnement Docker préconstruit de Vulhub et pour mysql, nous utiliserons la dernière version officielle de dockerhub. Le script d'installation est fourni sous forme de script docker-compose yml qui peut être trouvé dans le dépôt.
Nous supposons que la machine cible a docker et docker-compose installés. Sinon, veuillez vous référer à la documentation de docker pour les installer. Une fois docker installé, effectuez les étapes suivantes pour configurer le composant vulnérable :