漏洞简介
用友U8+是用友公司推出的企业管理软件平台,广泛应用于财务、供应链及人力资源等核心业务流程中。在U8+渠道管理(高级版)模块中,gettoken_new 接口存在SQL注入漏洞。该漏洞是由于页面在处理用户输入的参数时,未对输入内容进行充分过滤与安全校验,攻击者可构造恶意SQL语句,通过HTTP请求注入至后端数据库查询中。
影响版本
V18, V16.5, V16.1, V16.0, V15.1, V15.0, V13
fofa语法
title="渠道管理(高级版)"
漏洞分析
根据web.xml对url /api/gettoken_new 的映射
<servlet>
<servlet-name>GetTokenServlet</servlet-name>
<servlet-class>
com.gxfcsoft.framework.core.GetTokenServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>GetTokenServlet</servlet-name>
<url-pattern>/api/gettoken_new</url-pattern>
</servlet-mapping>
直接看 com.gxfcsoft.framework.core.GetTokenServlet 实现逻辑
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Calendar c = Calendar.getInstance();
String start_date = DateUtil.getDateTime(c);
String errorInfo = "";
String resultInfo = "";
boolean isSuccess = false;
String remoteAddr = req.getRemoteAddr();
String remoteHost = req.getRemoteHost();
String remoteUser = req.getRemoteUser();
int remotePort = req.getRemotePort();
String path = req.getPathInfo();
if (path == null || path.isEmpty())
path = req.getRequestURI().substring(req.getContextPath().length());
String username = "";
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
JSONObject json = new JSONObject();
String appid = req.getParameter("appid");
String userid = req.getParameter("userid");
String appkey = req.getParameter("appkey");
String appsecret = req.getParameter("appsecret");
json = checkParams(appid, userid, appkey, appsecret, json);
if (json.isEmpty()) {
appsecret = appsecret.replace(" ", "+");
Element element = queryObject(appid, appsecret, appkey);
跟进checkParams 方法看下
public JSONObject checkParams(String appid, String userid, String appkey, String appsecret, JSONObject json) {
if (StringUtil.isEmpty(appid)) {
json.put("flag", "1");
json.put("msg", String.valueOf(appid) + "为空!");
}
if (StringUtil.isEmpty(userid)) {
json.put("flag", "1");
json.put("msg", String.valueOf(userid) + "为空!");
}
if (StringUtil.isEmpty(appkey)) {
json.put("flag", "1");
json.put("msg", String.valueOf(appkey) + "为空!");
}
if (StringUtil.isEmpty(appsecret)) {
json.put("flag", "1");
json.put("msg", String.valueOf(appsecret) + "为空!");
}
return json;
}
判断这些参数是否为空。继续跟进queryObject 方法
public Element queryObject(String appid, String appsecret, String appkey) {
Connection conn = null;
try {
conn = ResManager.getConnection("default");
UserState us = new UserState();
us.setCorpName("default");
CommonDao cDao = new CommonDao(conn, us);
String select_sql = "select top 1 * from iauthregister where appid = '" + appid + "' and appsecret = '" + appsecret + "' and appkey = '" + appkey + "' ";
Element element = cDao.findOne(select_sql);
return element;
} catch (SQLException e) {
e.printStackTrace();
return null;
} finally {
if (conn != null)
ResManager.freeConnection("default", conn);
}
}
到这就很明了了,参数appid、appsecret和appkey未经过任何过滤或校验就被直接拼接进SQL语句中,从而导致SQL注入漏洞。
补丁修复也很直接,正则检测是否包含危险字符串

漏洞复现
GET /api/gettoken_new?appid='SQLI_POC&appkey=1&appsecret=1&userid=1 HTTP/1.1
Host: u8.mrxn.net

延时 5 秒成功


