0x00 前言
這段時間就一直在搞代碼審計了。針對自己的審計方法做一下總結,記錄一下步驟。
審計沒他,基礎要牢,思路要清晰,姿勢要多且正。
下面是自己審計的步驟,正在逐步調整,尋求效率最高。
0x01 關於 XiaoCms
XiaoCms 企業建站版基於 PHP+Mysql 架構 是一款小巧、靈活、簡單、易用的輕量級 cms。能滿足各種企業站 博客 等中小型站點。(此cms貌似已經停止更新了)
01. 支持自定義內容模型
通過自定義內容模型和自定義字段可以輕松簡單的定制出各種內容模型 如新聞模塊、產品模塊、下載模塊、圖片模塊。
02. 支持自定義會員模型。
通過自定義會員模型可以擴展各種會員模型 如 個人、企業。
03. 支持自定義表單模型。
通過自定義表單模型可以擴展內容評論、 在線留言、 報名、產品訂購、等各種提交表單。
04. 支持自定義表。
05. 區塊管理功能。
06. 支持手機版。
07. 支持url偽靜態 生成靜態 動態 三種模式。
08. 支持游客投稿。
09. 支持會員投稿,會員模塊單獨分離可選不安裝。
10. 簡單易用的后台操作管理方式,小白也懂得怎么用。
11. 靈活的模板標簽語言 讓制作模板更容易更省時間。
12. 系統開源二次開發簡單。
13. 自定義推薦位。
14. 采用pdo數據庫驅動提高安全性。
15. 前后台徹底分離,支持更改后台目錄。
16. XiaoCms不僅僅是企業建站cms,更是輕量級的萬能建站CMS
(摘自官網)
(從官網簡介我們知道數據庫使用了pdo預處理)
下載好源碼解壓,安裝好程序。
0x02 初識XiaoCms
目錄結構
├─admin //后台
│ ├─controller //控制器
│ ├─img //后台圖片
│ └─template //后台模板
├─core //核心模塊
│ ├─controller //控制器
│ ├─img //圖片
│ │ ├─calendar
│ │ │ └─skins
│ │ │ └─default
│ │ ├─js
│ │ ├─kindeditor
│ │ │ ├─lang
│ │ │ ├─plugins
│ │ │ │ ├─autoheight
│ │ │ │ ├─baidumap
│ │ │ │ ├─clearhtml
│ │ │ │ ├─code
│ │ │ │ ├─filemanager
│ │ │ │ │ └─images
│ │ │ │ ├─flash
│ │ │ │ ├─image
│ │ │ │ │ └─images
│ │ │ │ ├─insertfile
│ │ │ │ ├─lineheight
│ │ │ │ ├─link
│ │ │ │ ├─media
│ │ │ │ ├─multiimage
│ │ │ │ │ └─images
│ │ │ │ ├─pagebreak
│ │ │ │ ├─plainpaste
│ │ │ │ ├─quickformat
│ │ │ │ └─wordpaste
│ │ │ └─themes
│ │ │ ├─common
│ │ │ ├─default
│ │ │ └─simple
│ │ ├─message
│ │ ├─uploadify
│ │ └─watermark
│ └─library //一些輔助庫
├─data //存放數據
│ ├─bakup
│ ├─cache
│ ├─config
│ ├─install
│ ├─models
│ ├─tplcache
│ └─upload
│ └─image
└─template
├─default
│ └─images
└─mobile
從目錄文件名定義,我們大概可以猜測系統使用的是MVC模式。
借助工具phpstorm,從index.php跟一下程序。了解程序是怎么運行的,做了什么過濾。(也就是當我們第一次訪問index.php的執行過程)
跟進xiaocms.php
展開xiaocms類看一下類的具體方法:
不一一細看,主要看一下run函數
run方法的主要作用是解析傳來的 controller,action 等參數,隨之加載相應的控制器類,調用相應的方法。驗證了我們之前的猜測,這個系統確實是MVC模式。
其中在包含控制器的代碼中,只是判斷文件是否存在,就直接包含了文件。
在php5.3之前是可以用%00截斷進行目錄穿越,造成任意文件包含的。
但仔細閱讀,會發現其實前面parse_request已經進行了過濾,所以此路不通。有一點需要注意的是,當我們沒有傳入c和a參數時,會默認調用index 控制器下的index方法。
在看完了這個xiaocms.php之后,我們再去看一下,之前加載的幾個類。
進入global.function.php,這是一個公共函數庫,各種輔助方法。(仔細閱讀,就不詳解了)
隨后就是version.php,只是簡單定義一下版本常量而已。
之后是Base.class.php,這是一個基礎的類庫,很多類都是繼承於它。
先看看構造函數,balbla的加載了很多東西,然后就是把該設置的設置,渲染好頁面返回給前端。
總結一下:
當我們訪問index.php時,系統先去訪問index.php ,index.php又包含了xiaocms.php,xiaocms.php又包含了global.functions.php,base.class.php等文件,設置了相應的配置,先是運行了base.class.php的構造函數,實例化了數據庫,session等對象,渲染好了基礎頁面。隨之運行run方法,解析傳輸過來的url,調用對應的控制器和方法。
程序的運行過程是大概了解了,但是不太清楚是否做了過濾?我們訪問一下文章,帶入點參數。
因為沒有傳輸c和a參數,所以程序默認調用的是index控制器下index方法
找到控制器index.php。
index 方法
傳入的是id,在else if下面.跟進get方法
對get輸入進行了過濾,轉義了雙引號和左尖括號,右尖括號。
其中post方法也是一樣的。
至此,我們大概了解了整個程序的運行路線,以及輸入過濾等。
0x03 黑盒白盒結合審計
先瀏覽一下網站,看一下前台有什么功能,后台有什么功能。主張以功能點驅動審計。
先看一下前台有什么功能,大概總結一下有四個功能點(頁面瀏覽,留言,評論,搜索)
會產生這些問題
首先看一下頁面瀏覽方面是否會產生sql注入的問題。
因為使用了pdo預編譯,注入幾率很小,但也不能說絕對,也有pdo照顧不到的地方
(1)參數占位符不能用於指定查詢中的表和列的名稱。
(2)參數占位符不能用於查詢的其他部分,比如ORDER BY子句中的ASC或者DESC關鍵詞等。
搜索一下參數為 id 或者 catid 的輸入有沒有做整型過濾
幾經測試,發現此路不通。
因為做了pdo,且經過了實體化過濾,單引號,雙引號,<,>都是沒戲的了。
那么前台的幾個功能點算是被堵死了。
再來看一下后台
先看登陸
由於用的是session跟cookie沒啥關系了,而驗證碼也是繞不過去。
唯一有點欣慰的是可以繞過鎖定15分鍾的限制,驗證碼也比較簡單,可以通過第三方庫來識別。
可以對后台進行爆破。
登陸進去后台首頁
后台功能點繁多就不一一截圖了。
既然已經進入后台了,那么我們就可以看看有沒有什么方法可以getshell。
1,配置文件??
來到系統配置頁面
我們看看config.ini.php正常狀況下是怎樣子的?
用的是單引號,因為只是過濾了雙引號,那么我們是不是可以通過單引號逃出,造成代碼執行呢?
測試一下
發現配置文件變成這樣子了。
哪里來的單引號?
跟蹤代碼發現,只有剛開始的過濾,都沒有其他過濾啊。
唯一奇怪的可能就只有var_export這個函數了。
看一下手冊,發下果然是它搞的鬼。
那么此路不通。
2,文件上傳看一下??
找到文件上傳相關代碼,發現了這么一個方法
其中這行代碼設置了upload相關配置
$result = $upload->set_limit_size(1024*1024*$size)->set_limit_type($type)->upload($_FILES[$fields],XIAOCMS_PATH.$filenpath); //設置上傳文件的大小,上傳文件的類型,設置上傳文件存儲的路徑
跟進到upload.class.php看一下上傳代碼。
先是設置上傳的限制類型
然后調用upload函數進行上傳。
跟進parse_init。判斷上傳的文件名是否在可上傳數組內。而這個可上傳后綴名數組是我們可控的。
那么就造成了任意文件上傳。
看一下有誰調用了upload方法,發現了兩個地方,其中第二個是可控的。
跟進uploadify_uploadAction方法
可以看到沒有任何限制。
那么這個請求應該是這樣子的。
http://127.0.0.1/xiaocms/admin/index.php?c=uploadfile&a=uploadify_upload&type=php&size=1000
post參數 submit,file。
本地構造一個上傳頁面
頁面代碼如下:
<html> <body> <form action="http://127.0.0.1/xiaocms/admin/index.php?c=uploadfile&a=uploadify_upload&type=php&size=1000" method="post" enctype="multipart/form-data"> <input type="file" name="file" /> <input type="hidden" name="submit" value="submit"/> <input type="submit" value="submit" /> </form> </body> </html>
上傳一個php試一下
成功getshell。
當然這里是我們能夠進入后台的前提。
如果我們沒有進入后台的話,可以利用csrf,因為這個程序后台的請求都是存在csrf的。
但還有一個問題就是文件名。
那么完全是可以通過csrf來getshell的。(有前台留言和評論功能)
update,在后台數據庫恢復處發現了一個任意目錄刪除漏洞
根據代碼我們可以可以知道paths,沒有做任何過濾,直接帶進去刪除。
代碼首先判斷了path 是否存在 以及$dir.$path是否是一個目錄,這里我們可以通過不發送path參數進行繞過。
最終的請求應該是這樣子的。
POST /xiaocms/admin/index.php?c=database&a=import HTTP/1.1 Host: 127.0.0.1 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Referer: http://127.0.0.1/xiaocms/admin/index.php?c=database Accept-Language: zh-CN,zh;q=0.8 Cookie: PHPSESSID=fgcbjs2jerab54cm70on37grh2 Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 29 submit=submit&paths[]=
首先在data目錄下新建一個test文件夾作為測試文件夾
發送請求包
查看一下目錄
成功刪除test文件夾。
update
審另一套cms的時候,想起了p神之前的分享,說到了一個叫會話固定的漏洞。
發現此cms也是存在的。
看代碼 \core\library\session.class.php
會話初始時會接受外部參數,設置session_id。
起初我以為必須網站管理員在還沒有打開這個網站的時候可以使用,也就是還沒有初始化session的時候,實驗發現。就算已經是初始化了session,也是通過一個鏈接,讓管理員設置session id 為我們控制的session_id。
想到的一個場景就是,網站管理員在收到留言的時候,點擊了我們的鏈接,然后種下了我們設置的session_id。
我們就可以利用這個session_id直接登陸后台,再通過之前的任意文件上傳漏洞,直接getshell。
poc代碼:
<html> <body> <form action="http://127.0.0.1/xiaocms/" method="post"> <input type="hidden" name="session_id" value="testxiaocms"> <input type="submit" > </form> </body> </html>
0x04 總結
通過這次審計,算是熟練了自己審計的思路和步驟吧。
總的來說這套cms,問題不是很多。現在僅發現了一個后台爆破和后台getshell。
但因為這套cms已經很久沒有更新了,且都是后台的問題,並不會有什么影響。
還有很多想寫的,待以后再說吧。