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

雷石安全实验室

共 8839字,需浏览 18分钟

 ·

2024-04-01 20:03

31ab3a865a3a7bbbf846c8ab181305b6.webp


最近看到一个NC的任意文件上传漏洞,自己在复现的时候不知是版本问题还是姿势问题怎么都不成功,遂分析了一下。



01.

漏洞分析

以下分析及复现均在NC6.3和NC6.5版本下进行。

已知是saveDoc.ajax接口存在问题,先看存在漏洞的功能模块下的配置文件。

                  
                    
                      <?xml version="1.0" encoding="UTF-8"?>
                    
                  
                  
                    
                      <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>
                    
                  
                


找到了相应的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;
                  
                  
                    }
                  
                  
                    }
                  
                

获取了两个参数,ws和content,先检查是否空值,空值就响应401了,不为空时会传给DocHelper类的saveDoc函数处理。

来看saveDoc的代码:

                  
                    public void saveDoc(String ws, String content) throws
                  
                  
                    IOException {
                  
                  
                    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;
                  
                  
                    }
                  
                  
                    }
                  
                  
                    }
                  
                  
                    }
                  
                


先是检查路径是否存在,不存在先创建路径,然后创建File对象,此时文件还未存入磁盘。


这里创建FIle对象时 用了两个参数拼接 dir是默认的路径,ws是用户提交的在这里拼接了.txt后缀。


接着是file.exists() 判断文件是否存在,不存在时使用文件流(FileOutputStream)将数据写入磁盘文件。


由于ws参数是可控的且没有检查过滤,就造成了任意文件上传漏洞吗?


注意看 if (file.exists())的部分,

这里的写入文件之前 ,并没有使用createNewFile()创建文件,如果上传的文件是磁盘中本身不存在文件,这里执行完也不会有新文件创建,如果上传的文件路径 已经有了旧文件,那就会覆盖旧文件内容。


下面通过复现过程来理解漏洞





02.

漏洞复现

 1.先访问接口,接口存在但返回了401,没有权限

                  
                    /uapws/saveDoc.ajax?ws=vvv&content=vvv
                  
                

   65c7101d3566110a9532e360f7a196fd.webp


补上两个参数,绕过了认证权限,返回200

                  
                    /uapws/saveDoc.ajax?ws=vvv&content=vvv
                  
                

6dfbf3ad09a769e159456dd71ca2823f.webp


按照刚才对代码的分析,此时如果是正常的文件上传情况下,应该会在磁盘的目录内写入 vvv.txt 的文本文件。

但我们分析了代码缺少createNewFile(),实际结果是。

27bc4a408e6a7f711f0c1875434a225a.webp


但如果服务器已经存在的文件,是否能写入?即“文件覆盖”先创建aaa.txt

71d4448ec8411f05e8069e620cf69dfe.webp


然后发送请求,覆盖文件。

                  
                    http://10.168.20.203:9000/uapws/saveDoc.ajax?
                  
                  
                    ws=aaa&content=aaayes
                  
                


执行结果如图

7cc166351db6e739745f0af722931a25.webp


也可以通过00截断来绕过。txt后缀限制

                  
                    POST http://10.168.20.203:9000/uapws/saveDoc.ajax?
                  
                  
                    ws=test.jsp%00
                  
                  
                    content=testok
                  
                

c7085a6dc6c04bfa67f1020a23dbd2d0.webp


2.使用00截断

d9fb95195450c4d0b05184175a3c3667.webp


3.成功覆盖任意后缀文件

37e774a6bd79ef575c85dd0b162a8dd2.webp


结语:



又是被瞎命名忽悠的一天~

杭州漠坦尼科技有限公司

商务咨询:

0571-87031601

商务邮箱:

mtn@motanni.com

雷石安全实验室


欢迎关注我们!


本文作者:xueqi

浏览 12
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报