漏洞通報信息:
https://mp.weixin.qq.com/s/_bpg8buT92dzRuGdr2ZrRg
https://mp.weixin.qq.com/s/s1yqJNOsCk-uVyCtg6SG7A
OA-2017非官網:http://www.downxia.com/downinfo/202980.html
最新版v11下載地址:http://www.tongda2000.com/download/2019.php?F=baidu_natural&K=
補丁包:http://cdndown.tongda2000.com/oasp/2019/2020_A1.rar
下載補丁包查看,發現新版v11的補丁有點多啊,又看了一下2017版本的,發現只修改了一個ispirit/im/upload.php。於是選擇先分析OA2017作爲切入點,方便偷懶。
基本思路:安裝2017版的通達OA,提取出對應的upload.php做個代碼對比,就能夠知道補丁的修改點了。
安裝後在webroot目錄下獲得了全部代碼,不過代碼都是zend54加密的,需要解密。
由於文件比較多,可以使用SeayDzendj本地解密:https://www.webshell.cc/6379.html
之後使用Bcompare進行代碼比對,發現代碼有兩處變動。
第一處:
第二處:
分析:
第一處代碼的修改使原本可以不包含的auth.php變成了必定包含。那我們來看一下auth.php的內容。
auth.php
顯然,auth.php是用來檢驗用戶登錄狀態的。那麼在修復前,是if..else語句,該檢測可以被繞過,從而在未登錄的狀態下執行後續的文件上傳操作。
第二處代碼的修改則是多了一句
if (strlen(urldecode($_FILES['ATTACHMENT']['name'])) != strlen($_FILES['ATTACHMENT']['name']))
{
$_FILES['ATTACHMENT']['name'] = urldecode($_FILES['ATTACHMENT']['name']);
}
如果字符串解碼後的長度與原長度不同,說明可以被url解碼,那麼再url解碼,而不是直接解碼。
一開始懷疑是把shell.php文件名二次編碼後繞過上傳檢測,然後在其他調用上傳文件的頁面(例如個人文件移動)中被再次解碼,生成shell.php文件。 所以在此加入了檢測語句,防止文件名被二次解碼。但仔細一想,發現這根本沒什麼用呀,這裏的代碼解碼只進行了一次,無法檢測3次、4次url編碼的文件名,並不能達到攔截文件名的效果。
網站內隨便找點上傳功能試試,也沒發現什麼端倪
這邊疑惑了很久,搞不清它的意義。後來覺得可能這並不是漏洞的修補點,因爲通達OA2017也有很多個小版本,可能小版本更新中早就已經加入了這段代碼,而非此次的補丁(後續對OA v11的分析也印證了這一點)。
在url檢測後,緊接着是文件上傳。
$ATTACHMENTS = upload("ATTACHMENT", $MODULE, false);
嘗試構造上傳請求,必要的變量名有P,DEST_UID,以及一個文件的變量名ATTACHMENT。
同時上傳參數值以及文件內容的請求比較少見,那麼此時作爲一個垃圾安全人員,如何POST值的同時加入文件上傳這種問題,顯然是要百度解決的。百度後,我們可以構造類似於下面這種形式的頁面代碼,抓取其請求進行修改。
<form action="user.do" id="upfile" method="post" enctype="multipart/form-data">
<input type="hidden" name="x2" value="12334" />
<input type="file" name="x1" value="瀏覽圖片" />
<input type="submit" value="tijiao"/>
</form>
構造請求包,上傳成功。文件保存於\MYOA\attach\im\2003\目錄,在原來的文件名前面加了一長串隨機值,而且該目錄不存在web目錄下。 嘗試在文件名中插入../測試是否能目錄穿越,也不行。
我們再看代碼,之前提到的第二處代碼修改點的外圍是if ($UPLOAD_MODE == '1') { }。
那麼就想着嘗試$UPLOAD_MODE == '1'來看看會出現什麼情況,結果發現$UPLOAD_MODE這個變量是憑空出現的! 先不慌,猜想可能是從其他文件中包含過來的,或者是某種全局變量啥的。 全局搜索字段“UPLOAD_MODE”,也是什麼都沒有。 那麼這個變量是量子力學?平行宇宙?
可以通過“變量覆蓋漏洞”的知識點聯想“變量註冊”這個概念,參考:https://www.cnblogs.com/xiaozi/p/7768580.html
例如當register_globals=On的時候,可以直接使用$id來代替$_GET['id'] $_POST['id']接受傳遞過來的值。 當然不只這一種方式,此處也並非是這種方式,就不再浪費時間去找相關的代碼了。 實踐出真知,直接上傳測試。
變量$UPLOAD_MODE註冊成功,上傳文件成功,實際在目錄中的文件名是1123589952.12345.gif,還是仍舊保存在原來的目錄。
不過只能上傳小馬文件,卻無法觸發,這就很難受。繼續分析一下,會發現一個奇怪的地方,upload.php所在的目錄\ispirit\im中的代碼似乎是一條獨立的系統,並沒有用於其web頁面。
這im其實是負責通達OA的客戶端程序-辦公精靈的後端接口。從菜單欄-附件程序可以下載
下載了客戶端,不過客戶端一直連不上服務。而且也爲這2017版的漏洞點花了太多時間,性價比不高,就暫時停止了。
回過頭來看最新版v11,我們以2017的upload.php漏洞進行切入。
查看ispirit/im/upload.php,通過對比可以發現只有一個修改點,和2017版本的補丁一樣,是對auth.php的包含問題。而之前在2017版本的困惑的第二個修改點,在此卻並不是補丁,代碼前後一致,說明之前的想法是對的,這裏並不是漏洞觸發點。
然後我們對所有的補丁的文件做個統計,會發現大部分的代碼修改點都是一致的
general\appbuilder\modules\officeproduct\models\OfficeProducts.php
general\netdisk\api.php
general\person_info\avatar\avatar.upload.php
general\picture\upload_new.php
general\reportshop\design\report\set_report.php
general\reportshop\workshop\report\crscell\set_report.php
general\setting_guide\update.php
general\index_simple_submit.inc.php
inc\attendance\attend.clock.funcs.php
inc\interface\interface.netdisk.funcs.php
inc\interface\interface.picture.funcs.php
inc\utility_file.php
module\AIP\upload.aip.php
task\clean\slow_logs.inc.php
上述14個文件的代碼修改點:rename函數更改爲td_rename
general\system\attachment\position\add.php
general\system\attachment\position\update.php
上述2個文件的代碼中皆增加了如下代碼檢測,檢測路徑中的關鍵字。
ispirit\im\upload.php 包含auth.php,檢測登錄狀態。
\ispirit\interface\gateway.php增加了..檢測,防止跨目錄包含
mobile\inc\funcs.php
general\netdisk\swfupload_new.php
這兩個文件改動有些大,不再討論。
分析一下最廣泛的補丁:rename函數更改爲td_rename,
rename()是php的自帶函數,rename(oldname,newname)函數重命名文件或目錄。若成功,則該函數返回 true。若失敗,則返回 false。rename也是支持路徑輸入的,即可以移動文件,跨目錄改名。
td_name()則是在inc\utility_file.php中被定義的:
function td_rename($oldname, $newname)
{
if (!is_uploadable($newname)) {
Message(_("禁止"), _("禁止創建此類型文件"));
Button_Back();
exit();
}
if (file_exists($oldname)) {
return rename($oldname, $newname);
}
else {
Message(_("錯誤"), _("原文件不存在"));
Button_Back();
exit();
}
}
有了is_uploadable()的檢測, 其定義也在inc\utility_file.php中,禁止改名後的新文件以php爲後綴。
很容易聯想到在ispirit\im\upload.php中存在無需登錄的文件上傳,只不過文件名稱被做了限制,而且保存目錄不在網站目錄下。 這時候配合rename()的改名和移動目錄的能力,就能把文件名改爲xx.php並放入網站目錄下。不過遺憾的是,這個改名操作的漏洞點需要用戶在登錄狀態下才能,降低了安全風險。 rename()帶來的安全隱患應該普遍存在於各個web項目中。
參考:
UnicodeSec出了一個分析,https://www.cnblogs.com/potatsoSec/p/12516234.html
在ispirit/interface/gateway.php中存在的文件包含漏洞可以通過包含日誌的形式觸發,且無需登錄。
poc:
首先構造url並訪問,在日誌中寫入一句話
/ispirit/interface/gateway.php?json={}&aa=<?php file_put_contents('1.php','hello world');?>
然後通過如下url進行文件包含利用
/ispirit/interface/gateway.php?json={}&url=../../ispirit/../../nginx/logs/oa.access.log