php反序列化

The Redefine Team Lv2

image-20250221201913064

phar 反序列化
注意:要将 php.ini 中的 phar.readonly 选项设置为 Off,否则无法生成 phar 文件

//phar 的使用格式

startBuffering(); $phar->setStub(''); //设置stub,我们必须以这个为结尾,否则phar扩展将无法识别这个文件为phar文件 $phar->setMetadata($a); //将自定义的meta-data存入manifest,我感觉就是将序列化的东西存进去 $phar->addFromString('test.txt', 'test');//添加要压缩的文件 $phar->stopBuffering();//签名自动计算 这里我们可以使用winhex,看看他是否将meta-data序列化 注意:phar文件一定要用winhex或010或脚本直接修改,不能用记事本之类的,他的签名会变化的。 这里我们看到他是进行了序列化的。 然后解释phar文件的结构 1.a stub 可以理解为一个标志,格式为xxx,前面内容不限,但必须以__HALT_COMPILER();来结尾,否则phar扩展将无法识别这个文件为phar文件。

2.a manifest describing the contents phar 文件本质上是一种压缩文件,其中每个被压缩文件的权限、属性等信息都放在这部分。这部分还会以序列化的形式存储用户自定义的 meta-data,这是上述攻击手法最核心的地方

3.the file contents 被压缩文件的内容。

4.[optional] a signature for verifying Phar integrity (phar file format only) 签名,放在文件末尾

然后我们具体是通过 phar 协议文件包含来使用的。

phar:// 相对路径 /a.phar

phar:// 绝对路径 /a.phar

phar:// 协议(像是 http tcp 协议这样的)

以下是另一个示例的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class A { 
public $a;
}
class B {
public $b;
}
$a = new A();
$a->a = new B();
$a->a->b = "phpinfo();";

$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //设置stub
$phar->setMetadata($a); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
$phar->stopBuffering();

上面的一部分是pop链的内容,下面的和上面的那个差不多,但多了一些
第一句是实例化一个phar的对象括号里面是名字,后缀必须是.phar,前面名字无所谓
第二句开启缓冲区,即是要写入数据了
第三句可以理解为写入phar文件的头部信息"GIF89a".可以不写,上面的代码示例就没写,后面的必须写,代表php终止编译的一句话
第四句是最重要的一行,把上面$a放进去,设置一些数据
第五句再为这个phar文件设置一些文件前面是文件名字,后面是文件内容都随意就行
第六句关闭缓冲区


上传上去后用phar://读取文件就可以反序列化,路径上面说了可以相对可以绝对,后缀可以是phar也可以是txt随便什么,协议对了就行

在 php 版本大于 7.1 后,对 private protected 这些不敏感,可以直接改成公共或是 var

# CVE-2016-7124

  • PHP5 < 5.6.25
    PHP7 < 7.0.10

    序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过 __wakeup 的执行。

image-20250307192347628

绕过是在属性数字前面加个 +,但是这样 get 传参时候 + 有其他意思,要全部 url 编码一下或者直接给 + 换成他的编码格式 %2b

image-20250307192658849

对于低版本的 php,直接在后面加上他要的内容即可

# POP 链

  • POP 即面向属性编程 (Property Oriented Programing),利用代码中的各类对象属性和魔术方法,来构造一条人为控制的调用路线。
  1. 确定入口

    能够开始执行调用的地方。

    1. 静态函数调用

      1
      $a->test();

动态函数调用

1
2
$b = 'test';
$a->{$b}();

魔术方法

1
2
__destruct()  // 对象销毁时自动执行
__wakeup() // 反序列化中自动执行

确定出口(利用点)

  1. 类方法中的危险函数

    1
    2
    3
    4
    eval()
    system()
    shell_exec()
    file_get_contents()
    1. 涉及 FLAG 的地方。
  2. 构造属性调用链

    通过魔术方法构造调用链。

# 魔术方法

1
2
3
4
5
6
7
8
__destruct()  // 对象销毁时自动执行
__wakeup() // 反序列化中自动执行

__toString() // 将对象转换为字符串是自动触发
__invoke() // 将对象作为函数调用时触发
__get($name) // 访问对象中不存在的属性时触发,并将名字作为参数传入
__set($name, $value)// 对对象中不存在的属性赋值时触发,并将名字和值作为参数传入
__call($name, $args)// 调用对象中不存在的方法时触发,并将名字和参数数组作为参数传入

# session 反序列化

NSS图片
NSS图片

  • 标题: php反序列化
  • 作者: The Redefine Team
  • 创建于 : 2025-02-21 20:18:11
  • 更新于 : 2025-03-08 15:19:12
  • 链接: https://redefine.ohevan.com/2025/02/21/php反序列化/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论