该题的原型是2016xctf的一道反序列化,我本来想着随便改改就放服务器上去了,然后发现怎么这么多问题啊,慢慢dubug,然后花了4、5个多小时去研究php伪协议、反序列化、php类的相关知识、linux文件结束符,感觉对反序列化的了解、对php伪协议的过滤器的了解 都大大加深了😭,虽然现在已经是4.40了,但人总是要微笑着活下去,不是么

下面先给出最后的源码:
<?php
$a=isset($_GET["a"])?$_GET["a"]:'';
$b=isset($_GET["b"])?$_GET["b"]:'';
$c=isset($_GET["c"])?$_GET["c"]:'';
$d=isset($_GET["d"])?$_GET["d"]:'';
$e=isset($_GET['e'])?$_GET['e']:'';
if(preg_match('/php/i', $a)){
die("This not allow pseudo protocol!");
}
if(preg_match('/\.\./', $a)){
die("This also not allow!");
}
if((file_get_contents($a,'r')===$b)&&(file_get_contents($e,'r')==="I'm Administrator!")){
echo "hello admin!<br>";
if(preg_match("/flag/",$c)){
echo "不能现在就给你flag哦";
exit();
}else{
include($c);
if(preg_match('/base64/', $d)){
die("No! you can't use it!");
}
if(preg_match('/string\..+/', $d)){
die("No! you can't use it!");
}
if(preg_match('/zlib/', $d)){
die("No! you can't use it!");
}
if(preg_match('/mcrypt/', $d)){
die("No! you can't use it!");
}
$d = unserialize($d);
echo $d;
}
}else{
echo "you are not admin ! <br>";
}
?>
<!--
$a=isset($_GET["a"])?$_GET["a"]:'';
$b=isset($_GET["b"])?$_GET["b"]:'';
$c=isset($_GET["c"])?$_GET["c"]:'';
$d=isset($_GET["d"])?$_GET["d"]:'';
$e=isset($_GET['e'])?$_GET['e']:'';
if(preg_match('/php/i', $a)){
die("This not allow pseudo protocol!");
}
if(preg_match('/\.\./', $a)){
die("This also not allow!");
}
if((file_get_contents($a,'r')===$b)&&(file_get_contents($e,'r')==="I'm Administrator!")){
echo "hello admin!<br>";
if(preg_match("/flag/",$c)){
echo "不能现在就给你flag哦";
exit();
}else{
include($c);
if(preg_match('/base64/', $d)){
die("No! you can't use it!");
}
$d = unserialize($d);
echo $d;
}
}else{
echo "you are not admin ! <br>";
}
-->
<?php
#class.php
$GLOBALS['data']="\x4d\xc9\x68\xff\x0e\xe3\x5c\x20\x95\x72\xd4\x77\x7b\x72\x15\x87\xd3\x6f\xa7\xb2\x1b\xdc\x56\xb7\x4a\x3d\xc0\x78\x3e\x7b\x95\x18\xaf\xbf\xa2\x00\xa8\x28\x4b\xf3\x6e\x8e\x4b\x55\xb3\x5f\x42\x75\x93\xd8\x49\x67\x6d\xa0\xd1\x55\x5d\x83\x60\xfb\x5f\x07\xfe\xa2";
class Flag{//flag.php
public $file;
public $chack;
public function __tostring(){
if(isset($this->file)&&isset($this->chack)){
$this->chack=str_replace(" ","+", $this->chack);
if(base64_decode($this->chack)!==$GLOBALS['data']&&md5(base64_decode($this->chack))===md5($GLOBALS['data'])){
echo file_get_contents($this->file);
echo '<br>';
return "Good~";
}
else{
return "It's a little worse. ";
}
}
return "To be more luckly~";
}
}
?>
<?php
#flag.php
#wpsec{Unserialization_And_Pseudo_Protocol}
echo "wpsec{Dou_Ni_Wan_2333333333}";
#robots.txt
Disallow:./class.php
出题思路:
1.如果直接复制2016 的xctf题目,网上一搜就有很多wp,那么答题者在做题的时候便不认真对待此类题型,对以后出现相关变化题型的话,可能会有弊端
2.不能太简单了,简单了的话随便弄弄就出来了,那就不好玩了
3.前几天不是收集了两组md5么,要是能拿过来用用就好了~~
预期解题思路:

我们查看网站源码,发现有注释,再看红框部分有两个强相等比较,右边的很容易,考的是php伪协议的php://input,能确定$e的值是
php://input
,之后再post一个字符串I'm Administrator!
即可
但是左边的就有点奇怪了,$a不允许php伪协议,那么只能老老实实的去读文件了,而且还不允许越界,只限这个文件夹内,那么说明文件夹中肯定有容易发现的文件
那就猜测吧,或者上扫描器去扫,发现了两个文件,一个flag.php,一个robots.txt


这个flag.php里的flag看起来很诡异。。将这个作为flag提交之后发现确实不正确。那么线索就在robots.txt中了。
我们发现这个文件很简单,而且还告诉了我们有class.php这样一个文件,这样很显然,已经明确了$a和$b的值分别是 robots.txt
、Disallow:./class.php
之后我们再用练了很多遍的老套路,用$c依次获得index.php和class.php 源码(php://filter/read=convert.base64-encode=XXX),最后固定下来$c的值为class.php
index.php文件内容确实和注释一摸一样,class.php的内容如下

观察红色框部分,发现是md5强相等,那么找到$data的另一对md5相同的数据即可,刚好我知道(观众:你TM是作者,你肯定知道啊)。在我之前的文章有提到过这组数据。
#强网杯某大牛wp
$Param1="\x4d\xc9\x68\xff\x0e\xe3\x5c\x20\x95\x72\xd4\x77\x7b\x72\x15\x87\xd3\x6f\xa7\xb2\x1b\xdc\x56\xb7\x4a\x3d\xc0\x78\x3e\x7b\x95\x18\xaf\xbf\xa2\x00\xa8\x28\x4b\xf3\x6e\x8e\x4b\x55\xb3\x5f\x42\x75\x93\xd8\x49\x67\x6d\xa0\xd1\x55\x5d\x83\x60\xfb\x5f\x07\xfe\xa2";
$Param2="\x4d\xc9\x68\xff\x0e\xe3\x5c\x20\x95\x72\xd4\x77\x7b\x72\x15\x87\xd3\x6f\xa7\xb2\x1b\xdc\x56\xb7\x4a\x3d\xc0\x78\x3e\x7b\x95\x18\xaf\xbf\xa2\x02\xa8\x28\x4b\xf3\x6e\x8e\x4b\x55\xb3\x5f\x42\x75\x93\xd8\x49\x67\x6d\xa0\xd1\xd5\x5d\x83\x60\xfb\x5f\x07\xfe\xa2";
#008ee33a9d58b51cfeb425b0959121c9
最后$d的值构建方法如下,由于大部分过滤器都被禁止了,所以构造的过滤器是string.rot13:

然后把数据整合好,提交上去,成功获取flag

End:
彩蛋1:
这里的string.rot13是我在写过滤器的时候发现的,当时代码写错了,但是却仍然能得到flag,而且还是原始值,就感觉特别奇怪,在 win10 php5.6 和 ubuntu16.04 php7.0 上均可以复现,所以就想让大家用这种方法去获取文件内容,所以才把前面的过滤器都禁止掉了。
彩蛋2:
我在ubuntu上用vim创建robots.txt之后,发现poc执行不成功,经过debug发现vim会自动把文件加上0x0A结束符,所以跟我们输入的不一致,而且如果我们输入%0a的话直接在浏览器中就截断了...最后解决的方法是,将文件取到本地,用010Editor删除了最后的linux结束符,然后再塞回去的。。。
彩蛋3:
或许有人注意到class.php中有个字符替换,将空格替换成加号。这是因为在url中,+一般都是用来做空格用的,会变成 0x20 而不是它真正的ascii值0x2b
补充:
考虑到+转空格是基础知识,所以将class.php中$this->chack=str_replace(" ","+", $this->chack);
给去掉了,base64编码的时候记得将+改为%2b
网友评论