某通电子文档安全管理系统SQL注入漏洞 代码分析

某通电子文档安全管理系统SQL注入漏洞 代码分析

影响版本

V5.6.3.152.186 20240811之前

产品简介

某通电子文档安全管理系统是一款综合性的数据智能安全产品,涵盖了透明加密、数据分类分级、访问控制等多项核心技术。该系统保护范围广泛,包括终端电脑、智能终端以及各类应用系统,能有效防止数据泄露,满足数据安全合规要求。该系统采用事前主动防御、事中实时控制、事后及时追踪的设计理念,全方位保障用户终端数据安全。

代码分析

首先进入WEB-INF的web.xml页面中,Fn+F搜索CDGAuthoriseTempletService1

image-20240809122703164

Ctrl点击键入该类中,该类位于com/esafenet/servlet/service/document/CDGAuthoriseTempletService1.class中,这个是一个servlet文件,找到与前端交互的方法即service方法

image-20240809123056046

对该代码分析如下

    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
        response.setContentType("text/html");  
        ServiceUtil.XMLInit(this.xStream);//调用一个工具类,用于初始化初始化xstream对象,用于XML序列化和反序列化  
        CDGAuthoriseTemplet caTempl \= new CDGAuthoriseTemplet();//可能是一个数据访问对象(DAO)  
        String toServerXML \= ServiceUtil.getXMLFromRequest(request);//获取请求中的xml字符串  
        GetCDGAuthoriseTemplet gcat \= (GetCDGAuthoriseTemplet)this.xStream.fromXML(toServerXML);//将XML字符串反序列化为GetCDGAuthoriseTemplet类型的对象gcat  
        boolean flag \= this.validateInfo(gcat);//对反序列化的内容进行校验  
        if (!flag) {//校验结果为false,直接进行gcat序列化为xml发送响应  
            ServiceUtil.sendInfo(request, response, this.xStream.toXML(gcat));  
        } else {  
            CDGAuthoriseTempletModel model \= new CDGAuthoriseTempletModel();  
​  
            try {  
                caTempl \= model.getAuthoriseTempletList(caTempl, gcat.getUserId(), gcat.getSecretLevelId());//取授权模板列表  
                ServiceUtil.sendInfo(request, response, this.xStream.toXML(caTempl));//将结果(即caTempl对象)的XML表示发送给客户端。  
            } catch (Exception var9) {  
                Exception e \= var9;  
                e.printStackTrace();  
                gcat.setReturnMessage("error099");  
                ServiceUtil.sendInfo(request, response, this.xStream.toXML(gcat));  
            }  
        }  
    }

分析:上述代码就是接受前端的请求数据,数据类型为xml,将其进行xml反序列之后进行校验,进行校验成功之后调用getAuthoriseTempletList方法,之后将内容进行序列化返回给前端

我们先分析一下这个校验即this.validateInfo(gcat);

    private boolean validateInfo(GetCDGAuthoriseTemplet gcat) {  
        String userId \= gcat.getUserId();  
        String secretLevelId \= gcat.getSecretLevelId();  
        if (userId != null && !"".equals(userId)) {  
            if (secretLevelId != null && !"".equals(secretLevelId)) {  
                try {  
                    User localUser \= this.userDao.findUserById(userId);  
                    if (localUser \== null) {  
                        gcat.setReturnMessage("error007");  
                        return false;  
                    } else {  
                        return true;  
                    }  
                } catch (Exception var5) {  
                    gcat.setReturnMessage("error104");  
                    return false;  
                }  
            } else {  
                gcat.setReturnMessage("error112");  
                return false;  
            }  
        } else {  
            gcat.setReturnMessage("error101");  
            return false;  
        }  
    }  
}

上述代码就是先判断序列化之后的内容中userId以及secretLevelId是否为空,不为空则进行findUserById操作,Ctrl点击跟进该方法

image-20240809131236314

分析:绿框中的内容对userid的内容转换为小写,尝试从缓存(usermap)中获取用户信息,找到将结果返回

蓝框中的内容就是去数据库中查找是否有该userId,若有则将结果返回

分析完这个校验之后,接着进入到校验成功之后else语句中即如图代码中

image-20240809131826665

分析:调用了model.getAuthoriseTempletList方法进行模板列表的更新,之后进行序列化并将结果返回给前端

Ctrl点击进入到getAuthoriseTempletList方法中

image-20240809132254737

它又调用了List<AuthoriseTemplet>下的getAuthoriseTempletList方法,我们继续跟进

image-20240809132420212

分析:调用 this.getAuthoriseTempletList(userId, secretLevelId) 方法来获取与指定用户和密级相关的 CDGAuthoriseTempletInfo 对象列表其中包含包括名称(name)、描述(description)、密级(secretLevel)、创建日期(createDate)。然后创建一个空的 ArrayList 类型的 authoriseTempletList,用于存储转换后的 AuthoriseTemplet 对象,将获取到的对象列表中的内容给到AuthoriseTemplet 对象之后返回这个对象

我们进入到getAuthoriseTempletList方法中查看它是如何获取对象列表的

image-20240809133658638

分析:该方法就是判断我们传递的userIdsecretLevelId是否为空,若不为空就将其拼接到sql语句中(猜测这就是sql注入漏洞形成的原因),之后调用dao.getAuthoriseTempletList(sqls.toString())将其结果返回

进入到List<CDGAuthoriseTempletInfo>下的getAuthoriseTempletList方法中,这里见我们转入的参数进行了sql语句的拼接后,调用了dao.getAuthoriseTempletList方法,这里有多个地方声明了该方法我们选择的是第一个

image-20240809134019773

image-20240809134827756

分析:该方法会将我们传入的参数直接拼接到sql语句中即(sql.append(condtion)),之后进行调用getCommonResults(sql.toString())方法执行sql语句的查询(并且没有任何过滤)并将结果赋值给maps,之后就是判断maps是否为空,将maps中的内容赋值给list,返回list。

总结

经过以上分析我们已经确定了该漏洞的成因,

  1. CDGAuthoriseTempletModel下的getAuthoriseTempletList方法--->List<AuthoriseTemplet>下的 getAuthoriseTempletList方法,其中的参数就是我们可以控制的由前端传过来UserIdSecretLevelId
  2. List<AuthoriseTemplet>下的 getAuthoriseTempletList方法-->List<CDGAuthoriseTempletInfo>下的getAuthoriseTempletList方法,通过sqls.append将我们可以控制的参数进行sql语句的拼接
  3. List<CDGAuthoriseTempletInfo>下的getAuthoriseTempletList方法-->dao.getAuthoriseTempletList(sqls.toString())只进行getCommonResults进而执行sql语句并将结果返回

因此只要我们在前端传入的参数UserId是缓存中的内容或者是数据库中的存在的值进而绕过validateInfo的if校验,进入到else语句中,之后SecretLevelId传入我们恶意的sql语句,进入getAuthoriseTempletList方法中进行sql语句的执行,这样从而将我们想要的数据以xml的格式返回到响应中

然后我们进行构造POC

电子文档安全管理系统(CDG)

图片.png

然后用加解密工具去加密

https://github.com/wafinfo/DecryptTools

图片.png
发送 POC 可直接获取到管理员账户密码。

POST /CDGServer3/CDGAuthoriseTempletService1 HTTP/1.1   
​  
Host:   
​  
Cache-Control: max-age=0   
​  
Sec-Ch-Ua: "Not:A-Brand";v="99", "Chromium";v="112"   
​  
Sec-Ch-Ua-Mobile: ?0   
​  
Sec-Ch-Ua-Platform: "Windows"   
​  
Upgrade-Insecure-Requests: 1   
​  
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like   
​  
Gecko) Chrome/112.0.5615.138 Safari/537.36   
​  
Accept:   
​  
text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,\*   
​  
/\*;q=0.8,application/signed-exchange;v=b3;q=0.7   
​  
Sec-Fetch-Site: none   
​  
Sec-Fetch-Mode: navigate   
​  
Sec-Fetch-User: ?1   
​  
Sec-Fetch-Dest: document   
​  
Accept-Encoding: gzip, deflate   
​  
Accept-Language: zh-CN,zh;q=0.9   
​  
Connection: close   
​  
Content-Type: application/xml   
​  
Content-Length: 510   

加密数据

图片.png

最后将返回的结果进行解密,可看到账户密码信息

图片.png

0 条评论