php代碼審計一條龍思路

語言: CN / TW / HK

點擊藍字

關注我們

聲明

本文作者:Gungnir

本文字數:9103

閲讀時長:23

附件/鏈接 :點擊查看原文下載

本文屬於【狼組安全社區】原創獎勵計劃,未經許可禁止轉載

由於傳播、利用此文所提供的信息而造成的任何直接或者間接的後果及損失,均由使用者本人負責,狼組安全團隊以及文章作者不為此承擔任何責任。

狼組安全團隊有對此文章的修改和解釋權。如欲轉載或傳播此文章,必須保證此文章的完整性,包括版權聲明等全部內容。未經狼組安全團隊允許,不得任意修改或者增減此文章內容,不得以任何方式將其用於商業目的。

最近也是邊挖src邊審計代碼,總結下最近的php代碼審計的一些思路,我一般按照順序往下做,限於能力水平,可能會有不對或者欠缺的地方,希望各位師傅能夠指導。

一、

前期工作,需要的工具

PHPStorm  | 是PHP編程語言開發的集成環境。

Fotify | 代碼審計靜態掃描工具,商業化靜態代碼掃描工具,誤報率相對較低。

seay | 源代碼審計工具

CodeQl| 高效的QL非商業的開源代碼自動化審計工具。

xcheck| Xcheck 是一款靜態應用安全測試工具,旨在及時發現業務代碼中的安全風險,尤其是由不受信輸入所觸發的安全漏洞。檢測範圍覆蓋主流 Web 安全漏洞,具備速度快、誤報低和準確率高等優點。

chrome & HackerBar插件

......此處省略一下大家用的其他的工具

二、

明確目標

在審計之前,我們首先先確定自己此次審計的目地,我覺得會有三種情況

  1. 為了提升自己的審計經驗

  2. 項目中為了審計出能進一步利用的漏洞,一般需要getshell、ssrf這種級別的。

  1. 為了挖點洞,去換錢或者換cve&cnvd。

有什麼區別呢?

為了提升審計經驗,我會去重點關注歷史漏洞,並去復現。

如果是為了能審出漏洞,去用作滲透中的進一步利用,那麼我覺得,可以重點使用xcheck、Fotify等自動化代碼審計,然後關注下面的文件上傳、包含、sql注入等等有嚴重危害的漏洞

如果是為了挖0day,搞證書什麼的,那麼全方位按步驟過一遍,是不錯的選擇。

三、

判斷是否使用了框架

判斷是否使用了框架,是蠻重要的,能幫助我們快速定位有用的函數集,篩選不需要去看的代碼。

一般來説,我覺得使用了框架的更好審計一點,因為使用了框架的,他的函數集文件(各種方法function)會比較規整,在某些固定文件夾中,清晰可見,當然需要我們先對框架有所瞭解。

目前比較主流的設計模式是MVC,即多層模型(M)、視圖(V)、控制器(C),在此不多贅述,php的主流框架幾乎都使用了MVC設計模式。

PHP底下的開發框架目前見的比較多的有Laravel,ThinkPHP,yii等。

3.1. ThinkPHP框架

ThinkPHP這裏需要區分TP3和TP5的差別,首先我們先來看看TP3的目錄結構。(現在基於TP3的系統都很少了。。。瞭解一下就好

其中,Application和Public目錄下面都是空的。

Application是存放項目中的重要的一些函數集,Public是公共文件夾,供用户訪問的,重要的函數集千萬不能放在此文件夾下。

Application目錄默認是空的,但是第一次訪問入口文件會自動生成,參考後面的入口文件部分。其中框架目錄ThinkPHP的結構如下:

另外TP5和TP3實際上差距有點大,先看看TP5下載下來的默認文件結構。其中在public文件下有個route.php文件,它的作用是用於php自帶webserver支持,可用於快速測試,啟動命令:php -S localhost:8888 router.php。而它的相關網站功能目錄也需要從根目錄下的index.php入手。

以下為TP5的目錄結構。

一般如果是審計基於框架的cms,我不會去看框架系統目錄,就是上面的ThinkPHP文件夾下的東西,第三方類庫vendor也不會去先看,除非是在審計過程中流向了這些文件中,才會大概看一看,而重點在Application文件夾下做文章。

既然是MVC框架的,那麼我們真正關心的是其中的控制器(C),因為功能點大部分都在C上,我們能找到的大部分漏洞也都在C上

下圖為基於TP6的ThinkAdmin項目目錄

app(也就是application),下面有admin、data、index、wechat幾個文件夾,每個文件夾代表了一個應用,比如admin一般來説都是後台的服務,wechat為微信應用服務,每個應用下面都有Controller(控制器)、Module(模型)、View(視圖,一般是html文件)

現在目錄很明確,目標就很明確,拿到這樣基於框架的cms,就應該知道,該重點審計的地方在哪裏。

3.2. Laravel框架

文章地址:https://blog.csdn.net/jiangnanqbey/article/details/80746252

目錄怎麼變,MVC架構的重點還是在Controllers裏

3.3. 如果沒用框架

沒用框架的話,先搞明白目錄結構,一般來説

審計過程中需要關注幾個點:(在我們後面開始審計的過程中,自己要注意這些地方,經常想一想)

1)函數集文件,通常命名包含function或者common等關鍵字,這些文件裏面是一些公共的函數,提供其他文件統一調用,所以大多數文件都會在文件頭部包含到其他文件。尋找這些文件一個非常好用的技巧就是去打開index.php或者一些功能性文件,在頭部一般都能找到。

2)配置文件,通常命名中包括config關鍵字,配置文件包括web程序運行必須的功能性配置選項以及數據庫等配置信息。從這個文件中可以瞭解程序的小部分功能,另外看這個文件的時候注意觀察配置文件中參數值是單引號還是用雙引號括起來,如果是雙引號可能就存在代碼執行的問題了。

3)安全過濾文件,安全過濾文件對代碼審計至關重要,這關係到我們挖掘到的可以點能否直接利用,通常命名中帶有filter、safe、check等關鍵字,這類文件主要是對參數進行過濾,大多數的應用其實會在參數的輸入做一下addslashes()函數的過濾。

4)index文件,index是一個程序的入口,所以通常我們只要讀一讀index文件就可以大致瞭解整個程序的架構、運行的流程、包含到的文件,其中核心的文件有哪些。而不同目錄的index文件也有不同的實現方式,建議最好將幾個核心目錄的index文件都通讀一遍。

四、

瞭解路由

我很喜歡Thinkphp這類框架的原因是,他們的路由很好摸清,如果在哪個方法中找到了漏洞,我就能直接根據路由訪問這個方法,直接利用。

瞭解路由也是為了能快速定位漏洞位置,要不然,你通過審計源碼找到的漏洞,卻不知道在瀏覽器中用什麼樣的url去訪問,這不是件很尷尬的事兒嗎?

比如Thinkphp的路由有三種方式

4.1. 普通模式

關閉路由,完全使用默認的pathinfo方式URL:

'url_route_on'  =>  false,

路由關閉後,不會解析任何路由規則,採用默認的PATH_INFO 模式訪問URL:

module/controller/action/param/value/...

module就是使用的應用。

controller是控制器,跟文件名一致。

action是方法,某控制器下的方法。

param是需要的變量

value是參數

但仍然可以通過Action參數綁定、空控制器和空操作等特性實現URL地址的簡化

4.2. 混合模式

開啟路由,並使用路由+默認PATH_INFO方式的混合:

'url_route_on'  =>  true,

該方式下面,只需要對需要定義路由規則的訪問地址定義路由規則,其它的仍然按照默認的PATH_INFO模式訪問URL。

4.3. 強制模式

開啟路由,並設置必須定義路由才能訪問:

'url_route_on'  =>  true,
'url_route_must'=>  true,

這種方式下面必須嚴格給每一個訪問地址定義路由規則,否則將拋出異常。

首頁的路由規則是 /

其實,在實際審計過程中,我一般會先去黑盒訪問一遍功能點,分析後差不多也能知道路由怎樣構成,如果有的地方不清楚,可以去源碼中找路由文件

一般帶有route關鍵詞的文件,或文件夾與路由有關。

分析好路徑,之後就可以真正的開始審計。

四、

開始審計

在人工審計之前,可以使用我之前提到的xcheck、Fotify、codeql等自動化審計工具先審計一遍,根據報告,驗證一遍,再往下去根據下面的步驟審一遍,一個項目,也就能審個七七八八了,深層次的利用也就得看自身的實力與經驗了。

如果使用了框架,可以先看看此項目還有沒有框架的漏洞存在,我就不再贅述了。

5.1. 鑑權

首先對於項目整體的一個權限認證做一個判斷,判斷是否存在越權,未授權訪問的情況。

一般來説,需要權限認證的地方,是後台管理,即admin應用下的。

所以對於admin下的控制器這些方法,需要判斷是否可以未授權訪問。

目前對於整個後台管理鑑權的方式,一般是採用寫一個基類,比如Base.php或者common.php,其中存在鑑權方法,然後在每個控制器類繼承這個類。

比如xiaohuanxiong漫畫cms的後台,就是採用了這種方法。

不過我也看到了,有的比較好的項目,自己二開框架,做了自己的組件,然後,每個類都繼承了此組件,也是同樣的原理

比如ThinkAdmin,繼承了自己組件的controller。

我們知道了鑑權的方式,所以我們首先看的是,如果他沒有這些鑑權方式,或者其他鑑權方式也沒有,那麼他就會存在未授權訪問,即不登錄也能訪問後台功能。這是很危險的,一個是管理員才能看到的敏感信息,未授權就能看到,更危險的是,結合後台的漏洞,直接未授權getshell也是很有可能的,所以鑑權我們首先去看,而且容易去看的地方。

5.2. 按照漏洞類型審計

我認為對於我來説,比較好的審計方法是黑盒白盒一起,根據漏洞類型一個一個的去找尋可能存在漏洞的地方,然後再回溯查看是否用户可控,以此快速定位漏洞。

所以一般我是根據漏洞類型,以及每個漏洞可能涉及的危險函數,去快速定位。

那一般看的地方有SQL注入、XSS、CSRF、SSRF、XML外部實體注入等等

5.2.1. sql注入

來自 梅子酒師傅的 《對PHP類CMS審計的一點總結》

  1. 如果使用了框架,可以分辨一下框架名稱以及版本,去搜索一下該版本的框架是否存在漏洞,如果存在再去cms中驗證。因為本篇文章主要講我自己在cms審計上的一些經驗,因此不多深入框架的審計部分。

  2. 如果沒有使用框架,則需要仔細的觀察數據庫函數,一般來説,cms是將select、insert等函數進行了封裝的,比如$db->table(‘test’)->where(“name=admin”)便是 select * from test where name=admin這種格式,而此時若是發現cms使用的是過濾+拼接,那麼很有可能會出現問題,而如果使用了PDO,則繼續跟進涉及到table,order by等字段的拼接去,因為這些字段是無法使用PDO的。

審計要素:

  • 參數是否用户可控

  • 是否使用了預編譯

那麼首先,如果沒有使用框架封裝的sql語句,那麼全局搜索insert、select等sql語句關鍵詞,然後定位到具體的語句,然後查看裏面有沒有拼接的變量,回溯可不可控。如果可控並且存在字符串拼接,很有可能就存在漏洞。

使用了框架的就是搜索的關鍵詞不一樣,還是得看是否存在字符串拼接,可不可控。

即使使用了預編譯,但是如果在預編譯之前字符串拼接了,那照樣沒有鳥用,該注入還是能注入。

下面提供一般我會搜索的關鍵詞(框架的根據你審計項目的框架的手冊,自行搜索。)師傅們有想補充的也可以補充。

insert
create
delete
update
order by
group by
where
from
limit
desc
asc
union
select

5.2.2. xss漏洞

審計要素

  • 是否存在全局參數過濾器,過濾規則是否符合安全要求,是否存在需過濾和不需過濾兩種輸出,頁面是否控制恰當。

  • 輸出時是否進行編碼(HTML、JS等)。

  • 前端是否採用了Angularjs、React、vue.js等具有XSS防護功能的前端框架進行數據輸出。

這個的話,我就不會關鍵詞搜了,我就是會在尋找其他漏洞的過程中,注意有沒有直接把輸入原樣輸出的地方,也沒有特別關注這一塊。

如果想特意挖掘這一塊,可以

查看是否配置了全局的攔截器、過濾器。檢查數據輸出函數,例如常用的輸出函數有print、print_r、echo、printf、sprintf、die、var_dump、var_export。

5.2.3. CSRF漏洞

與XSS攻擊相比,CSRF攻擊往往不大流行(因此對其進行防範的資源也相當稀少)和難以防範,所以被認為比XSS更具危險性。

審計要素

  • 是否在表單處存在隨機token。

  • 是否存在敏感操作的表單。

CSRF主要利用場景實際上是一些越權的操作,或者一些敏感功能存在的地方,例如管理後台、會員中心等地方。我們可以嘗試搜索表單位置,查看是否會生成隨機token,在查看後端代碼中是否會先驗證這部分的token。如果沒有驗證token,再進一步看看是否有refer的相關驗證,如果沒有,那麼就存在CSRF的問題。

可以嘗試全局搜索

csrf-token
csrf_token
csrftoken
csrf

下面是一個更新密碼的操作,假設構造一個鏈接為 http://127.0.0.1/index.php?password_new=password&password_conf=password&Change=Change#的鏈接,直接發送給受害者點擊,那麼當前情況下,可以直接修改受害者的密碼,因為沒有進行任何的驗證措施。當然一般代碼不會這麼寫,只是拿DVWA的CSRF舉個例子。

5.2.4. SSRF漏洞

ssrf是利用存在缺陷的web應用作為代理攻擊遠程和本地的服務器。常見的方式如下:

1.可以對外網、服務器所在內網、本地進行端口掃描,獲取一些服務的banner信息;

2.攻擊運行在內網或本地的應用程序(比如溢出);

3.對內網web應用進行指紋識別,通過訪問默認文件實現;

4.攻擊內外網的web應用,主要是使用get參數就可以實現的攻擊(比如struts2,sqli等);

5.利用file協議讀取本地文件等。

審計要素:

  • 是否存在可以產生SSRF漏洞的函數。

  • 是否存在內網ip地址正則過濾,且正則是否嚴謹。

  • 是否存在限制請求的方式只能為HTTP或者HTTPS。

當然PHP底下經常可能會出現SSRF漏洞的主要有幾個函數,它們分別是file_get_contents()、fsockopen()、curl_exec()、get_headers()。通過全文關鍵函數搜索,在看是否限制了訪問端口,訪問協議,內網ip地址等。

利用file://、http/https:// 、dict://、gopher://協議去搞內網。

列一下,我經常搜索的關鍵詞

file_get_contents
fsockopen
curl_exec
get_headers
fopen
readfile

注意

1. 一般情況下PHP不會開啟fopen的gopher wrapper
2. file_get_contents的gopher協議不能URL編碼
3. file_get_contents關於Gopher的302跳轉會出現bug,導致利用失敗
4. curl/libcurl 7.43 上gopher協議存在bug(%00截斷) 經測試7.49 可用
5. curl_exec() //默認不跟蹤跳轉,
6. file_get_contents() // file_get_contents支持 php://input協議

各種繞過,我就不在這説了。

5.2.5. XML外部實體注入

審計要素

  • 參數是否用户可控

  • 是否libxml版本為2.9.0以上

  • 是否禁用了外部實體

這個個一般我關注的少,僅僅是搜索

“DOMDocument”,“SimpleXMLElement”和“simplexml_load_string”等關鍵詞,分析下是否存在參數拼接的XML字符串,或未做限制的批量解析方法。對參數進行回溯,判斷其是否用户可控。

差不多就沒啥了。

5.2.6. 文件包含漏洞

審計要素

  • 參數是否用户可控

  • 是否存在include,require,include_once, require_once等函數。

文件包含算是拿shell最快的方法了,所以一般要重點關注。

無非是include,require,include_once, require_once這四個函數,全局搜索這四個函數,一個一個去看,去回溯,查看變量可不可控。

5.2.7. 文件上傳漏洞

審計要素

  • 是否檢查了上傳文件的文件類型

  • 是否限制了文件上傳路徑

  • 是否對文件進行了重命名

  • 文件大小是否限制

  • 是否返回了文件路徑或文件路徑很好猜測

有的項目,會對文件上傳下載進行分裝,所以可以全局搜索有關upload、file的函數,看看是不是封裝了

function upload
function file

如果封裝了,那麼就看這些封裝好的函數,有沒有上面提到的審計要素的漏洞。

如果沒封裝,一般是move_uploaded_file這個函數,全局搜索,這個函數,回溯查看這些漏洞存不存在。(白盒黑盒一起搞比較好。)

5.2.8. 變量覆蓋

審計要素

  • 是否存在造成變量覆蓋的函數,例如:extract()、parse_str()、import_request_variables和$$等。

  • 是否存在可以完整利用的攻擊鏈。

一般就這幾個函數和關鍵詞

extract
parse_str
import_request_variables
mb_parse_str
$$

不過還有個特殊的配置,也可能造成變量覆蓋

下面的部分來自mi1k7ea師傅PHP變量覆蓋漏洞

register_globals全局變量覆蓋

php.ini中有一項為register_globals,即註冊全局變量,當register_globals=On時,傳遞過來的值會被直接的註冊為全局變量直接使用,而register_globals=Off時,我們需要到特定的數組裏去得到它。

注意:register_globals已自 PHP 5.3.0 起廢棄並將自 PHP 5.4.0 起移除。

當register_globals=On,變量未被初始化且能夠用户所控制時,就會存在變量覆蓋漏洞:

<?php
echo "Register_globals: " . (int)ini_get("register_globals") . "<br/>";

if ($a) {
  echo "Hacked!";
}
?>

通過GET和POST方式輸入變量a的值:

當然,也可以從COOKIE中輸入:

5.2.9. 代碼執行漏洞

審計要素

  • php.ini文件中的disable_function是否有禁用函數。

  • 是否存在代碼執行的敏感函數。

  • 是否輸入變量可控。

全局搜索下面的關鍵詞,回溯參數可不可控。

eval
asser
preg_replace
create_function
array_map
call_user_func
call_user_func_array
array_filter
usort
uasort
$a($b)(動態函數)

5.2.10. 命令執行漏洞

審計要素

  • 參數是否用户可控

  • 是否配置了全局過濾器,過濾規則是否符合安全規範

  • 是否所有的命令執行參數都經過了過濾器,或受白名單限制

全局搜索下面的關鍵詞,回溯參數可不可控。

exec
passthru 
proc_open 
shell_exec
system
pcntl_exec 
popen
``(被反引號包裹的變量也可以執行)

5.2.11. 任意文件下載/下載漏洞審計

審計要素

  • 是否存在../、.、..\等特殊字符過濾。

  • 參數是否用户可控

  • 是否配置了相對路徑或者絕對路徑。

查詢這些關鍵詞,查看變量是否可控,是否有過濾

fgets
fgetss
file_get_contents
readfile
parse_ini_file
highlight_file
file
fopen
readfile
fread

Tip:前兩天遇到個,過濾了config/database.php這樣的正則匹配,還過濾了..,目的是防止目錄穿越,讀取服務器其他目錄的文件,可是沒過濾一個.

這樣我使用config/./database.php繞過了正則,照樣把敏感文件讀取出來了。。。

5.2.12. 任意文件刪除

和上面的下載一樣

搜索的關鍵詞變了

rmdir
unlink

5.2.13. 任意文件寫入

還是一樣,關鍵詞為

copy
file_put_contents
fwrite

5.2.14. 會話認證漏洞

會話認證漏洞實際上涉及的方面比較廣,如cookie、session、sso、oauth等,當然這個漏洞比較常見是在cookie上,服務端直接取用cookie中的數據而沒有校驗,其次是cookie加密數據在可預測的情況下。

審計要素

  • 是否cookie中的加密數據可預測。

  • 是否cookie中的數據可預測。

  • 服務端是否只依賴cookie來判斷用户身份。

全局去尋找cookie生成的邏輯,判斷是否可預測,判斷用户身份是否只依賴cookie,而不是隨機的,比如

鑑權是隻通過cookie中的userid來判斷,如果我遍歷userid,可以達到登錄繞過或越權的目地。

5.2.15. 反序列化漏洞

一般實際審計的時候,項目中見的比較少,框架中見的比較多。

全局搜索serialize。看看存不存在可控變量。

很早之前寫過這個系列的小結

序列化(一)利用-phar-拓展-php-反序列化漏洞攻擊面

序列化(二)session反序列化

序列化(三)原生類反序列化

參考

對PHP類CMS審計的一點總結

http://www.oriole.fun/index.php/archives/69/

PHP變量覆蓋漏洞小結

還有狼組wiki中的文章

總結

這篇文章,就是自己總結下審計的流程,或許有很多不足、缺漏,希望師傅們諒解及指正。

審計是一件很難一概而論的事情,有時會很枯燥,看代碼看的頭疼,但自己找到0day的感覺,是非常不一樣的,加油吧,師傅們。

Gungnir

掃描關注公眾號回覆加羣

和師傅們一起討論研究~

WgpSec狼組安全團隊

微信號:wgpsec

Twitter:@wgpsec