珂蘭寺小課堂|PHP代碼審計(一)

代碼審計(code audit)是一種通過分析源代碼來發現程序錯誤、安全漏洞和違反程序規范的技術。它屬于防御性編程的一部分,旨在減少程序發布前的錯誤。

C和C++源代碼是最常見的審計對象,因為其他高級語言如python,其底層實現依賴于c語言,經過處理后被Python封裝,易受攻擊的功能較少(例如,Python幾乎不需要考慮邊界檢查函數的漏洞)。

代碼審計的對象包括但不限于對windowslinux系統下的以下語言進行審核:Java,C,C#,ASP,phpjsp,.NET。

本系列代碼審計文章主要針對PHP語言展開,第一課首先為大家介紹一些PHP基礎知識。

PHP網頁工作原理

立即學習PHP免費學習筆記(深入)”;

要學習PHP代碼審計,首先需要了解PHP網頁的組成部分。

  1. 語言網頁類型:網頁中有動態語言和靜態語言,具體區別如下表所示。
動態語言 靜態語言
PHP語言 html,文本文件,圖片文件
需要專門的解釋器才能被服務器識別 可以被服務器(如nginxapache等Web服務器)直接識別
對每個客戶端的返回可能不一樣 返回固定
  1. 接口協議CGI協議(公共網關接口)工作在Web服務器與Web應用程序之間,實現數據交換,使解釋器和服務器能夠通信。CGI處理一個請求需要fork一個進程,處理結束后關閉進程,非常浪費CPU資源。

因此,引入了FastCGI,實現了master進程和worker進程常駐,優化了效率。

Web服務器和CGI接口通過一些環境變量向CGI程序傳遞重要參數。以下是一些常用的CGI環境變量:

變量名 描述
CONTENT_TYPE 指示所傳遞信息的MIME類型。通常為application/x-www-form-urlencoded,表示數據來自HTML表單。
CONTENT_LENGTH 如果服務器與CGI程序信息的傳遞方式是POST,這個環境變量的值表示從標準輸入STDIN中可讀的有效數據的字節數。在讀取輸入數據時必須使用。
http_Cookie 客戶機內的COOKIE內容。
HTTP_USER_AGENT 提供包含版本號或其他專有數據的客戶瀏覽器信息。
PATH_INFO 表示緊接在CGI程序名之后的其他路徑信息,常作為CGI程序的參數出現。
QUERY_STRING 如果服務器與CGI程序信息的傳遞方式是GET,這個環境變量的值表示所傳遞的信息,信息跟在CGI程序名之后,兩者中間用一個問號’?’分隔。
REMOTE_ADDR 發送請求的客戶機的IP地址。例如上面的192.168.1.67。這個值總是存在的,是Web客戶機需要提供給Web服務器的唯一標識,可用于區分不同的Web客戶機。
REMOTE_HOST 包含發送CGI請求的客戶機的主機名。如果不支持查詢,則無需定義此環境變量。
REQUEST_METHOD 提供腳本被調用的方法。對于使用HTTP/1.0協議的腳本,僅GET和POST有意義。
SCRIPT_FILENAME CGI腳本的完整路徑
SCRIPT_NAME CGI腳本的名稱
SERVER_NAME 你的WEB服務器的主機名、別名或IP地址。
SERVER_SOFTWARE 包含了調用CGI程序的HTTP服務器的名稱和版本號。例如,上面的值為Apache/2.2.14(unix)
  1. 服務器:不同服務器的特點、優點和缺點如下表所示。
Web Server 特點 優點 缺點
Nginx 基于事件驅動 性能、負載均衡,穩定性高,支持熱部署 /
Apache 基于進程驅動 支持幾乎所有平臺,組件多 系統壓力大,不支持熱部署
iis 最適合ASP.NET、ASP 產品相較成熟 只能運行在Windows平臺

PHP核心配置

代碼在不同環境下執行結果會有不同,不同版本會導致指令的變更,因此代碼審計需要熟悉各個版本配置文件的核心指令,以達到以下兩個基本目的:

  1. 擴展審計過程中的攻擊面(訪問目錄,訪問輸出內容,數據過濾,文件處理范圍,函數調用等)。
  2. 方便審計過程中調試和信息的輸出(display_errors, error_reporting控制錯誤信息顯示)。

兩個主要的PHP配置文件

  • php.ini:PHP配置中的幾種模式及其含義如下:
模式 含義
PHP_INI_USER 可在用戶腳本(例如ini_set())或Windows注冊表以及.user.ini中設定
PHP_INI_PERDIR 可在php.ini, .htAccess或httpd.conf設定
PHP_INI_SYSTEM 可在php.ini或https.conf中設定
PHP_INI_ALL 可在任何地方設定
  • .user.ini:用戶自定義的小型php.ini,會影響到PHP_INI_USER, PHP_INI_PERDIR模式下的配置。除了主php.ini之外,PHP還會在每個目錄下掃描.user.ini文件,且.user.ini能被動態加載,修改后不需要重啟服務器。

注意,PHP的核心配置項不一定是在php.ini中設置的。

審計中常涉及的配置

  1. register_globals(在PHP5.4.0被移除):隱患是直接將用戶通過GET、POST提交的參數注冊為全局變量,并初始化值為參數對應的值,使參數可以在腳本中直接使用。

  2. magic_quote_gpc(PHP 5.4后被取消):開啟后會對GET、POST、Cookie變量中的單引號、雙引號、反斜杠以及空字符(NULL)前面加上反斜杠。隱患是若在代碼層再次對單引號等進行特殊轉換過濾,可能導致過濾失效。

  3. magic_quotes_runtime:與magic_quotes_gpc相同,是在單引號、雙引號、反斜杠以及空字符前面加反斜杠,區別是magic_quotes_runtime是對從數據庫或文件中獲取的數據進行過濾。隱患是當該項開啟時,若在代碼層再次對單引號等進行特殊轉換過濾,可能導致過濾失敗。

  4. magic_quotes_sybase(PHP5.4后被取消):當magic_quotes_gpc也開啟時,會覆蓋掉magic_quotes_gpc的配置,同樣對GET、POST、Cookie進行處理,但僅僅是把轉移空字符和單引號變成雙單引號(用單引號來轉義單引號)。

    • Magic_quotes_sybase=0時,addslashes將對” ‘ 進行轉義操作;
    • Magic_quotes_sybase=1時,addslashes將對’進行”轉義操作。

    隱患是當該項與magic_quotes_gpc同時開啟時,可能導致參數意外閉合。

    實例如下:

    珂蘭寺小課堂|PHP代碼審計(一)

    注意,%27經URL解碼后為’

  5. safe_mode(PHP5.3以上的版本棄用):PHP的安全模式是一個非常重要的內嵌安全機制,能夠控制一些PHP中的函數是否能夠正常使用,比如system(),同時對很多文件操作函數進行權限控制,也不允許對某些關鍵文件進行操作,比如/etc/passwd,除非使用safe_mode_include_dir和safe_mode_exec_dir指定一個可被包含和存放了外部腳本的安全目錄。

    珂蘭寺小課堂|PHP代碼審計(一)

    隱患是當該項開啟時,如果本身敏感操作的拼接為雙引號,可能導致參數意外閉合。

  6. allow_url_includeallow_url_fopen:使include()、include_once()、require()、require_once()都可以引入URL類型協議,允許其包含遠程文件。

    • allow_url_fopen:是否允許將URL(如http://或ftp://)作為文件處理。
    • allow_url_include:是否允許include/require打開URL(如http://或ftp://)作為文件處理。

    隱患是從PHP5.2開始allow_url_include就默認為Off,而allow_url_fopen一直是On的。在文件包含漏洞中,會產生遠程文件包含的動作,增加攻擊面。

  7. open_basedir:open_basedir是PHP設置中為了防御PHP跨目錄進行文件(目錄)讀寫的方法,所有PHP中有關文件讀、寫的函數都會經過open_basedir的檢查。將PHP所有能打開的文件限制在指定的目錄樹,包括文件本身。

    本指令不受安全模式打開或關閉的影響。

    隱患是雖然在PHP5.3以后很少有能夠繞過open_basedir讀寫文件的方法,但是有很多可以繞過open_basedir的限制對其進行輸出目錄的繞過方法。

  8. disable_functions:可以禁止一些敏感函數的使用。

    一個目前推薦的禁用函數列表有:

    函數 作用
    dl() 載入指定參數的PHP擴展
    exec() 執行一個外部程序
    system() 執行外部程序,并且顯示輸出
    passthru() 同exec()函數類似,passthru()函數也是用來執行外部命令的
    proc_open() 執行一個命令,并且打開用來輸入/輸出的文件指針
    pcntl_exec() 在當前進程空間執行指定程序,可指定參數
    shell_exec() 通過shell環境執行命令,并且將完整的輸出以字符串的方式返回
    mail() 發送郵件
    imap_open() 打開IMAP流,參數username為用戶帳號。參數password為用戶的密碼
    imap_mail() 通過IMAP發送郵件
    putenv() 添加setting到服務器環境變量。環境變量僅存活于當前請求期間。在請求結束時環境會恢復到初始狀態
    ini_set() 設置指定配置選項的值。這個選項會在腳本運行時保持新的值,并在腳本結束時恢復
    apache_setenv() 設置Apache子進程環境變量
    symlink() 建立符號連接
    link() 建立一個硬連接
  9. display_errorserror_reporting:在調試PHP時,打開錯誤信息,設置錯誤顯示級別。

    隱患是敏感信息泄露。在審計中,開啟錯誤信息顯示可以更加直觀地了解數據產生的錯誤提示,會暴露目錄、絕對路徑,造成sql注入的錯誤信息。

  10. auto_append_fileauto_prepend_file:自動在文件的尾或頭處通過require引入特定的文件。

    隱患是通過上傳.user.ini可能造成上傳白名單擴展名的文件也能getshell。

? 版權聲明
THE END
喜歡就支持一下吧
點贊12 分享