複現條件
環境:windows7+phpstudy2018+php5.4.45+apache
程式架構:damicms 2014
條件:需要登入
特點:屬于GET型注入,且存在防禦腳本,防禦方法
複現漏洞
我們先注冊個賬号。賬号test0 密碼test0
登陸進行場景複現, 通路連結:http://localhost/test0/index.php?s=/api/ajax_arclist/model/article/field/username,userpwd from dami_member%23 (注:要寫%23,别寫#)
如圖 1所示
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5SNwEWZ2IWYlR2NxEWO3UDOzY2NzgTYzQzMjJjM4EGMi9CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
圖 1
我們可以看到賬号密碼已經爆出,證明漏洞存在。
接下來我們進行漏洞利用代碼剖析。不過在剖析之前,我們先要了解一下此程式的URL路由,便于url連結構造,之前我們已經有過介紹了。
url連結構造
首先我們在注冊的時候登陸,進入個人資料的的時候 我們可以看到注冊,登陸,個人資料的連結
注冊:http://localhost/test0/index.php?s=/Member/register.html
登陸:http://localhost/test0/index.php?s=/Member/login.html
個人資料:http://localhost/test0/index.php?s=/Member/main.html
通過 三個連結
我們可以得知為單一入口檔案通路模式,URL路由的映射采用的寫法是:網站域名/index.php?s=/控制器名/方法名.html 。看到html字尾 ,我們基本可以得知采用的是僞靜态規則,去掉字尾,連結可用。
猜測帶參數的連結構成:網站域名/index.php?s=/控制器/方法/參數名/參數值.html 或 網站域名/index.php?s=/控制器/方法/參數名/參數值
好,我們現在已經大概知道了連結構造。
接下來我們檢視目錄結構,如圖2所示,感覺目錄命名結構,有點像使用的thinkphp架構,打開/Core/Core.php,看下注釋,得知是thinkphp架構,(注:一般能知道什麼架構,或者你審計的用的是什麼cms,能查到該架構的開發手冊,直接檢視手冊如何設定的URL路由映射,進行URL連結構造就可以了。)這裡我們假設不知這套程式不知道用的是什麼架構,沒有對應開發手冊,我們來進行分析。我們基本可以猜測到哪個目錄有什麼作用功能。
Admin 背景功能目錄 背景的相關類方法,配置檔案基本都在此。
Core 核心目錄
install 安裝程式的目錄
Public 一般一些css,js檔案,圖檔檔案,編輯器插件,字型等都會放在這裡面公用。
Trade 檢視該目錄下的檔案名,随便點開看看檔案裡的注釋,得知為這是接口檔案目錄
Web前台程式功能目錄
Runtime 緩存目錄 一般緩存的東東都會生成在這裡面
僞靜态檔案 程式做僞靜态的配置
圖2
前台的控制器就在/Web/Lib/Action/控制器名+Action.class,php。背景控制器同上,隻是,"Web"改成了"Admin",也就是/Admin/Lib/Action/控制器名+Action.class,php。這樣,我們就可以通過構造URL找到
路由映射的代碼位置了。
下面我們根據漏洞複現的場景連結尋找出現漏洞的代碼進行複現剖析。
漏洞利用代碼剖析
檢視入口檔案是否引入了防禦腳本
我們先大體看一下網站源碼index.php,看一下是否有如圖-3所示,看到h13 (注:h代表行數,此處指第13行)引入了php_safe.php。打開此腳本, 我們看到php_safe.php圖4的h2 是//Code By Safe3
推測是360的防禦腳本 或者改造了的防禦腳本,h24-h33(注:h代表行數,此處指第24行到第33行)我們看到 不管是GET POST 還是COOKIE方式傳送的要進行過濾。
圖3
圖4
通過漏洞連接配接定位的漏洞位置
通過上面分析,根據漏洞連結我們可以定位到漏洞位置在\Web\Lib\Action\ApiAction.class.php的 ajax_arclist方法中 如圖5所示,
圖5
分析漏洞源碼
看到這個方法的入口處,很多$_REQUEST來接收參數,感覺琳琅滿目,不要是以而迷失了雙眼。我們先找到有SQL語句的地方。在h60,h64,h70。
看到三個sql語句中,可控的參數,$where $order $num $field 分别在h46->h48,h54被inject_check函數處理。我們按住ctrl,光标移動至inject_check上點選滑鼠左鍵,選擇/Core/Common/functions.php定位到h988的inject_check方法如圖6所示,我們看到eregi()方法 被中線劃掉,說明該方法棄用。php5.3x不再支援eregi。這裡我們選擇忽略或不忽略,為什麼可以這樣選擇呢?因為我們之前在進行檢視網站源碼index.php的時候知道了發現本程式調用了防禦腳本,GET方式傳參的值都會被檢測,另一個理由是看你運作該程式用的php版本是多少的。此時,我們回到三個SQL語句上。
看到參數被分别帶入了 where(), order(), field(), limit() 方法中。由于本程式是用的thinkphp架構,這四個方法的使用,我們直接看thinkphp的手冊就可以了。由于thinkphp 版本很多,我們先列印一下thinkphp的版本,在ajax_arclist方法開始處輸入 代碼: echo THINK_VERSION; die; 可以得知看到 2.1的版本。
圖6
然後我們去查一下thinkphp 2.1的手冊。這裡我檢視的是3.2的手冊 因為這些地方版本改動不大。
where()
$User = M("User"); // 執行個體化User對象
$User->where('type=1 AND status=1')->select();
對應的原生sql語句:SELECT * FROM think_user WHERE type=1 AND status=1
order()
$User->where('status=1')->order('id desc')->limit(5)->select();
對應的原生sql語句:SELECT * FROM think_user WHERE status=1 order by id desc limit 5
field()
$Model->field('id,title,content')->select();
對應的原生sql語句:SELECT id,title,content FROM table
limit()
$User->where('status=1')->field('id,name')->limit(10)->select();
對應的原生sql語句:SELECT id,name FROM think_user limit 10
我們可以構造一個 四個函數都用到的寫法
$User->where('status=1')->field('id,name')->order('id desc')->limit(5)->select();
生成的sql語句:SELECT id,name FROM think_user WHERE status=1 order by id desc limit 5
我們分析
在where 位置 limit位置 order 位置 如果構造語句的話都需要觸及到php_safe.php中被黑名單的危險關鍵詞。這裡我們不去研究如何繞過這個防禦腳本。而是在現有的漏洞環境中分析漏洞的産生。
但是,在field 位置 我們無需使用到被黑名單的危險關鍵詞,就可以直接構造出想要查詢其他表中字段的語句。好了,我們現在已經确定了 field參數符合SQL注入産生的條件。
我們回到ajax_arclist的開頭往下走。看如何能執行h71的sql語句。
在h35看到了exit() 終止語句不往下繼續執行的意思。我們要繞過,是以給變量$model 随便指派一個存在白名單的就可以繞過繼續執行下面的代碼,這裡給$model指派“article”。繼續往下走在h37判斷是否有傳遞的表名字首,如果有就與表名拼接,沒有就算了。然後繼續往下走,在h58判斷如果傳參page值就走h64,不傳參$page 就執行h70的sql語句。
Payload構造思路
我們想要爆出賬号密碼就要查詢dami_member中的username,userpwd兩個字段。想要執行SELECT username,userpwd from dami_member,這樣的語句就給field參數指派username,userpwd from dami_member%23,構造連結通路http://localhost/test0/index.php?s=/api/ajax_arclist/model/article/field/username,userpwd from dami_member%23 他其實執行的語句就成了SELECT username,userpwd from dami_member# FROM `dami_article`,我們注入的payload被拼接閉合在了原來的sql語句中,導緻爆出了賬号密碼的輸出,證明了sql注入漏洞的存在。