php反序列化漏洞

O:6:"Animal":1:{s:4:"name";N;}

  • O 有一个对象
  • : 下一句
  • 6 名字是6个字符
  • : 下一句
  • "Animal"内容是Animal
  • : 下一句
  • 1 对象有一个属性
  • : 下一句
  • { 对象属性描述开始
  • s 属性是一个字符串 string
  • : 下一句
  • 4 属性名字是4个字符
  • : 下一句
  • "name"属性名字是name
  • , 属性名字描述完成
  • N 没有值,值为NULL
  • ; 属性值描述完了
  • } 对象属性描述完了

结论

反序列化和类的方法无关,不能把类方法序列化。

反序列化流程

  1. 找到反序列化字符串规定的类名字
  2. 实例化这个类,但是不是调用构造方法
  3. 有了实例化的类对象,对它的属性进行赋值
  4. 执行魔术方法
  5. 返回构造好的对象

问题

  1. 接口是否可以序列化?

    serialize方法序列化传一个类的对象,类的实力,并返回反序列化的字符串,如果要序列化一个接口,那么就要有这个接口的实例化对象,而因为接口不能new,所以就没有实例化对象,所以没法给serialize方法作为参数,就没有返回的序列化字符串。
    接口不能直接序列化

  2. 匿名类是否可以序列化?

    缺少名字,无法序列化

  3. trait是否可以序列化?

    因为不能new,所以就没有实例化对象,所以没法给serialize方法作为参数,就没有返回的序列化字符串。

魔术方法

总结

  1. 魔术方法是一类类的方法特殊
  2. 会在序列化和反序列化及其他情况下,自动执行

分类

1. __construct

  1. 在实例化一个对象(new)时,会被自动调用
  2. 不允许重复声明
  3. 可以作为非public权限属性的初始化

2. __sleep__wakeup方法

  1. 序列化时自动调用__sleep方法
  2. 反序列化之后__wakeup被调用

3. __destruct析构方法

类对象将要销毁,也就是脚本执行完毕后执行清理工作时自动执行
添加杀死进程能够system('taskkill /fi "imagename eq php.exe" /f');绕过
system('taskkill /fi "imagename eq php-cgi.exe" /f');

4. __call__callstatic

对象执行执行类不存在的方法的时候,会自动调用__call方法

后者执行执行类的不存在的静态方法时,会自动调用__callstatic方法

5. __get __set__isset __unset魔术方法

__get对不可访问属性或不存在属性 进行访问引用时自动调用
__set对不可访问属性或不存在属性 进行写入时自动调用

6. __tostring 方法

类的实例字符串进行拼接或者作为字符串引用时,会自动调用__tostring方法

7. __invoke方法

当类的实例被作为函数名字执行的时候,会自动调用__invoke方法

8. __set_state 方法

文档中说 执行 var_export时自动调用

9. __debugInfo 方法的属性修饰符

执行var_dump时自动调用

10. __clone方法

当使用clone关键字 ,clone一个对象时,会自动调用

php的反序列化漏洞

条件

  1. 有反序列化提交的入口
  2. 被反序列化的类的魔术方法,有可能被利用

绕过方法

1. 绕过__wakeup方法
  • php5至php5.6.25 之间的版本可以绕过
  • php7到php7.0.10 直接的版本可以绕过

绕过方法:

  • 反序列化字符串中表示属性数量的值 大于 大括号内实际属性的数量时 ,wakeup方法会被绕过
2. 绕过 +号正则匹配

参数有过滤,不让输入 O:数字 的形式,试图防止反序列化某个对象

O:数字 改为 O:+数字 就可以绕过上面的O:数字 过滤

例题web56

3. 引用绕过相等

使用&符号表示两个变量指向相同的内存引用地址,就是指针

例题web57

4. 16进制绕过

反序列化后的字符串 不能出现某个关键单词时,可以使用大S绕过,变成支持ASCII的反序列化

O:8:"backdoor":1:{s:4:"name";s:10:"phpinfo();";}

O:8:"backdoor":1:{S:4:"n\97me";s:10:"phpinfo();";}


$data='O:8:"backdoor":1:{S:4:"n\97me";s:15:"system(\'calc\');";}';


5. exception 绕过

不影响析构方法执行
例题web59

6. php反序列化字符逃逸

如果代码对提交的反序列化字符串进行了过滤,将里面的内容进行了替换
比如fuck替换为loveu
未修正字符串长度时,再进行反序列化,就会出现逃逸情况
例题web60

  1. 可以控制某个类中的属性值
  2. 间接控制了某个类的反序列化字符串
  3. 由于存在无脑过滤,字符增减,造成 描述中字符串的长度 和实际的不一致
  4. 从而能够逃逸出若干个字符,实现字符可控,从而闭合前面的双引号
  5. 实现反序列化字符串的完全可控

phar反序列化

Phar认为是javajar包 (被封装成calc.exe类似的文件)

phar能做什么

多个php合并为独立压缩包
不解压就能执行里面的php文件
支持web服务器命令行

phar协议

phar://xxx.phar/aaa.php

metaData可以存放一个类实例,生成phar后,会将这个类示例以序列化字符串形式存放形式存放刀Phar文件内,当使用phar协议加载phar文件时,会自动反序列化这个类的序列化字符串

总结
  1. 生成phar包时,可以往metaData里面放对象
  2. 生成后,对象会自动序列化保存到phar包
  3. 使用phar协议读取phar包时,如果当前脚本识别了这个类,会自动调用这个类的魔术方法
可以包含的方法
  • include "phar://ctfshow.phar";
  • file_exists("phar://ctfshow.phar");
  • file_get_contents("phar://ctfshow.phar");
  • file_put_contents("phar://ctfshow.phar",'111');
  • require "phar://ctfshow.phar";
  • fileinclude("phar://ctfshow.phar");
  • filemtime("phar://ctfshow.phar");
  • filesize("phar://ctfshow.phar");
  • ls_dir("phar://ctfshow.phar");
  • scandir("phar://ctfshow.phar");
  • highlight_file("phar://ctfshow.phar");

哪里使用的头
如果有上传头,上传文件的前半部分可控,后缀黑名单,不能对危险的后缀,php phps phtml ini 没有禁止上传phar文件
能够上传phar文件,找到大量使用的file_exists等文件读取函数,通过控制phar://头,来使用phar协议来解析phar包
就能自动进行反序列化

条件:
  1. 能够生成phar包并上传写入
  2. 有可利用的文件操作函数,并控制了协议头,使用phar协议解析
  3. 有可利用的恶意类

session反序列化

PHP_SESSION_UPLOAD_PROGRESS

php的session是存放在文件中 其默认位置是/tmp/sess_PHPSESSID

session是可以放字符串、数字,也可以放对象

总结:
  1. session里面存放对象时,会自动进行序列化,存放序列化后的字符串
  2. session里面拿取对象时,会自动进行反序列化,执行对象的魔术方法

例题web63

thinkphp反序列化

本文链接:

https://youngking.xyz/index.php/archives/828/