用友NC checkekey接口SQL注入漏洞(XVE-2024-37013)复现与深度分析

📅 2026/7/5 9:24:50
用友NC checkekey接口SQL注入漏洞(XVE-2024-37013)复现与深度分析
1. 项目概述一次典型的企业级应用漏洞深度剖析最近在安全研究圈子里用友NC这个老牌ERP系统又曝出了一个值得关注的漏洞编号XVE-2024-37013核心问题出在checkekey这个接口上存在SQL注入风险。对于从事企业安全测试、红队评估或者应用安全研究的同行来说这类漏洞的复现与分析具有很高的实战价值。它不仅仅是一个简单的注入点更折射出在复杂业务系统中参数校验与权限控制的常见薄弱环节。这个漏洞的本质是攻击者能够通过精心构造的请求向checkekey接口传入恶意参数这些参数最终未被有效过滤就直接拼接到了数据库查询语句中从而可能执行任意SQL命令。想象一下一个支撑着企业核心财务、供应链、人力资源的系统如果存在这样的后门攻击者轻则可以窃取敏感业务数据重则可能篡改关键信息甚至获取服务器控制权后果不堪设想。因此深入理解其原理、掌握复现方法并思考防御策略对于我们构建更安全的应用环境至关重要。本文我将以一个安全研究者的视角带你从头到尾拆解这个漏洞。我会详细讲解漏洞产生的背景、用友NC中checkekey接口的典型作用、漏洞触发的具体路径并提供一个可操作的、安全的复现环境搭建与验证过程。更重要的是我会分享在复现这类漏洞时常见的“坑”以及排查技巧这些都是在实际渗透测试或代码审计中积累下来的经验希望能帮你少走弯路。无论你是刚入门的安全爱好者还是有一定经验的从业者都能从中获得一些实用的东西。2. 漏洞背景与核心原理深度解析2.1 用友NC系统与checkekey接口的角色用友NC作为一款面向大型集团企业的ERP套件其架构复杂模块众多。在这样庞大的系统中存在大量用于内部校验、状态检查或数据验证的接口checkekey通常就是其中之一。从命名习惯来看“check”和“key”的组合暗示其功能很可能是检查某个关键标识如单据编号、用户标识、会话令牌等的有效性或唯一性。在实际业务流中前端页面或服务在提交关键操作前可能会调用此类接口向后端询问“我持有的这个key是否有效是否已被使用权限是否匹配” 后端接收到这个key值去数据库里查询比对然后将结果返回。这个过程本身是合理的业务逻辑。问题就出在如果开发人员对传入的key参数过于信任没有进行严格的过滤和校验直接将其拼接到SQL语句中漏洞便产生了。这种漏洞模式在历史上有无数案例它反映的是一种“功能优先安全滞后”的开发思维。尤其是在业务压力大、追求快速上线时开发者可能会更关注功能是否实现而忽略了边界情况的安全处理。checkekey这类辅助性、非核心业务接口更容易成为安全审计的盲区。2.2 SQL注入漏洞原理与XVE-2024-37013的触发点SQL注入的原理大家都不陌生攻击者利用应用程序对用户输入数据验证不充分的缺陷在输入中插入恶意的SQL代码这些代码被后端程序误认为是合法的SQL指令的一部分而执行。XVE-2024-37013正是这种经典漏洞在用友NC特定接口上的体现。我们来推测一下漏洞代码可能的样子以下为基于常见漏洞模式的模拟代码非真实源码// 假设的漏洞代码片段 public boolean checkEkey(String userInputKey) { Connection conn getConnection(); Statement stmt conn.createStatement(); // 危险操作直接拼接用户输入 String sql SELECT COUNT(*) FROM some_table WHERE ekey userInputKey ; ResultSet rs stmt.executeQuery(sql); // ... 处理结果逻辑 }在这段伪代码中userInputKey直接和SQL字符串拼接。如果攻击者传入的值是 OR 11那么最终的SQL语句就变成了SELECT COUNT(*) FROM some_table WHERE ekey OR 11这个WHERE条件将永远为真可能导致接口返回非预期的数据例如验证通过。更危险的payload可能包括联合查询UNION SELECT、利用延时函数进行盲注、甚至执行存储过程。为什么是checkekey这类接口往往是GET请求参数暴露在URL中便于探测和攻击。其次它的返回值通常很简单如true/false,exists/not exists这反而适合盲注攻击——攻击者通过观察页面返回的差异如响应时间、返回内容、HTTP状态码来推断查询结果。对于用友NC这样数据库结构相对固定和已知的系统一旦注入点可利用攻击者就能系统地拖取用户表、权限表、业务数据表等核心信息。注意所有漏洞复现必须在合法授权和隔离环境中进行。绝对禁止对未授权的任何系统进行测试。本文所有内容仅用于安全技术研究与学习。3. 复现环境搭建与前期准备3.1 靶场环境构建策略要复现这个漏洞我们首先需要一个用友NC的测试环境。由于直接搭建完整的用友NC系统非常复杂涉及大量的商业软件和配置对于个人研究者而言不现实。因此我们通常采用以下几种更可行的策略漏洞验证环境推荐这是最安全、最合规的方式。我们可以尝试在虚拟机中基于历史版本或测试版的用友NC安装包需从合法渠道获得例如官方提供的演示版或已授权的测试版本搭建一个简单的环境。重点不是搭建全部业务模块而是确保包含存在漏洞的组件和接口。代码级模拟环境如果我们能通过分析定位到疑似存在漏洞的代码文件例如某个JSP或Java类可以单独将这部分代码提取出来嵌入到一个简单的Spring Boot或Servlet Web项目中模拟出漏洞触发的上下文。这种方法技术要求较高但能最深入地理解漏洞机理。使用公开的漏洞靶场密切关注一些开源漏洞靶场项目有时他们会集成最新的漏洞环境。虽然XVE-2024-37013比较新但可以关注类似Vulhub、WebGoat等项目的更新。对于本次复现假设我们采用第一种策略并已通过合法途径获得了一个用于安全研究的用友NC测试环境例如版本号可能为NC 6.5或某个已知受影响的版本并部署在本地虚拟机如VMware或VirtualBox中。环境配置清单主机Windows Server 2012 R2 / CentOS 7根据NC安装要求中间件IBM WebSphere / Apache Tomcat用友NC常用数据库Oracle 11g / SQL Server大型ERP常用网络虚拟机设置为Host-Only或NAT模式确保与宿主机网络互通且隔离于外网。3.2 必备工具集梳理工欲善其事必先利其器。复现一个Web漏洞尤其是SQL注入需要一套顺手的工具链。代理与抓包工具Burp Suite Professional/Community绝对的主力。用于拦截、重放、修改HTTP/HTTPS请求其Repeater模块是手动构造和测试Payload的利器Intruder模块可用于自动化模糊测试和盲注。Fiddler Classic轻量级的替代选择对于HTTP协议的抓包和分析也很方便。漏洞探测与利用工具SQLMap自动化SQL注入检测和利用的神器。它能识别注入类型、枚举数据库信息、拖取数据。在初步确认存在注入点后用SQLMap可以极大地提高效率。但切记在复现学习时应优先手动验证以理解原理再使用工具辅助。自定义Python脚本对于需要复杂逻辑判断的盲注或者工具无法很好处理的情况编写自己的脚本是必备技能。使用requests库发送HTTP请求根据响应特征进行判断。浏览器与插件Chrome/Firefox开发者工具用于快速查看网络请求、分析页面结构、调试JavaScript。HackBar / Max HackBar浏览器插件可以方便地在浏览器地址栏或新标签页中构造和发送Payload适合快速测试。辅助分析工具DirSearch / Gobuster用于目录扫描可能发现像checkekey这样的隐藏接口或文件。JD-GUI / FernFlower如果能够获取到用友NC的JAR或CLASS文件需要用这些Java反编译工具查看源码进行静态代码审计。在开始前请确保你的Burp Suite已正确配置代理浏览器信任了Burp的CA证书并且能够拦截到测试环境的流量。4. 漏洞发现与手动验证流程4.1 接口定位与请求分析首先我们需要找到checkekey接口的访问路径。这类接口的URL可能没有直接链接在前端页面上需要通过以下方式发现静态资源分析查看网页源代码中的JavaScript文件搜索“checkekey”、“check”、“ekey”等关键词可能会发现发起Ajax请求的URL。动态流量监控在Burp Suite中开启代理然后在使用用友NC测试环境时进行各种操作如点击保存、提交、验证等观察Burp的Proxy历史记录过滤出可能包含“check”或“key”的请求。目录/路径猜测结合用友NC的常见路径规律如/u8/,/nc/,/portal/,/servlet/等使用扫描工具或手动尝试访问如/nc/servlet/checkekey、/u8/api/checkekey等可能路径。假设我们通过监控流量发现了一个疑似请求GET /nc/web/some_module/checkekey.jsp?key123456789 HTTP/1.1 Host: 192.168.1.100:8080 ...或者是一个Servlet请求POST /servlet/CheckEkeyServlet HTTP/1.1 Host: 192.168.1.100:8080 Content-Type: application/x-www-form-urlencoded ekeyTESTKEY001type1找到接口后用Burp Suite的Repeater模块将其发送过去观察正常情况下的响应。正常的响应可能是一个JSON如{status:success, valid:true}或者是一个简单的文本“true”。4.2 初步注入探测与指纹识别在Repeater中我们开始修改参数值进行初步的SQL注入探测。这里的关键是观察应用程序对异常输入的反应。步骤一基础语法错误测试将key或ekey参数的值修改为包含一个单引号。Payload:123456观察点如果页面返回了数据库错误信息如Oracle的“ORA-xxxxx”MySQL的“You have an error in your SQL syntax”那么这是一个强烈的注入信号。即使没有详细报错如果页面返回了与正常请求完全不同的空白页、500错误码也可能意味着SQL语句执行出错。实操心得很多应用会捕获异常并返回统一的错误页面此时“空白”或“500错误”就是我们的“错误回显”。需要与正常返回仔细对比。步骤二逻辑测试如果第一步没有明显错误尝试逻辑真/假测试适用于盲注场景。永真Payload:123456 OR 11永假Payload:123456 AND 12观察点对比两个Payload的响应。例如一个“检查key是否存在”的接口永真条件可能返回“存在”或valid:true永假条件可能返回“不存在”或valid:false。如果两者响应有差异说明我们的输入影响了SQL逻辑注入存在。步骤三注释符测试尝试用注释符截断后续SQL代码确保我们的Payload能独立生效。Payload:123456--(Oracle, SQL Server) 或123456#(MySQL)观察点如果注入成功注释符后的SQL条件如果有会被忽略。响应应与只输入123456不同可能变得更“正常”或符合永真条件的结果。注意事项在测试过程中Burp Suite的Comparer工具非常有用它可以高亮显示两个响应之间的差异无论是HTML内容、JSON键值还是响应头能帮你发现细微的变化。4.3 确定数据库类型与注入方式一旦确认存在注入下一步是判断后端数据库类型这决定了后续Payload的构造。利用数据库特有函数Oracle: AND (SELECT 1 FROM DUAL)1--。如果正常换成0看是否有变化。MySQL: AND SLEEP(5)--或 AND BENCHMARK(1000000,MD5(test))--。观察响应是否明显延迟。SQL Server: AND WAITFOR DELAY 0:0:5--。观察延迟。PostgreSQL: AND pg_sleep(5)--。利用联合查询UNION试探 如果页面在错误时会将部分查询结果回显出来联合查询注入我们可以尝试判断列数。Payload: ORDER BY 1--, ORDER BY 2--... 逐渐增加数字直到页面报错。报错前的数字就是当前查询的列数。确定列数后尝试用UNION SELECT来探测数据库版本等信息。例如对于猜测是4列的Oracle UNION SELECT NULL, NULL, NULL, banner FROM v$version--。通过以上手动测试我们基本可以确定第一checkekey接口确实存在SQL注入漏洞第二后端数据库的类型假设测试发现对SLEEP函数有延迟反应初步判断为MySQL第三注入的类型是错误型、布尔盲注还是时间盲注。5. 利用SQLMap进行自动化验证与信息收集手动验证确认漏洞后我们可以使用SQLMap进行更深入、更自动化的利用以收集系统信息。再次强调仅用于授权的测试环境。5.1 SQLMap基础命令与参数解析在命令行中切换到SQLMap所在目录。基础命令结构如下python sqlmap.py -u http://192.168.1.100:8080/nc/web/checkekey.jsp?key123 --batch-u: 指定目标URL。--batch: 以非交互模式运行所有默认选项都选“是”适合自动化。但针对我们的场景需要更精细的参数python sqlmap.py -u http://192.168.1.100:8080/servlet/CheckEkeyServlet --dataekeyTESTtype1 --method POST --dbmsmysql --level3 --risk2--data: 指定POST请求的数据体。--method: 指定请求方法为POST。--dbmsmysql: 如果我们手动测试时怀疑是MySQL可以指定数据库类型加快检测速度。--level3: 检测等级等级越高测试的Payload和参数越多。对于Cookie、User-Agent头里的注入需要提高等级。--risk2: 风险等级提高等级会使用可能造成数据修改如UPDATE的Payload慎用在测试环境可适当提高。5.2 关键信息枚举实战SQLMap的强大之处在于其枚举能力。以下是一些关键命令获取当前数据库用户和名称python sqlmap.py -u [目标URL] --current-user --current-db这能告诉我们应用连接数据库用的是哪个账号以及当前操作在哪个数据库上。用友NC可能使用像nc、ufida、yonyou这样的数据库名。列出所有数据库python sqlmap.py -u [目标URL] --dbs这可以查看数据库服务器上还有哪些其他数据库可能包含测试库、历史库或其他业务系统的库。列出指定数据库的所有表python sqlmap.py -u [目标URL] -D nc --tables假设当前库是nc这条命令会列出nc数据库中的所有表名。我们需要关注用户表、权限表、密码表等例如sm_user,bd_user,aa_user,sys_user等以及可能存放密钥、会话信息的表。拖取表数据python sqlmap.py -u [目标URL] -D nc -T sm_user --dump这条命令会导出sm_user表的所有数据。这是非常敏感的操作在真实测试中必须获得明确授权。在复现环境我们可以查看表结构观察密码字段可能是password,user_password,cpassword的存储方式明文、MD5、SHA1、Bcrypt等。尝试获取操作系统Shell高级极度危险python sqlmap.py -u [目标URL] --os-shell这个功能尝试通过数据库的特性如MySQL的INTO OUTFILESQL Server的xp_cmdshell在服务器上执行命令。在99%的授权渗透测试中都不应轻易尝试此操作除非目标明确允许且环境完全隔离。在复现学习中可以了解其原理但谨慎执行。实操心得使用SQLMap时--proxyhttp://127.0.0.1:8080参数非常有用它可以让SQLMap的流量经过Burp Suite方便我们观察它具体发送了哪些Payload是如何判断注入的这对于学习Payload构造和绕过技巧至关重要。6. 漏洞根因分析与安全编码启示6.1 代码层面问题溯源通过前面的复现我们直观感受到了漏洞的危害。现在从代码层面深挖一下根源。问题核心在于未对用户输入进行可信校验和净化。在Java Web开发中直接使用字符串拼接构造SQL语句Statement是万恶之源。不安全代码示例再现String ekey request.getParameter(key); // 直接从HTTP请求获取 String sql SELECT * FROM nc_business_table WHERE check_key ekey ; Statement stmt connection.createStatement(); ResultSet rs stmt.executeQuery(sql);攻击者控制的ekey参数毫无阻拦地进入了SQL语句。安全的做法应该是使用预编译语句PreparedStatementString ekey request.getParameter(key); String sql SELECT * FROM nc_business_table WHERE check_key ?; PreparedStatement pstmt connection.prepareStatement(sql); pstmt.setString(1, ekey); // 参数化查询输入会被当作数据而非代码 ResultSet rs pstmt.executeQuery();使用PreparedStatement数据库驱动会确保参数被正确地转义和处理从根本上杜绝了SQL注入。6.2 框架与架构层面的防御缺失对于用友NC这样基于Java EE的复杂系统可能使用了Hibernate、MyBatis等ORM框架。这些框架本身提供了防注入机制但使用不当同样会引发问题。MyBatis的#{}与${}之坑在MyBatis的Mapper XML中#{}是预编译占位符安全而${}是字符串替换直接将参数值拼接到SQL中极其危险。如果开发人员在动态排序ORDER BY或表名选择时错误地使用了${}就会引入注入。例如ORDER BY ${sortField}如果sortField来自用户输入且未校验攻击者可以传入1; DROP TABLE users--。HQL注入Hibernate使用HQL虽然参数化查询是主流但通过字符串拼接HQL如from User where name name 同样会导致注入。权限过大的数据库账户应用连接数据库的账户往往拥有过高的权限如DBA权限。一旦发生注入攻击者利用此高权限账户所能造成的破坏就被放大了。应遵循最小权限原则应用账户只应拥有其业务必需的操作权限。6.3 纵深防御建议修复一个checkekey接口的注入只是治标。企业级应用需要建立纵深防御体系输入验证与过滤在接口入口处对key这类参数进行严格的格式和长度校验。例如如果key应该是数字或特定格式的字符串就用白名单正则表达式进行匹配拒绝任何不符合格式的输入。使用安全的API强制使用参数化查询PreparedStatement或ORM框架的安全查询方式。在代码审查中将字符串拼接SQL列为高危项。Web应用防火墙WAF部署WAF可以拦截常见的SQL注入攻击Payload作为一道有效的边界防护。但WAF可能被绕过不能替代安全的代码。定期安全扫描与代码审计对系统进行定期的黑盒漏洞扫描和白盒代码审计特别是对像checkekey这类非核心但遍布各处的辅助接口进行重点排查。错误信息处理配置自定义错误页面避免将数据库的详细错误信息如堆栈跟踪直接返回给用户这会给攻击者提供太多信息。7. 复现过程中的常见问题与排查技巧7.1 请求被拦截或返回异常问题发送测试Payload后请求被重置或返回“非法请求”、“安全校验失败”等提示。排查检查WAF/防护设备目标系统可能部署了WAF。尝试使用SQLMap的--tamper脚本对Payload进行编码、混淆以绕过WAF规则。常用脚本如space2comment,randomcase,charencode等。检查Session/Token某些接口需要有效的会话JSESSIONID或CSRF Token。确保你的测试请求携带了从正常登录流程中获取的有效Cookie和Token。在Burp中可以先走一遍完整的业务流再用那个会话去测试漏洞接口。参数格式检查参数是否需要Base64编码、URL编码或其他特定格式。用Burp的Decoder工具进行编码转换尝试。7.2 盲注判断困难问题页面返回总是同一个状态码如200内容也总是相似无法通过肉眼区分真/假条件。排查对比响应细节使用Burp Comparer对比永真和永假Payload的响应。差异可能非常细微比如某个HTML注释里的时间戳、一个隐藏字段的值、响应体的长度Content-Length不同。响应长度差异是盲注最常用的判断依据。时间盲注如果逻辑盲注无效尝试时间盲注。使用数据库的延时函数如SLEEP(5)。在Burp Repeater中发送Payload后观察右下角的响应计时器。如果注入成功响应时间会显著增加接近5秒网络延迟。编写自动化脚本当手动判断困难时就是编写Python脚本的时候了。脚本可以精确控制请求、测量响应时间、匹配特定字符串实现自动化的布尔或时间盲注判断。7.3 SQLMap无法识别注入点问题手动测试感觉有注入但SQLMap跑不出来。排查提高检测等级和风险使用--level5 --risk3。这会测试更多的参数如HTTP头和更“激进”的Payload。指定注入点如果参数在JSON或复杂数据体中使用--data并配合*标记注入点。例如--data{id:1, key:*}。处理反爬/频率限制有些系统会限制请求频率。使用--delay1每次请求延迟1秒和--timeout30设置超时时间来规避。查看详细日志使用-v 3或-v 4参数输出详细调试信息看SQLMap发送了哪些Payload收到了什么响应有助于判断问题所在。7.4 环境搭建失败或组件冲突问题用友NC测试环境无法启动或启动后服务异常。排查资源检查确保虚拟机分配了足够的内存NC通常需要4GB以上和CPU资源。依赖检查检查Java版本NC通常要求特定版本的JDK如1.7或1.8、数据库驱动、中间件版本是否匹配。日志分析查看NC、Tomcat/WebSphere、数据库的日志文件这是定位启动失败原因的最直接途径。错误信息通常会明确指出缺少哪个类、哪个配置文件出错或哪个端口被占用。使用简化环境如果完整版NC安装过于困难可以尝试寻找或构建一个仅包含漏洞组件的简化Web应用进行复现将重心放在漏洞原理本身。复现一个像XVE-2024-37013这样的漏洞远不止是运行一个工具那么简单。它要求你对Web应用的工作原理、数据库交互、HTTP协议有深入的理解并具备系统性的问题排查能力。每一次成功的复现和深度分析都是对自身安全技术栈的一次巩固和提升。希望这份详细的指南能为你打开一扇门不仅仅是学会复现一个漏洞更是理解一类安全问题及其应对之道。