【CTF】命令執(zhí)行RCE
一、命令執(zhí)行幾種payload寫法
*方法一*:
查看靶場內(nèi)容,其中過濾了flag字樣,那么也就是說可以執(zhí)行phpinfo()、system()等的命令。一般目標(biāo)的敏感文件位于tmp目錄下,使用命令c=system(“l(fā)s /tmp”)查看tmp目錄下的文件,由結(jié)果可看出其中有flag.php文件。然后使用命令system(“cat /tmp/flag.php”)即理論上可以查看flag文件,由于該頁面過濾了flag字樣,那么即可使用通配符的方式也就可以得到題目的flag值。
*方法二*:
可以在頁面代碼內(nèi)部的c執(zhí)行時,在c中再執(zhí)行一次eval函數(shù),語句如下:
可以看到,命令內(nèi)部是有flag的,但是為何沒有被過濾呢,這是由于頁面代碼對c中的flag進行了過濾,但是c的整體僅是一個內(nèi)部是GET語句的eval語句,而flag并不屬于c中的內(nèi)容,自然也不會被過濾。也就是說傳輸?shù)矫顑?nèi),格式為eval(“eval($_GET[w])”),也就是說外層的eval執(zhí)行的是內(nèi)部字符串表達式的結(jié)果,eval會將內(nèi)部的整體作為代碼執(zhí)行。
eval功能:返回傳入字符串的表達式的結(jié)果。
所以,如果將c=eval(…)內(nèi)部的eval除去后,無法正常顯示flag文件,因為沒有eval函數(shù)后,格式為eval(“($_GET[w])”),eval內(nèi)部沒有任何命令可執(zhí)行,只是普普通通的接受了一個GET傳輸入的w的值,而對他沒有任何處理。
同理還可以在c后使用system命令。
也還可以使用P7-4節(jié)學(xué)習(xí)的php偽協(xié)議,通過語句來獲得:
c=include($_GET[w]);&w=php://filter/convert.base64-encode/resource=/tmp/flag.php
通過該語句得到的是flag文件內(nèi)容的base64編碼形式的結(jié)果。
*方法三*:
還可使用命令echo ls
先查看當(dāng)前目錄下的文件,``反引號是一個操作系統(tǒng)層面的命令,與system函數(shù)同級,但是他執(zhí)行的結(jié)果不打印,結(jié)果不會回顯出來,所以使用了echo命令。
打開靶場后,查看靶場所顯示的源代碼:
其中if語句內(nèi)表示,當(dāng)執(zhí)行一個GET傳入的內(nèi)容c中沒有flag/system/php時,才會執(zhí)行剛剛輸入的c命令。其中preg_match表示做正則匹配的函數(shù)。一般目標(biāo)的敏感文件存放于tmp目錄下,tmp目錄是linux的臨時文件,一般是可讀可寫的。
那么直接可以使用c=eval($_GET[w]);&w=system(“cat /tmp/flag.php”);即可得到flag。
二、payload命令執(zhí)行
首先可以查看,頁面,可以發(fā)現(xiàn)被過濾的字符:
最簡單的一種方式,,使用該語句即可得到flag?;蛘呤褂?/p>
c=include($_GET[w]);&w=php://filter/convert.base64-encode/resource=/tmp/flag.php
也可以得到flag
除了這兩種方法,還有什么高階的方式呢。
由于本題過濾了flag和php,首先使用echo ls
,并且注意,此處的代碼內(nèi)是過濾了空格的,對于空格的跳過,此處不可以使用$IFS
9
的形式來繞過空格,因為
9的形式來繞過空格,因為
9的形式來繞過空格,因為IFS$9是在操作系統(tǒng)中使用的,但是本題是代碼層面的命令,就只能使用%09來繞過空格。首先,為了查看以下本題的tmp目錄下的文件,想要使用echo ls /tmp
命令,即echo%09ls%09/tmp
,即可發(fā)現(xiàn)tmp目錄下的flag文件:
但是能夠發(fā)現(xiàn),本題的過濾時十分嚴(yán)格的,cat等命令都無法使用。既然cat無法使用,那么嘗試命令more/tac等,得到flag:
c=echo%09tac%09/tmp/f*
;
等價于c=echo tac /tmp/flag.php
三、命令執(zhí)行和通配符的繞過
從本題來看,此處過濾的命令更多了,在之前學(xué)習(xí)的命令都無法使用
查看過濾了的字符,其中%、數(shù)字9和空格都被過濾,那么還可以使用${IFS}來繞過空格,然后還可以使用通配符‘?’來繞過對flag的限制。發(fā)現(xiàn)cat也被過濾了,那么可以使用單引號繞過的方式:
c=c'a't${IFS}/tmp/fla?.php
即可得到:
注:此處為什么不能夠?qū)憺閒*代表flag.php文件呢,因為通配符中,*可以表示一個或多個字符,但是‘?’只能代表一個字符,并且本題的*被過濾,無法使用。
還可以使用另一種命令來繞過對cat的過濾,即c=/bin/c?t${IFS}/tmp/fla?.php
也可以:,也能夠執(zhí)行,因為tmp目錄下只有flag一個文件
四、php中讀文件、命令執(zhí)行的函數(shù)
參考博客:
https://blog.csdn.net/weixin_39687736/article/details/123862218
1. *system*
system( c o m m a n d , command, command,return)
執(zhí)行系統(tǒng)命令/php自定義命令,并將相應(yīng)的執(zhí)行結(jié)果輸出,同步進程,執(zhí)行完后進行后續(xù)代碼執(zhí)行。
2. *exec*
exec(
c
o
m
m
a
n
d
,
command,
command,outpub,$return)
exec輸出的是命令執(zhí)行結(jié)果的最后一行內(nèi)容。如果你需要獲取未經(jīng)處理的全部輸出數(shù)據(jù),請使用passthru()函數(shù)。如果想要使用exec顯示當(dāng)前目錄下的所有文件的話,可以使用語句:exec(command:“l(fā)s >> 1.txt”);來將exec讀取到的當(dāng)前目錄下的所有文件名導(dǎo)入到一個新創(chuàng)建的1.txt文件中。
<< : 疊加; < : 覆蓋
3. *passthru*
passthru( c o m m a n d , command, command,return_var)
與system函數(shù)同級,若今后題目中system函數(shù)被過濾了,即可使用它。
4. *shell_exec*
shell_exec($command)
與exec一樣,無回顯,需要使用echo顯示結(jié)果。
5. 反引號`
echo `command`
反引號和shell_exec意思相同
在php中稱之為執(zhí)行運算符,PHP 將嘗試將反引號中的內(nèi)容作為 shell 命令來執(zhí)行,并將其輸出信息返回
6. …(見上方連接)
*php中讀文件函數(shù)*:
可使用echo fiel_get_contents(“flag.php”)該語句是以流的形式讀取文件,需要在查看頁面源代碼中查看讀取到的接果。
hightlight_file(“flag.php”),不需要使用echo
五、intval函數(shù)繞過:
函數(shù):
① isset():用于檢測變量是否已設(shè)置并且非NULL。
② preg_match():正則匹配,前一參數(shù)放要搜索的內(nèi)容,后一參數(shù)是需要被匹配的內(nèi)容,測試被匹配內(nèi)容中是否存在要搜索的內(nèi)容。例如本題即num中不能有數(shù)字。
③ die():函數(shù)輸出一條消息,并退出當(dāng)前腳本。本題中即當(dāng)num中有數(shù)字,輸出nonono。
④ intval():用于獲取變量的整數(shù)值。
*intval函數(shù)*:
*語法*:
int intval ( mixed $var [, int $base = 10 ] )
*參數(shù)說明*:
$var:要轉(zhuǎn)換成 integer 的數(shù)量值。
$base:轉(zhuǎn)化所使用的進制。
*如果 base 是 0,通過檢測 var 的格式來決定使用的進制*:
如果字符串包括了 “0x” (或 “0X”) 的前綴,使用 16 進制 (hex);否則,
如果字符串以 “0” 開始,使用 8 進制(octal);否則,
將使用 10 進制 (decimal)。
*返回值*
成功時返回 var 的 integer 值,失敗時返回 0。 空的 array 返回 0,非空的 array 返回 1。
最大的值取決于操作系統(tǒng)。 32 位系統(tǒng)最大帶符號的 integer 范圍是 -2147483648 到 2147483647。舉例,在這樣的系統(tǒng)上, intval(‘1000000000000’) 會返回 2147483647。64 位系統(tǒng)上,最大帶符號的 integer 值是 9223372036854775807。
字符串有可能返回 0,雖然取決于字符串最左側(cè)的字符。
在對intval函數(shù)的返回值處,發(fā)現(xiàn)如果傳入空的array(數(shù)組),則會返回0,非空的array則會返回1,那么只需要傳入一個非空的數(shù)組,即可實現(xiàn)讓本程序輸出flag值。
要如何傳入一個數(shù)組呢,格式:num[]=w,即在需要傳入的num后加上方括號,即代表此時傳入的是一個數(shù)組,并且使傳入的數(shù)組為非空且無數(shù)字,即可得到flag。
并且,本題如果直接書寫為num[]=或者num[]也可以得到flag,因為如果不定義num的值的話,默認(rèn)num有一個值為空,也滿足條件。
例題:
得到代碼后,分析代碼:
分析本題,當(dāng)num為4476時,程序會die,并輸出nonono,但是想要獲得flag的話,又需要num為4476。
那么這里就涉及到intval函數(shù)的一個知識點,當(dāng)int intval ( mixed $var [, int $base = 10 ] )中的base為0時,通過檢測 var 的格式來決定使用的進制,
如果字符串包括了 “0x” (或 “0X”) 的前綴,使用 16 進制 (hex);否則,
如果字符串以 “0” 開始,使用 8 進制(octal);否則,
將使用 10 進制 (decimal)。
那么推測,是否可以通過輸入16進制或者8進制的num值,來繞過本程序的檢驗,先進行進制轉(zhuǎn)換
4476的16進制:0x117c,8進制:010574
嘗試將上述兩種進制以格式傳入,
十六進制:num=0x117c
八進制:num=010574
使用以上兩種方式,都成功的獲取到了本題的flag。
除了以上的方法,由于intval會取整,可以使用小數(shù)的方式來得到,例如輸入4476.1、4476w等方式,都能夠得到flag。
六、php弱類型特性
**屬于弱類型校驗,只校驗值是否一樣,不校驗類型,而=**屬于強類型校驗,不僅校驗值,還校驗類型。
本題及表示,當(dāng)a與b同時都有POST輸入,而a與b的傳輸不相同,但是a和b的md5值相同,才能夠得到flag,否則輸出wrong。
*方法一*:
*md5()函數(shù)*:
*語法:*
md5(string,raw)
*定義和用法:*
md5() 函數(shù)計算字符串的 MD5 散列。
md5() 函數(shù)使用 RSA 數(shù)據(jù)安全,包括 MD5 報文摘要算法。
來自 RFC 1321 的解釋 - MD5 報文摘要算法:MD5 報文摘要算法將任意長度的信息作為輸入值,并將其換算成一個 128 位長度的"指紋信息"或"報文摘要"值來代表這個輸入值,并以換算后的值作為結(jié)果。MD5 算法主要是為數(shù)字簽名應(yīng)用程序而設(shè)計的;在這個數(shù)字簽名應(yīng)用程序中,較大的文件將在加密(這里的加密過程是通過在一個密碼系統(tǒng)下[如:RSA]的公開密鑰下設(shè)置私有密鑰而完成的)之前以一種安全的方式進行壓縮。
如需計算文件的 MD5 散列,請使用 md5_file() 函數(shù)。
md5() 函數(shù)不能處理數(shù)組,數(shù)組都返回 null,md5(a[]) 結(jié)果為 null。
本題運用到了md5()函數(shù)的不能處理數(shù)組,數(shù)組都返回 null,md5(a[]) 結(jié)果為 null的特性,當(dāng)給a和b傳入不同兩個數(shù)組時,在第一步判斷時不會認(rèn)定a與b相同,但是在第二步判斷時,由于md5函數(shù)不能處理數(shù)組,所以會返回null那么即可傳輸:a[]=1&b[]=2,即可得到flag:
*方法二*:
PHP在處理哈希字符串時,會利用”!=”或”==”來對哈希值進行比較,它把每個以”0E”開頭的哈希值都解釋為0,因此若是兩個不一樣的密碼通過哈希之后,其哈希值都是以”0E”開頭的,那么PHP將會認(rèn)為他們相同,都是0。
因為php中0e代表0的科學(xué)計數(shù)法,無論后面的數(shù)字跟的是多少,結(jié)果都等于0。
http://www.javashuo.com/article/p-adowhkuk-q.html
然后在本題中,利用一些經(jīng)過md5加密后開頭為0e的原始值,來對a和b進行賦值,即可成功繞過:
a=s878926199a&b=s155964671a
七、變量覆蓋
*函數(shù)*:
*定義和用法*
parse_str() 函數(shù)把查詢字符串解析到變量中。
****注釋:****如果未設(shè)置 array 參數(shù),由該函數(shù)設(shè)置的變量將覆蓋已存在的同名變量。
****注釋:****php.ini 文件中的 magic_quotes_gpc 設(shè)置影響該函數(shù)的輸出。如果已啟用,那么 在 parse_str() 解析之前,變量會被 addslashes() 轉(zhuǎn)換。
*語法*
parse_str(string,array)
*參數(shù)* | *描述* |
---|---|
string | 必需。規(guī)定要解析的字符串。 |
array | 可選。規(guī)定存儲變量的數(shù)組名稱。該參數(shù)指示變量存儲到數(shù)組中。 |
*方法一**:*
結(jié)合parse_str()函數(shù)的性質(zhì),本題需要傳入兩個值,一個是post傳輸?shù)膙1和一個GET傳輸?shù)膙3,也就是說本題需要傳入一個v1=‘flag’=(v3的md5加密后的值)。
接下來執(zhí)行后即可獲得本題的flag。
*方法二*:
運用md5()函數(shù)對數(shù)組進行操作后結(jié)果為null的性質(zhì),對v3當(dāng)作數(shù)組進行傳入值,然后不對v1傳入任何值也可獲得本題的flag。
$$變量覆蓋
*foreach有兩種語法:*
*第一種*:遍歷給定的 數(shù)組語句 array_expression 數(shù)組。每次循環(huán)中,當(dāng)前單元的值被賦給 $value 并且數(shù)組內(nèi)部的指針向前移一步(因此下一次循環(huán)中將會得到下一個單元)。
foreach (array_expression as $value)
*第二種*:同上,同時當(dāng)前單元的鍵名也會在每次循環(huán)中被賦給變量 $key。
foreach (array_expression as $key => $value)
本題的foreach函數(shù)里有GET和POST兩個參數(shù),那么也就是證明,可以自定義的通過GET/POST的方式傳輸進幾個變量,并通過鍵值對的形式賦值。
* k e y = key= key=value*:
當(dāng)傳入一個a=1時,此時變?yōu)榱?a= 1 ,也就是把 a 變換為了變量 1,也就是把a變換為了變量 1,也就是把a變換為了變量a,把1變?yōu)榱俗兞?1,并把 1 賦值給 1賦值給 1賦值給a。這與$ k e y = key= key=value有何區(qū)別呢,當(dāng)value傳入一個值后,其由于$value本身就是一個變量,他就會表示一個具體的變量的值。
那么對于本題而言,出現(xiàn)了兩次 k e y = key= key=value,再結(jié)合下方的if語句:
只要阻止這一步執(zhí)行了die命令,就可以獲得flag,但是想要使傳入的flag等于題目的flag顯然是不現(xiàn)實的,也就是說在最后一個if語句處,一定會die,但是可以通過變量相等的傳遞,來逐步實現(xiàn)。比如對于本題,在第一個foreach處先傳入一個suces=flag,然后在第二個foreach處通過error=suces的形式,即可實現(xiàn)對flag和error兩個字符串的過濾(因為他們變成變量的形式了)。在最后一個if語句,執(zhí)行了die( e r r o r ) ,但是此時的 e r r o r 已經(jīng)等于了 error),但是此時的error已經(jīng)等于了 error),但是此時的error已經(jīng)等于了flag,也就是說,輸出的會是flag。
那么經(jīng)過兩次傳參,也就是說
第一次: s u c e s = suces= suces=flag
第二次: e r r o r = error= error=suces
也就是說,此時的 e r r o r 在值上等于 error在值上等于 error在值上等于flag,那么即可通過die($error)語句,獲得flag。文章來源:http://www.zghlxwxcb.cn/news/detail-769752.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-769752.html
到了這里,關(guān)于【CTF】命令執(zhí)行RCE的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!