您好,登錄后才能下訂單哦!
這篇文章給大家介紹如何從一道CTF題目談PHP中的命令執(zhí)行,內(nèi)容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
快睡的時候,打開B站發(fā)現(xiàn)有位用戶留言,大意就是讓我?guī)兔匆坏李},正好當(dāng)時有空,于是就打開了他發(fā)的鏈接,代碼如下
很明顯是一道PHP代碼審計的題目,而且只需要繞過第三行的if即可進行任意命令執(zhí)行。
解決思路
看了代碼之后覺得是道普通的題目,對于/a-zA-Z/這個正則表達式,我們可以利用PHP動態(tài)函數(shù)的特性,構(gòu)造出字符串即可。
對于想要的字符串,我們可以通過以下三種方式來構(gòu)造:
1. 異或
對于PHP中的字符串,兩個字符串異或的結(jié)果是將兩個字符串逐位異或,返回一個新字符串。那么我們便可以使用此特性進行構(gòu)造。
例如我們需要構(gòu)造phpinfo,則可以用腳本得到('0302181', '@[@[_^^')這兩個字符串,腳本如下:
其中valid是可用的字符,answer是我們需要構(gòu)造的字符串。那么我們得到了這個字符串,又該如何去執(zhí)行呢。我們可以通過一個變量存儲兩字符串異或后的值,再讓這個變量進行動態(tài)函數(shù)執(zhí)行即可,而變量的話因為PHP的變量命名規(guī)則和C語言相同,可以使用下劃線進行命名,如下:
2. 取反構(gòu)造
和第一種類似,都是基于PHP字符串位運算的特點(會逐位進行位運算)。而取反構(gòu)造某些情況比異或構(gòu)造要方便,因為異或的情況某些字符是無法直接通過其他字符進行異或構(gòu)造的,而取反卻可以利用漢字或者其他特殊字符進行構(gòu)造(不會有題目會限制某個漢字吧)。比如字母s我們可以通過~('和'{2})得到。而這個時候如果要用異或去構(gòu)造的話,你得找到兩個異或值為s的特殊字符。
取反構(gòu)造的腳本和異或構(gòu)造類似,在此不再給出。
3. 自增構(gòu)造
`++'a' == 'b'
`
這個特點是利用了PHP是弱類型語言的特性,在對變量進行操作的時候,PHP會隱式的轉(zhuǎn)換其變量類型,很多代碼審計的題目也是利用了這一特性。
遇到障礙
有了上面的思路后,而且也成功執(zhí)行了phpinfo(),下一步是不是就可以直接構(gòu)造命令執(zhí)行函數(shù)去進行讀取文件,當(dāng)時我也是這么想的,于是我構(gòu)造了passthru(), system(), shell_exec(), exec()等函數(shù),都受到了阻礙,沒有回顯,通過進一步的調(diào)試之后發(fā)現(xiàn)是禁用了這些函數(shù)(通過在函數(shù)后面加一個打印函數(shù)觀察是否執(zhí)行)。
在這里我停留了很久,試過打印$GLOBALS等都沒有任何有用的信息。最后通過使用glob()函數(shù)進行目錄掃描,發(fā)現(xiàn)了flag.php文件,以及file_get_contents()進行獲取,最終的payload如下
?mess=$_="`0123"^"?`~``";${$_}[_](${$_}[__]);&_=assert&__=print_r(base64_encode(file_put_contents("flag.php")))
最后再將其界面就可以得到最終的flag了。在最終的payload中我沒有去一個一個的構(gòu)造字符串異或,因為那太長了,而是構(gòu)造了一個$_POST[_]($_POST[__])的動態(tài)函數(shù),這樣就可以在其他參數(shù)位置直接寫函數(shù)了。
深入分析
題目到這里就結(jié)束了,其實并沒有多難,首先是通過特性去構(gòu)造動態(tài)函數(shù),然后發(fā)現(xiàn)了命令執(zhí)行被禁用之后,能夠知道使用其他函數(shù)去進行獲取信息就行了。但是做完這道題后,不僅引發(fā)了我的思考,PHP中的命令執(zhí)行就只有這些方式了嗎,肯定不是。于是,我總結(jié)了幾種新的命令執(zhí)行技巧供大家參考。
1. 當(dāng)打印函數(shù)被禁用時
如果沒有了打印函數(shù),意味著你無法看到回顯,這時候即使命令執(zhí)行成功了你也無法得到信息,這個時候你就得利用其他方式去獲取回顯了。
首先是網(wǎng)上很多blog使用的方式,phpinfo如果發(fā)現(xiàn)開啟了curl,或者其他文件傳輸擴展的的話,可以自建一個靶機,將所有訪問信息存入數(shù)據(jù)庫或是文件,然后將回顯信息發(fā)送到你的靶機地址,這樣你去看日志就可以了,這種方式不是很方便而且有一定的局限性。這里我要介紹的是一種新的方式。
如果你使用過Django或者jsp開發(fā)web的話,你肯定知道輸出一個變量可以使用{{xxx}}或是<%=xxx%>的方式,那么在PHP中是否也有這種方式呢,答案是肯定的,PHP中的<?=xxx?>就可以將一個變量輸出,那么如果使用它呢,你只需要構(gòu)造如下的payload
$_="xxx";?><?=$_?>
這樣就可以將變量$_里面的內(nèi)容打印到屏幕上,而且關(guān)鍵的是這個輸出方式默認是開啟的,管理員很容易就忽視這個選項。所以在做題時不妨一試。
2. 其他的命令執(zhí)行方式
當(dāng)system,passthru等不能用時,網(wǎng)上會告訴你可以使用popen,proc_open這些管道命令去進行執(zhí)行命令,當(dāng)然這沒有問題,而這里我向你介紹一種新方式,使用反引號,在PHP中,被兩個反引號括起來的內(nèi)容將會作為shell命令執(zhí)行,并將輸出信息返回,所以你可以構(gòu)造下面的payload進行命令執(zhí)行
$_=`ls`;
3. 不能使用數(shù)字字母的命令執(zhí)行
當(dāng)不能使用字母數(shù)字時,當(dāng)然你可以使用上述的方式構(gòu)造字符串進行執(zhí)行,但是這里提供一些新東西,對于linux中的shell是支持正則表達式的,當(dāng)你忘記某些字符時可以通過? % *來代替,經(jīng)過測試,這里的匹配方式也是按照順序進行匹配,所以你可以查看你的linux中/bin目錄下面的順序,來獲取一些可以使用的命令,比如
=> /bin/cat
那么這樣的話,如果要獲取/var/www/html/index.php(你得感謝apache默認目錄如此之深),則可以直接使用來獲取
這篇文章只是針對這道題而延展出的一些東西,在真正做題時,情況可能更加復(fù)雜,例如限制長度,限制參數(shù)等等情況,而我們的做法也不可能千篇一律,可能某些時候我們甚至?xí)玫揭恍〤VE漏洞。而本篇文章只是告訴讀者一些可能以前沒有見過的新東西。
關(guān)于如何從一道CTF題目談PHP中的命令執(zhí)行就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。