作者:nannet
信息來源:中國***聯盟(www.chinawll.com) 今天我的決定和大家探討一些我的一些在PHP代碼審計方面一些脆弱性的方法的經驗。 如果你記得,大約一年前,我寫過這篇文章。 PHP代碼審計的20種方法。 一段時間以前,“Stefan Esser” 做了一個關於PHP安全性的模板,我將以我的經驗給大家簡短的概括一下,PHP代碼審計: 大多數PHP代碼的漏洞: 1.跨站式腳本 2.跨站請求僞造 3.SQL注入 4.不安全的會話處理 5.session劫持 6.信息公開 7.頭注入漏洞 8.不安全的配置 9.脆弱的隨機性 想要知道更多如何從你的源碼中找到問題的所在的信息,請閱讀我的文章 http://www.abysssec.com/blog/2009/03/php_fuzz_audit/ 或者另一個描述(發現PHP注入漏洞) http://www.milw0rm.com/papers/381 這些問題由於代碼編寫的不正確 1--不安全的會話處理 接受用戶一些沒有被注入的輸入 2--檢測 檢測功能可以用作是“修補”用戶的輸入,關於請求的嚴格性(比如:規定的數據類型,最大長度)來代替拒絕潛在危險的完整輸入,總的來說檢測功能的使用並不被支持,因爲確定的項和結構體的安全過濾,很可能有他們的自己的安全隱患。另外由於打印錯誤的自動更正可能會使得輸入在語法上或者語義上報錯。舉個例子: is_numeric()Checks a variable for numeric content檢測一個數字型的變量 is_array()Checks if a variable is an array檢測一個是否爲數組的變量 strlen()Returns a string‘s length. 返回字符長度 strip_tags()Removes HTML and PHP tags. 3--溢出 這裏有一些不同種類的溢出方式: 1.反斜槓前綴“\”定義了一些字符串不超過這個字符,舉個例子:\t是一個tab空間,\n是一個另啓一行的字符串,這個可以作爲這個函數的特殊的功能,在對於另起一行的字符串有特殊的目的。比如header()。在這些規範的表達之內,反斜槓時通常被用作去溢出這些有特殊目的的字符,比如像\. or \*, 這些是和所有函數處理規範的表達所相關的。 2.HTML 加密翻譯字符時通常被網頁瀏覽器譯成HTML他們的加密等價的。– e.g. < is < or < or < and > is > or > or >. HTML加密應該被用作是輸出處理,而用戶的輸入應該被反映進HTML裏面,同時沒有注入代碼。 3.URL 加密確保,每個字符沒有被允許在URL內。根據RFC 1738,被適當的譯成E.g. space converts to + or %20 and < is %3C. 這個溢出和函數處理URL是相關的。例如urlencode()和urldecode()。 4--配置 程序錯誤,包括邏輯程序。 好,我們知道有四點在過程中可以幫助我們。 1.我們PHP輸入點: 我們需要發現他們和所有的函數功能和變量,而這些必須指定分配給他們 在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 2限制我們的理解 很好,第二點,我們的問題也就從這裏開始,就像以前一樣,我們不能從代碼中發現一些錯誤。因爲,程序設計者用了一些限制功能。舉個例子,無論在哪裏,我們可以看見接下來的函數可以控制輸入變量,很可能當許多***的時候被執行。所有你只有兩種方法:一你從你的邏輯代碼中找出問題,二你從你的PHP代碼中找出PHP錯誤。 A. 溢出和加密功能 A-1 (XSS dies = 90% 直接的翻譯是一個夢想) : htmlspecialchars() ,溢出字符& < and > as HTML , 爲了保護應用程序遭到安全漏洞XSS。正確的字符和模型 ENT_QUOTES 應該被使用。 1 <?php 2 echo "Hello " . htmlspecialchars( $_GET['name'], ENT_QUOTES); 3 ?> htmlentities(), 對所有的應用字符采用HTML實體加密程序來保護應用程序遭到安全漏洞XSS。正確的字符和模型 ENT_QUOTES 應該被使用。 1 <?php 2 echo "Hello " . htmlentities( $_GET['name'], ENT_QUOTES); 3 ?> ( htmlentities() 在特殊的事件中繞回 [utf7] : http://pstgroup.blogspot.com/2007/11/bypass-htmlentities.html ) urlencode() , 採用URL加密被看做是URL的查詢部分。 1 <?php 2 $url = "http://www.example.com/" . "index.php?param=" . urlencode($_GET['pa']); 3 ?> A-2 : (SQL injection dies = 90% The direct transition is a dream) : addslashes() : 採用一個簡單的反斜槓溢出,輸入字符串被假設爲單字節的密碼。addslashes() 不能被用作是保護程序對抗SQL注入,直到所有的數據庫系統運行了多字節的加密字符串。比如UTF-8。 addcslashes() : 採用一個簡單的反斜槓溢出,這是可以被用來是字符串被用作在JavaScript 字符串。然而用這種函數來保護程序來對抗 HTML tag 注入也是沒有可能性的。 (bypass addslashes() in special case : http://sirdarckcat.blogspot.com/2009/10/couple-of-unicode-issues-on-php-and.html) mysql_real_escape_string(), 溢出一個字符串用在mysql_query(),在當MySQL連接當中的字符是要被考慮到的,所以在多字節加密字符串上運行是很安全的。應用程序工具字符串溢出被用作抵抗SQL注入***是可以用這種函數的。 1 <?php 2 $sql = "SELECT * FROM user WHERE" . " login='" . mysql_real_escape_string( $_GET['login'], $db) . "'"; 3 ?> A-3 : (XSS , SQl Inject = 100% The direct transition is a dream) : preg_quote() , 應該被用作溢出用戶輸入被插入正規的表達,這種方法,正規的表達被很好的從語義操作上保護了。 1 <?php 2 $repl = preg_replace('/^' . preg_quote($_GET['part'], '/'). '-[0-9]{1,4}/', '', $str); 3 ?> 有問題的代碼: 1 <?php 2 $h = $_GET['h']; 3 echo preg_replace("/test/e",$h,"jutst test"); 4 ?> It works like this: http://site.com/test.php?h=phpinfo() B- CType Extension : ? ctype_alnum()字母數字字符 – A-Z, a-z, 0-9 ? ctype_alpha()字母字符– A-Z, a-z ? ctype_cntrl() 控制字符– e.g. tab, line feed ? ctype_digit()數字字符 – 0-9 ? ctype_graph()字符創造一個可見的輸出 e.g. no whitespace ? ctype_lower()小寫字符 – a-z ? ctype_print()打印的字符 ? ctype_punct()標點字符 – printable characters, but not digits, letters or whitespace, e.g. .,!?:;*&$ ? ctype_space()白色空間字符 – e.g. newline, tab ? ctype_upper()大寫字符 – A-Z ? ctype_xdigit() 十進制和十六進制 – 0-9, a-f, A-F 1 <?php 2 if (!ctype_print($_GET['var'])) { 3 die("User input contains ". "non-printable characters"); 4 } 5 ?> C – Filter Extension – ext/filter 從PHP 5.2.0 開始,過濾伸展提供了一個簡單的API輸入確證和輸入過濾。 filter_input(): 調回GET, POST, COOKIE, ENV or SERVER 這些變量的內容,採用特殊的過濾。 1 <?php 2 $url = filter_input(INPUT_GET, 'url', FILTER_URL); 3 ?> filter_var(): 過濾一個變量用特殊過濾。 1 <?php 2 $url = filter_var($var, FILTER_URL); 3 ?> 所有過濾的的列表: ? FILTER_VALIDATE_INTChecks 無論輸入是一個整數類型 ? FILTER_VALIDATE_BOOLEANChecks 無論輸入是一個boolen類型 ? FILTER_VALIDATE_FLOATChecks 無論輸入是一個浮點數 ? FILTER_VALIDATE_REGEXPChecks 輸入不符合規定的輸入法 ? FILTER_VALIDATE_URLChecks 無論輸入是一個URL ? FILTER_VALIDATE_EMAILChecks 輸入是一個email地址 ? FILTER_VALIDATE_IPChecks 無論輸入是一個IPv4 or IPv6. Sanitising Filters ? FILTER_SANITIZE_STRING / FILTER_SANITIZE_STRIPPEDStrips and HTML-encodes characters according to flags and applies strip_tags(). ? FILTER_SANITIZE_ENCODEDApplies URL encoding. ? FILTER_SANITIZE_SPECIAL_CHARSEncodes ‘ ” < > & \0 and optionally all characters > chr(127) into numeric HTML entities. ? FILTER_SANITIZE_EMAILRemoves 所有的字符不能被用在email地址 ? FILTER_SANITIZE_URLRemoves 所有的地址不能被用在URL ? FILTER_SANITIZE_NUMBER_INTRemoves all characters except digits and + -. ? FILTER_SANITIZE_NUMBER_FLOATRemoves all characters not allowed in floating point numbers. ? FILTER_SANITIZE_MAGIC_QUOTESApplies addslashes(). Other Filters ? FILTER_UNSAFE_RAWIs a dummy filter. ? FILTER_CALLBACKCalls a userspace callback function defining the filter. D) HTTP Header Output HTTP 頭文件可以被用在header() 函數中,用戶輸入在被送入header() 總是被先檢查,否則會遇到代碼安全性的問題。另起一行的字符不能被用在header() 中以至於防止HTTP頭注入。被注入的頭文件也可以被用作XSS和HTTP***。總的來說,用戶輸入必須被處理在一個區分上下文的方式當中。 1 <?php 2 if (strpbrk($_GET['type'], ";/\r\n")) die('invalid characters'); 3 header("Content-Type: text/" . $_GET['type'] . "; charset=utf-8;"); 4 ?> E)Secure File Handling: 查找和代替NULL字節 1 <?php 2 if (strpos($_GET["f"], "\0") === true) { 3 $file = str_replace("\0", "", $_GET["f"]); 4 } 5 ?> 防止遠程文件 1 <?php 2 $file = "./".basename($_GET["f"]). ".php"; 3 ?> 1 <?php 2 if (in_array($_GET['action'], array('index', 'logout'))) { 3 include './'.$_GET['action'] . '.php'; 4 } else die('action not permitted'); 5 ?> 3)配置點 : 最後一點,在程序結構中的漏洞,源代碼審計中最巧妙地一部分。 我們看到接下來的這些配置 源代碼或者是PHP 【a】當服務器遠程URL對這些文件進行處理功能 文件處理功能就像打開文件包括接受URL類似於文件參數。舉個例子(fopen(‘http://www.example.com/’, ‘r’)) 儘管他們可以像HTTP URLs,這樣就產生了一個巨大的安全危險,如果用戶輸入沒有正確的語義,就相當於在服務器上對遠程代碼開啓了一扇門。 Register Globals is ‘ON’ : 在PHP4.2.0通常用來輸入值作爲全局變量,這樣就在註冊的全局上被命名,這就在很多的網絡的應用程序上對安全性負責任,因爲這使得***者在很多情況下可以很輕鬆的控制全局變量,但是幸運的是從PHP4.2.0開始就不能了,因爲在很多時候這是非常危險的。 1 <?php 2 if (ereg("test.php", $PHP_SELF)==true) 3 { 4 include $server_inc."/step_one_tables.php"; 5 } 6 ?> 真實的例子: Exp 1 : PHP Code Execution: <?php // Replace any usernames $ret = preg_replace("#\[:nom[^\]]*)\]#e", "username(0, trim(\"\\1\"))", $ret); ?> php code execution is possible via complex variable evaluation. [:nom:{${phpinfo()}}] or this code <?php if($globals['bbc_email']){ $text = preg_replace( array("/\[email=(.*?)\](.*?)\[\/email\]/ies", "/\[email\](.*?)\[\/email\]/ies"), array('check_email("$1", "$2")', 'check_email("$1", "$1")'), $text); } ?> 2-配置錯誤:審計迂迴 <?php list($user,$hash) = unserialize(stripslashes($_val)); $user = trim(genc('get',$user)); $req = "SELECT user_nickname, user_password FROM {$jamroom_db['user']} WHERE user_nickname = '". dbEscapeString($user) ."' LIMIT 1"; $_rt = dbQuery($req,'SINGLE'); if (strlen($_rt['user_password']) === 0) { return(false); } if (md5($_rt['user_password'] . $sect) == $hash) { print_r($rt); return($_rt); } ?> 上面代碼的問題是 $_val 是一個用戶的值從$_COOKIE['JMU_Cookie']調用. <?php $data = array(); $user = 'admin'; // Target $data[0] = base64_encode(serialize($user)); $data[1] = (bool)0; echo "\n\n===[ 0 ] ========================\n\n"; echo 'Cookie: JMU_Cookie=' . urlencode(serialize($data)); $data[1] = (bool)1; echo "\n\n===[ 1 ] ========================\n\n"; echo 'Cookie: JMU_Cookie=' . urlencode(serialize($data)); ?> 上面的腳本是一個如何工作的例子,他將會創造一個cookis當做一個用戶名登陸,對於更多的信息檢查將會對比PHP ,特殊的驗證。 3- new bug : http://www.sektioneins.com/en/advisories/advisory-022009-phpids-unserialize-vulnerability/index.html 另外,我還會出版一些 最近研究的關於瀏覽器的安全性。 本文摘自: 中國***聯盟(http://www.chinawll.com/) 詳細出處請參考:http://www.chinawll.com/forum.php?mod=viewthread&tid=1576&extra= |
PHP代碼審計
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.