雷石|用友NC的任意文件覆蓋漏洞分析

最近看到一個NC的任意文件上傳漏洞,自己在復(fù)現(xiàn)的時候不知是版本問題還是姿勢問題怎么都不成功,遂分析了一下。
01.
漏洞分析
以下分析及復(fù)現(xiàn)均在NC6.3和NC6.5版本下進行。?
已知是saveDoc.ajax接口存在問題,先看存在漏洞的功能模塊下的配置文件。
<config><action-mappings ><action path="/getAllServices.ajax"type="nc.uap.ws.console.action.GetServicesAction" /><action path="/login.ajax"type="nc.uap.ws.console.action.LoginAction" /><action path="/getBasicInfo.ajax"type="nc.uap.ws.console.action.GetBasicInfoAction" /><action path="/getWssInfo.ajax"type="nc.uap.ws.console.action.GetWssInfoAction" /><action path="/getKSInfo.ajax"type="nc.uap.ws.console.action.GetKSInfoAction" /><action path="/saveDoc.ajax"type="nc.uap.ws.console.action.SaveDocAction" /><action path="/loadDoc.ajax"type="nc.uap.ws.console.action.LoadDocAction" /><action path="/loadReqTemplete.ajax"type="nc.uap.ws.console.action.GenSoapRequestAction" /><action path="/soapRequest.ajax"type="nc.uap.ws.console.action.SoapRequestAction" /><action path="/soapFormat.ajax"type="nc.uap.ws.console.action.SoapFormatAction" /></action-mappings><login name = "administrator" password="ufsoft*12345"/></config>
找到了相應(yīng)的jar包,查看該接口的代碼,如下:
public class SaveDocAction implements IAction {public Faults execuse(HttpServletRequest req,HttpServletResponse resp) {String ws = req.getParameter("ws");String content = req.getParameter("content");DocHelper manager = new DocHelper(Config.getDocDir());try {if (ws == null || content == null) {resp.setStatus(401);resp.getWriter().write("0");resp.sendError(401,"Not certified");} else {manager.saveDoc(ws, content);}} catch (IOException e) {Logger.error(e.getMessage(), e);}return null;}}
獲取了兩個參數(shù),ws和content,先檢查是否空值,空值就響應(yīng)401了,不為空時會傳給DocHelper類的saveDoc函數(shù)處理。
來看saveDoc的代碼:
public void saveDoc(String ws, String content) throwsIOException {File dir = new File(this.DocDir);if (!dir.exists() || !dir.isDirectory())dir.mkdir();File file = new File(dir, ws + ".txt");FileOutputStream os = null;if (file.exists())try {os = new FileOutputStream(file);os.write(content.getBytes());} catch (IOException e) {throw e;} finally {if (null != os) {os.close();os = null;}}}}
先是檢查路徑是否存在,不存在先創(chuàng)建路徑,然后創(chuàng)建File對象,此時文件還未存入磁盤。
這里創(chuàng)建FIle對象時 用了兩個參數(shù)拼接 dir是默認(rèn)的路徑,ws是用戶提交的在這里拼接了.txt后綴。
接著是file.exists() 判斷文件是否存在,不存在時使用文件流(FileOutputStream)將數(shù)據(jù)寫入磁盤文件。
由于ws參數(shù)是可控的且沒有檢查過濾,就造成了任意文件上傳漏洞嗎?
注意看 if (file.exists())的部分,
這里的寫入文件之前 ,并沒有使用createNewFile()創(chuàng)建文件,如果上傳的文件是磁盤中本身不存在文件,這里執(zhí)行完也不會有新文件創(chuàng)建,如果上傳的文件路徑 已經(jīng)有了舊文件,那就會覆蓋舊文件內(nèi)容。
下面通過復(fù)現(xiàn)過程來理解漏洞
02.
漏洞復(fù)現(xiàn)
1.先訪問接口,接口存在但返回了401,沒有權(quán)限
/uapws/saveDoc.ajax?ws=vvv&content=vvv
補上兩個參數(shù),繞過了認(rèn)證權(quán)限,返回200
/uapws/saveDoc.ajax?ws=vvv&content=vvv

按照剛才對代碼的分析,此時如果是正常的文件上傳情況下,應(yīng)該會在磁盤的目錄內(nèi)寫入 vvv.txt 的文本文件。
但我們分析了代碼缺少createNewFile(),實際結(jié)果是。

但如果服務(wù)器已經(jīng)存在的文件,是否能寫入?即“文件覆蓋”先創(chuàng)建aaa.txt

然后發(fā)送請求,覆蓋文件。
http://10.168.20.203:9000/uapws/saveDoc.ajax?ws=aaa&content=aaayes
執(zhí)行結(jié)果如圖

也可以通過00截斷來繞過。txt后綴限制
POST http://10.168.20.203:9000/uapws/saveDoc.ajax?ws=test.jsp%00content=testok
2.使用00截斷
3.成功覆蓋任意后綴文件

結(jié)語:
又是被瞎命名忽悠的一天~
杭州漠坦尼科技有限公司
商務(wù)咨詢:
0571-87031601
商務(wù)郵箱:
雷石安全實驗室
歡迎關(guān)注我們!
本文作者:xueqi
