程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> PHP基礎知識 >> php代碼審計 教程

php代碼審計 教程

編輯:PHP基礎知識
 

0×01 工具篇
編輯器(notepad++,editplus,UE等等,看個人習慣)
TommSearch(字符串檢索) || grep
HttpProtocolDebugger(http協議調試器)
Fiddler(分析包,改包)
Seay PHP代碼審計工具(php-code-audit分析輔助)
幾個有趣的項目
dvwa(代碼審計測試平台)
phpmvs
php security audit check
PHP Vulnerability Hunter

0×02 函數篇
addslashed()添加反斜槓
stripslashed()去掉反斜槓
get_magic_quotes_gpc() 判斷是否開啟gpc
expode(“.”,$array)分割成數組
is_numeric()判斷是否為數字
sizeof()判斷長度
trim() 去除字符串開頭和末尾的空格或其他字符
system() 輸出並返回最後一行shell結果。
exec() 不輸出結果,返回最後一行shell結果,所有結果可以保存到一個返回的數組裡面。
passthru() 只調用命令,把命令的運行結果原樣地直接輸出到標准輸出設備上。
EscapeShellCmd(),把一個字符串中所有可能瞞過Shell而去執行另外一個命令的字符轉義。這些字符在Shell中是有特殊含義的,象分號(;),重定向(>)和從文件讀入 (<)等。
EscapeShellArg() 。在給定的字符串兩邊加上單引號,並把字符串中的單引號轉義,這樣這個字符串就可以安全地作為命令的參數。
用popen()函數打開進程
上面的方法只能簡單地執行命令,卻不能與命令交互。但有些時候必須向命令輸入一些東西,如在增加Linux的系統用戶時,要調用su來把當前用戶換到root才行,而su命令必須要在命令行上輸入root的密碼。這種情況下,用上面提到的方法顯然是不行的。
popen ()函數打開一個進程管道來執行給定的命令,返回一個文件句柄。既然返回的是一個文件句柄,那麼就可以對它讀和寫了。在PHP3中,對這種句柄只能做單一 的操作模式,要麼寫,要麼讀;從PHP4開始,可以同時讀和寫了。除非這個句柄是以一種模式(讀或寫)打開的,否則必須調用pclose()函數來關閉 它。
例子1:
/* PHP中如何增加一個系統用戶
下面是一段例程,增加一個名字為james的用戶,
root密碼是 verygood。僅供參考
*/
$sucommand = “su –login root –command”;
$useradd = “useradd “;
$rootpasswd = “verygood”;
$user = “james”;
$user_add = sprintf(“%s “%s %s””,$sucommand,$useradd,$user);
$fp = @popen($user_add,”w”);
@fputs($fp,$rootpasswd);
@pclose($fp);

require在被包含文件有錯誤代碼時將不再往下執行
include在被包含文件有錯誤代碼時仍然往下執行

htmlspecialchars() 函數把一些預定義的字符轉換為 HTML 實體。
預定義的字符是:
& (和號) 成為 &
” (雙引號) 成為 ”
‘ (單引號) 成為 ‘
< (小於) 成為 <
> (大於) 成為 >

move_uploaded_file() 函數將上傳的文件移動到新位置。

extract() 函數從數組中把變量導入到當前的符號表中。
對於數組中的每個元素,鍵名用於變量名,鍵值用於變量值。
第二個參數 type 用於指定當某個變量已經存在,而數組中又有同名元素時,extract() 函數如何對待這樣的沖突。
本函數返回成功設置的變量數目。
語法
extract(array,extract_rules,prefix)

parse_str() 函數把查詢字符串解析到變量中. (常見於變量覆蓋漏洞)
語法
parse_str(string,array)
參數    描述
string    必需。規定要解析的字符串。
array    可選。規定存儲變量的數組名稱。該參數指示變量存儲到數組中。

針對變量指定攻擊
不使用foreach遍歷$_GET變量,改用$_GET[(index)]

eval() 函數把字符串按照 PHP 代碼來計算。該字符串必須是合法的 PHP 代碼,且必須以分號結尾。
如果沒有在代碼字符串中調用 return 語句,則返回 NULL。如果代碼中存在解析錯誤,則 eval() 函數返回 false。

preg_replace 執行一個正則表達式的搜索和替換
/e參數執行代碼

0×03 漏洞篇
———————————————–
[1].Sql-Injection
留意:cookie及x-forward-for,寬字節,報錯注射等
挖掘漏洞參考
變量
$_GET[""],$_POST[""],$_COOKIE[""], $SERVER[""]
數據庫操作函數
mysql_query()
數字型注入防范:
1.is_numeric() ctype_digit() intval()
2.str_length()確定長度
字符型注入防范:
1.mysql_real_escape_string()
2.數據庫查詢語句前加@防爆錯
3.str_length()確定長度
———————————————–
[2].Command-Execution
函數:
system(),passthru(),popen(),exec()
數據庫操作函數:
exec,system,popen,passthru,proc_open,shell_exec
執行命令管道符 % | >
測試如0 | dir c:
|| 雙豎線的作用,前面語句執行錯誤則執行後面語句
如xx”+||+whoami+||+echo
———————————————–
[3].File-Inclusion
函數:
include(),require(),include_once(),require_once()
遠程文件包含漏洞要求
allow_url_fopen()  allow_url_include()  file_get_contents()
繞過:zlib://和ogg://
5.2.0之後版本
data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8+  //
@eval(file_get_contents(‘php://input’));  //POST phpinfo();
配合%00截斷,新版本自動轉義\0
———————————————–
[4].CSRF
CSRF防范策略
1>驗證http-referer字段
安全性低,易被偽造
2>在請求地址中添加token並驗證
token可在用戶登錄後存放在session中,每次請求時將token從session中取出,去請求的token對比以防范CSRF
GET方式:http://url/?=token

如果一個網站接受請求地方比較多,則在每次頁面加載時遍歷整個dom樹,在dom中每個a和form標簽後加入token
但在動態頁面加載後產生的html代碼,則需要以硬編碼的形式手工添加
這種方式安全性弱點在於,如在論壇等交互比較頻繁的地方hacker可構造環境盜取token並進而構造csrf攻擊
故手工關閉referer
3>在HTTP頭中自定義屬性並進行驗證。通過XMLHttpRequest類。
通常用於Ajax方法對頁面局部的異步刷新
但適應性一般,對已有的網站架構局限性較大
———————————————–
[5].XSS(Cross Site Script)
反射型與存儲型
控制$_GET,$_POST,$_COOKIE 各種傳入的變量
使用htmlspecialchars()函數進行基礎過濾
結合CSRF實現自動化利用
———————————————–
[6].File_Upload
函數:move_uploaded_file()
變量:$_FILES
php文件上傳利用form表單進行文件上傳時必須為post使用multipart/form-data才能完整的傳遞文件數據
php利用$_FILES系統函數的相關參數與函數move_upload_file函數來實例把由$_FILES全局變量生成的臨時文件移動到指定目錄完成文件的上傳
$_FILES['files']['name']客戶端文件的原名稱
$_FILES['files']['type']文件的MIME類型
$_FILES['files']['size']已上傳文件的大小
$_FILES['files']['tmp_name']儲存的臨時文件名,一般為系統默認
$_FILES['files']['error']該文件上傳到相關的錯誤代碼
防范方式:
1>判斷MIME TYPE文件類型如$_FILES['files']['type']==”image/jpeg”,判斷文件大小,如$_FILES['files']['size']<10000 && $_FILES['files']['size']>100
2>指定上傳文件名,如依賴時間生成hash(time).jpg等方式
3>根據文件後綴名判斷文件
如file_ext=substr($filename,$strrpos($filename,’.’)+1);
注意是否可能有雙擴展名,二次上傳突破等邏輯問題
4>服務器嘗試渲染文件等方式判斷是否為圖片
5>不依賴於客戶端js腳本限制上傳文件類型
6>白名單規則
apache服務器常見上傳安全問題
1>配合.htaccess利用上傳
AllOverride ALL 允許子規則覆蓋父規則
.htaccess添加AddType Application/x-httpd-php .jpg
2>文件名解析漏洞
*.php.123
在.htaccess添加AddHandler php5-script .php,文件名中包含php擴展名可以php腳本執行,如x.php.jpg
.php3 .php4擴展名

0×04 配置篇
1>關注漏洞信息,及時更新版本
2>php.ini httpd.conf .htaccess文件配置
1)safe_mode相關配置
2)register_globals關閉
3)open_basedir配置,防范目錄遍歷
4)allow_url_fopen關閉
5)disable_functions配置
6)magic_quotes_gpc打開
7)error_reporting=E_ALL & ~E_NOTICE
8)display_errors=Off避免攻擊者獲取更多信息
9)expose_php=Off隱藏版本信息
3>最小化服務器其他賬戶權限
4>第三方安全加固軟件安裝
5>調用第三方安全防護文件,配置php.ini
include_path=”.:/php/includes”
auto_pretend_file=”anti-inj.php”
auto_appent_file=

0×05 思路篇
剛開始練習審計時,拿到一套源碼,馬上做的事情就是,丟到工具裡,去掃敏感的函數,然後去一個一個的回溯它,找到入口點。但是,這樣審計很浪費時間,每次都要在回溯過程中,不斷的去尋找源碼中定義的一些通用函數。由於不了解整個源碼的流程,導致在找這些通用函數的過 程中浪費了很多的時間與精力。
所以,我重新調整了我的審計流程。在拿到源碼之後,先從它開始的地方(一般是根目錄下的index文件)按照執行的順序去讀代碼,一直到它的初始化內容, 和基本功能實現完畢為止。這樣,可以明確的了解整套源碼的結構,哪一種函數文件放在哪個文件夾下;知道通用函數放在哪個文件中。這對我們在之後閱讀“疑似”有問題的代碼時,有很好的幫助,例如,在看到一個通用函數時,我們可以快速的切換到通用函數文件,查找這個函數的實現代碼。
注:此處引用修改唐門三少文章《PHP代碼審計學習總結》

0×06 小結
代碼審計一如逆向工程,均需要耐心與細心。
此外,關注漏洞發布平台上最新漏洞並跟蹤加以分析也是一個很快提升自己能力的方法。

 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved