php strlen遇0截断,聊下php下的截断问题
0x01 起因
有天在群里說起上傳的%00截?cái)嗟囊恍﹩栴},就想起之前自己在這個(gè)問題踩過坑,想起了自己曾經(jīng)的flag說要寫文章,一直沒寫,現(xiàn)在來填坑了。
0x02 經(jīng)過
源碼理解1
2
3
4//test.php
include "1.txt\000.jpg";
?>
1
2
3
4//1.txt
echo 'helloworld';
?>
上面的示例代碼在 php版本小于5.3.4 的情況下回輸出 helloworld 。從php的內(nèi)核執(zhí)行過程來看,PHP通過 php_execute_script 來執(zhí)行PHP的腳本,這里選取部分有關(guān)代碼,具體可以看這里:
在 第10行 我們看到,他調(diào)用 zend_execute_scripts 來針對(duì)腳本進(jìn)行解析,而這個(gè)函數(shù)是在Zend/zend.c里面,截取部分相關(guān)代碼如下:
從PHP內(nèi)核開來實(shí)際上是分為兩塊部分,一個(gè)是 compile編譯過程 ,另一個(gè)是execute執(zhí)行過程。
第一部分:compile編譯過程
我們可以看到這里的代碼邏輯通過 zend_compile_file 獲取文件的內(nèi)容,zend_compile_file是一個(gè)函數(shù)指針,其聲明在/Zend/zend_compile.c中
1ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
在引擎初始化的時(shí)候,會(huì)將 compile_file 函數(shù)的地址賦值給 zend_compile_file 。
簡單總結(jié)一下上面部分代碼的邏輯:
zend_compile_file 函數(shù)首先調(diào)用 open_file_for_scanning 去讀取文件,然后通過 第17行的zendparse 去進(jìn)行語法和詞法解析。而 zendparse 是通過 lex_scan 去掃描出token并進(jìn)行語法分析。
第二部分:execute執(zhí)行過程
zend_execute 也是一個(gè)函數(shù)指針,其聲明在/Zend/zend_execute.h中。
1ZEND_API extern void (*zend_execute)(zend_op_array *op_array TSRMLS_DC);
在引擎初始化的時(shí)候,會(huì)將 execute 函數(shù)的地址賦值給 zend_execute 。
根據(jù)我們的了解,zend_execute 通過 ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER 函數(shù)來進(jìn)行include的實(shí)際處理,即包含要包含的文件。
對(duì)比修復(fù)代碼找到漏洞觸發(fā)點(diǎn):
摘出部分修復(fù)代碼:
我看下存在漏洞的調(diào)試運(yùn)行結(jié)果:
修復(fù)代碼的 Z_STRVAL_P(inc_filename) 即上圖中的val,即”1.txt”,strlen取得長度為5,而 Z_STRLEN_P(inc_filename) 即上圖中的len即10。這里實(shí)際上解析到的文件名是1.txt。
不存在漏洞的調(diào)試運(yùn)行結(jié)果:
一旦出現(xiàn)%00截?cái)?#xff0c;include的文件名經(jīng)過url轉(zhuǎn)碼由”1.txt%00.jpg”變?yōu)椤?.txt\000.jpg”,進(jìn)入php語法詞法分析器解析后會(huì)將這個(gè)字符串解析成一個(gè)字符串,并使用 zend_scan_escape_string 進(jìn)行字符串轉(zhuǎn)碼,如圖,進(jìn)入 zend_scan_escape_string 的內(nèi)容為:
只要比較發(fā)現(xiàn)文件名的strlen長度和語法分析出來的長度不一樣,就說明內(nèi)部存在截?cái)嗟淖址?#xff0c;因此輸出了打開文件失敗的信息。
利用方式
劃重點(diǎn) PHP版本低于5.3.4
%00截?cái)嘤羞@么2種利用狀況
在burpsuite的16進(jìn)制編輯工具將”shell.php .jpg”(帶空格的)中間的空格由20改成00
在1中,url中的%00(形如%xx),web server會(huì)把它當(dāng)作十六進(jìn)制處理,然后將該十六進(jìn)制數(shù)據(jù)hex(00)“翻譯”成統(tǒng)一的ascii碼值“NUL(null)”,實(shí)現(xiàn)了截?cái)唷?/p>
在2中,burpsuite用burp自帶的十六進(jìn)制編輯工具將”shell.php .jpg”(中間有空格)中的空格由20改成00,如果burp中有二進(jìn)制編輯工具。
延伸一下
其實(shí)關(guān)于截?cái)嘞嚓P(guān)問題,還有個(gè)很有趣的函數(shù), iconv() 函數(shù):
在了解 iconv() 函數(shù)漏洞之前,可能需要一點(diǎn)前置知識(shí)
在php中,所有的字符都是二進(jìn)制的串,PHP本身并不認(rèn)識(shí)任何編碼,只是根據(jù)編碼來顯示內(nèi)容。PHP中的chr() 函數(shù)從指定的 ASCII 值返回字符。ASCII 值可被指定為十進(jìn)制值、八進(jìn)制值或十六進(jìn)制值。八進(jìn)制值被定義為帶前置 0,而十六進(jìn)制值被定義為帶前置 0x。
而在php5.4之前, iconv() 函數(shù)在轉(zhuǎn)換編碼的時(shí)候,遇到不合法的字符串的時(shí)候會(huì)將其截?cái)唷?/p>
1
2
3
4
5
6
7<?php
for($k=0;$k<=255;$k++)
{
$a='shell.php'.chr($k)."1.jpg";
echo 'k:'.$k.' '.'$a:'.$a.' '.'iconv("UTF-8","gbk",$a):'.iconv("UTF-8","gbk",$a)."\n";
}
?>
通過fuzz發(fā)現(xiàn),其中 iconv(“UTF-8”,”gbk”,$a) 或是 iconv(“UTF-8”,”gb2313”,$a) 都會(huì)在chr(128)到chr(255)之間截?cái)?#xff0c;使結(jié)果為shell.php
在php5.4.0版本的時(shí)候就不存在這個(gè)問題了。
實(shí)際例子
關(guān)于我們剛剛說的 iconv() 截?cái)嗟膯栴},其實(shí)sitestar pro就是個(gè)典型例子,我們看個(gè)例子:
漏洞觸發(fā)點(diǎn)在 module/mod_tool.php 中的 img_create() 函數(shù),截取部分代碼如下:
這部分中有段代碼吸引了我的注意力
1
2
3
4if(!preg_match('/\.('.PIC_ALLOW_EXT.')$/i', $file_info["name"])) {
Notice::set('mod_marquee/msg', __('File type error!'));
Content::redirect(Html::uriquery('mod_marquee', 'upload_img'));
}
跟進(jìn)一下這個(gè) PIC_ALLOW_EXT 參數(shù),發(fā)現(xiàn)其在數(shù)據(jù)庫中寫死了,只允許 gif|jpg|png|bmp 這類文件。即如果文件名最后不是 gif|jpg|png|bmp ,則提示文件類型錯(cuò)誤。
所以這部分的正則表達(dá)式的功能應(yīng)該是針對(duì)文件后綴名進(jìn)行檢查。
繼續(xù)跟進(jìn)這部分代碼,有一串代碼如下:
1
2
3
4if (!$this->_savelinkimg($file_info)) {
Notice::set('mod_marquee/msg', __('Link image upload failed!'));
Content::redirect(Html::uriquery('mod_marquee', 'upload_img'));
}
這部分代碼應(yīng)該是進(jìn)行文件保存的功能,這個(gè)有個(gè)核心函數(shù) _savelinkimg ,跟進(jìn)這個(gè)函數(shù)。
第二行問題出現(xiàn)了
1$struct_file['name'] = iconv("UTF-8", "gb2312", $struct_file['name']);
在 iconv 轉(zhuǎn)碼的過程中, utf->gb2312 (其他部分編碼之間轉(zhuǎn)換同樣存在這個(gè)問題)會(huì)導(dǎo)致字符串被截?cái)?#xff0c;如:$filename="shell.php(hex).jpg; (hex為0x80-0x99),經(jīng)過 iconv 轉(zhuǎn)碼后會(huì)變成 $filename="shell.php" ;
0x03 結(jié)果
總結(jié)一下截?cái)啻蟾趴梢栽谝韵虑闆r適用
include(require)
file_get_contents
file_exists
所有url中參數(shù)可以用%00控制
0x04 參考文獻(xiàn)
潛伏在PHP Manual背后的特性及漏洞(看雪峰會(huì)議題)
wooyun-2014-048293
總結(jié)
以上是生活随笔為你收集整理的php strlen遇0截断,聊下php下的截断问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 坦克加装高射炮和滑膛炮哪个更强?
- 下一篇: java websocket ie8_w