-
Notifications
You must be signed in to change notification settings - Fork 42
A Basic SSTI Expr
v1ll4n edited this page Jun 14, 2023
·
3 revisions
cases = [
{"boundary": ["", ""], "note": "no-boundary", "note_zh": "无边界", "usedby": []},
{"boundary": ["{{", "}}"], "note": "basic:{{...}}", "note_zh": "基础模版: {{...}}", "usedby": ["twig", "flask/jinja2", "django"]},
{"boundary": ["${", "}"], "note": "basic:${...}", "note_zh": "基础模版:${...}", "usedby": ["java", ]},
{"boundary": ["{", "}"], "note": "basic:{...}", "note_zh": "基础模版:{...}", "usedby": []},
{"boundary": ["<%=", "%>"], "note": "ruby", "note_zh": "Ruby 模版"},
{"boundary": ["{php}", "{/php}"], "note": "smarty: {php}...{/php}", "usedby": ["smarty"]},
{"boundary": ["{php} echo ", "; {/php}"], "note": "smarty: {php}...{/php}", "usedby": ["smarty"]},
{"boundary": ["$eval('", "')"], "note": "AngularJS: $eval('...')", "usedby": ["Angulary"]},
{"boundary": ["{%", "%}"], "note": "Tornado: {%...%}", "usedby": ["Tornado", "django"]},
]
yakit.AutoInitYakit()
sstiDesc = `服务器端模板注入(Server-Side Template Injection,简称 SSTI)是一种安全漏洞,它发生在服务器端的模板引擎中。模板引擎通常用于将动态数据嵌入到静态 HTML 页面中,以生成最终的网页。当攻击者能够向模板引擎提供恶意输入并成功执行任意代码时,就发生了服务器端模板注入。
SSTI 的风险因素包括:
任意代码执行:攻击者可能利用模板注入来执行任意代码,从而控制服务器或访问敏感数据。
数据泄露:攻击者可能利用模板注入来访问服务器上的敏感数据,例如数据库中的用户凭据或其他重要信息。
拒绝服务:攻击者可能利用模板注入来导致服务器崩溃,导致服务不可用。`
solution = `为了防止服务器端模板注入,可以采取以下措施:
输入验证:对用户输入进行严格的验证,确保只接受预期的数据类型和格式。可以使用白名单方法,仅允许已知安全的输入。
输出编码:在将用户输入插入模板之前,对其进行适当的编码,以防止恶意代码执行。
最小权限原则:确保服务器端应用程序以最小权限运行,以减少潜在的损害。
使用安全的模板引擎:选择已知具有良好安全记录的模板引擎,并确保使用最新版本。
通过采取这些措施,可以大大降低服务器端模板注入的风险。
`
checkCase = (instance, https, reqBytes) => {
prefix, suffix = instance.boundary
yakit.Info("开始测试 SSTI:%v ... %v", prefix, suffix)
var params = fuzz.HTTPRequest(reqBytes, fuzz.https(true))~.GetCommonParams()
for param in params {
checked = 0
failed = false
var lastResponse
var lastPayload
baseResponse, _ = poc.HTTP(reqBytes, poc.https(https))~
for count in 6 {
index = count + 1
if index - 3 >= checked {
failed = true
break
}
try {
exprDetails = fuzz.FuzzCalcExpr()
var result = exprDetails.result
var expr = exprDetails.expr
generateExprCount = 0
for str.Contains(string(baseResponse), expr) && generateExprCount < 100 {
generateExprCount ++
exprDetails = fuzz.FuzzCalcExpr()
result = exprDetails.result
expr = exprDetails.expr
}
payload = prefix + expr + suffix
freq = param.Fuzz(payload)
// freq.Show()
rsp, err = freq.ExecFirst()
if err {
yakit.Info("请求失败: %v", err)
continue
}
if (result in string(rsp.ResponseRaw)) && !str.MatchAnyOfRegexp(string(rsp.ResponseRaw), result + `\d{2}`, `\d{2}` + result) {
yakit.Info("SSTI 表达式执行成功:复核次数: " + string(index))
checked ++
lastResponse = rsp
lastPayload = payload
}
} catch err {
die(err)
}
}
if !failed {
yakit.Info("表达式注入成功检测:参数:%v", str.TrimSpace(param.String()))
url = lastResponse.Url
risk.NewRisk(
lastResponse.Url,
risk.titleVerbose(f"SSTI 表达式注入(参数:${param.Name()}): ${url} "),
risk.title(f"SSTI Expr Injection (Param:${param.Name()}): ${url}"),
risk.request(lastResponse.RequestRaw),
risk.response(lastResponse.ResponseRaw),
risk.payload(lastPayload),
risk.severity("high"),
risk.type("SSTI"),
risk.typeVerbose("模版注入"),
risk.description(sstiDesc),
risk.solution(solution),
risk.details({
"reason": "本漏洞的检测方法是通过数值计算来实现的,我们通过输入一个类似 2012-10-02 的表达式,如果它的结果是 2000,那么我们认为 SSTI Expr 成功,这种计算方法非常简单明了",
"note": "为了保证计算有效,我们会多次计算这个值确保绝大多数计算都是成功的",
"url": url,
})
)
}
}
}
checkReq = (ishttps, req) => {
for instance in cases {
try {
checkCase(instance, ishttps, req)
} catch err {
yakit.Error(err)
}
}
}
mirrorNewWebsitePathParams = (isHttps, url, req, rsp, body) => {
checkReq(ishttps, req)
}
// if YAK_MAIN {
// testurl = [
// "https://127.0.0.1:8787/expr/injection?b={%22a%22:%201}",
// `https://127.0.0.1:8787/expr/injection?a=1`,
// `https://127.0.0.1:8787/expr/injection?c=abc`,
// ]
// for u in testurl {
// https, bytes, _ = poc.ParseUrlToHTTPRequestRaw("GET", u)
// checkReq(https, bytes)
// }
// }