靶场实战:SSRF 参数多场景测试(一)
前言
本文继续靶场通关系列。
上周说到导致XSS的原因Yakit靶场通关教程|XSS多场景(二) ,本周放送的靶场新类型有相似之处。从外网通过SSRF攻击访问内网,接着对内网的应用展开攻击,像这类攻击者利用应用程序中的漏洞,使得服务器端发起未经授权的请求,访问可能不能被访问的资源或系统,就是SSRF 服务器端请求伪造。
本文将针对 SSRF 的典型场景进行讲解。
SSRF 形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能,且没有对目标地址做过滤与限制,比如从指定URL地址获取网页文本内容,文档等。概括来说一句话:利用存在缺陷的web应用作为代理攻击远程和本地的服务器。其因为在攻击过程中穿透了网络边界,对内网的应用危害比较大,开发过程中应尽量避免产生 SSRF 漏洞。
服务器端请求伪造(Server-Side Request Forgery, SSRF) 是一种安全漏洞,攻击者可以在受害服务器上执行未经授权的请求,可能导致数据泄露、服务端攻击等问题。
SSRF漏洞允许攻击者发送恶意请求,以服务器的身份向内部网络或外部资源发起请求。攻击者可以通过此漏洞访问内部服务、获取敏感数据,甚至攻击内部系统。
案例分享及教学SSRF JSON Body SSRF
在该漏洞案例中,攻击者构造了一个JSON请求,其中包含一个名为 "ref" 的字段,其值为恶意的URL(如 https://www.atacker.com )。当服务器解析该JSON请求时,会发起一个GET请求到指定的URL。攻击者可以通过设置恶意URL来访问受限制的内部资源、绕过防火墙、探测内网服务等。
示例代码:
{
DefaultQuery: "json={\"abc\": 123, \"ref\": \"http://www.baidu.com\"}",
Path: "/json-in-get",
Title: "SSRF JSON Body SSRF",
Handler: func(writer http.ResponseWriter, request *http.Request) {
raw := request.URL.Query().Get("json")
if raw == "" {
writer.Write([]byte(`No data available!`))
return
}
var m = make(map[string]interface{})
err := json.Unmarshal([]byte(raw), &m)
if err != nil {
writer.Write([]byte(`JSON Syntax Error: ` + err.Error()))
return
}
ref, ok := m["ref"]
if !ok {
writer.Write([]byte(`No "ref" in JSON found!`))
return
}
var u = fmt.Sprint(ref)
c := utils.NewDefaultHTTPClient()
c.Timeout = 5 * time.Second
rsp, err := c.Get(u)
if err != nil {
writer.Write([]byte(err.Error()))
return
}
rawResponse, err := utils.HttpDumpWithBody(rsp, true)
if err != nil {
writer.Write([]byte(err.Error()))
return
}
writer.Write(rawResponse)
},
RiskDetected: true,
}
攻击示例:
1、构造恶意JSON请求:
{"abc": 123, "ref": "http://127.0.0.1:8787/ssrf/flag"}
2、将该JSON请求作为请求体,发送到目标服务器的 /json-in-get 路径。
3、服务器解析JSON请求体,并尝试访问 "ref" 字段中指定的恶意URL(http://127.0.0.1:8787/ssrf/flag )
4、如果服务器没有适当的防御措施,可能会成功发起请求,攻击者可以获取响应,从而获得攻击目标内部的信息。
防御措施:
- 仔细验证和过滤请求体中的数据,确保只允许访问受信任的URL。
- 在服务器端进行白名单验证,只允许访问特定的URL。
- 对于传入的URL参数,进行严格的验证和限制,避免访问内部资源。
- 将不受信任的输入数据进行编码,避免恶意构造的URL。
- 针对内网访问,可以使用防火墙或网络隔离等措施限制出站访问。
靶场演示:视频SSRF GET 中 URL 参数
以下是一个简化的示例代码,用于说明GET请求中的URL参数SSRF漏洞。该示例代码允许用户提供一个URL作为查询参数,然后发起GET请求并返回响应。
示例代码:
{
DefaultQuery: "url=http://www.baidu.com/",
Path: "/in-get",
Title: "SSRF GET 中 URL 参数",
Handler: func(writer http.ResponseWriter, request *http.Request) {
ref := request.URL.Query().Get("url")
var u = fmt.Sprint(ref)
c := utils.NewDefaultHTTPClient()
c.Timeout = 5 * time.Second
rsp, err := c.Get(u)
if err != nil {
writer.Write([]byte(err.Error()))
return
}
rawResponse, err := utils.HttpDumpWithBody(rsp, true)
if err != nil {
writer.Write([]byte(err.Error()))
return
}
writer.Write(rawResponse)
},
RiskDetected: true,
}
攻击示例:
如果目标服务器存在SSRF漏洞,它将会发起对http://127.0.0.1:8787/ssrf/flag的GET请求。攻击者可以通过这种方式获取敏感信息、绕过防火墙,甚至攻击内部资源。
http://127.0.0.1:8787/ssrf/in-get?url=http://127.0.0.1:8787/ssrf/flag
防御措施:
要防范这种类型的漏洞,开发者需要对输入的URL参数进行严格的验证和过滤,限制访问内部网络资源。同时,对于发起的网络请求,需要限制请求的目标范围,以及对请求的目标进行白名单控制,避免访问恶意站点。
靶场演示:视频SSRF POST 中 URL 参数
在这个示例中,我们将介绍一个SSRF漏洞案例,涉及将URL参数嵌入POST请求中,导致攻击者可以发起未经授权的请求。
示例代码:
用户可以通过POST请求提交一个URL,然后服务器将该URL作为目标发起HTTP请求,而没有充分的验证。
在提交表单时,攻击者可以将恶意URL作为参数,从而导致服务器发起未经授权的请求,从而触发SSRF漏洞。
{
DefaultQuery: "",
Path: "/in-post",
Title: "SSRF POST 中 URL 参数",
Handler: func(writer http.ResponseWriter, request *http.Request) {
if request.Method == "GET" {
writer.Header().Set("Content-Type", "text/html; charset=utf8")
writer.Write([]byte(`<form action="/ssrf/in-post" method="post">
<!-- ... 省略其他标签 ... -->
</form>`))
return
}
raw, err := ioutil.ReadAll(request.Body)
if err != nil {
writer.Write([]byte(err.Error()))
return
}
values, err := url.ParseQuery(string(raw))
if err != nil {
writer.Write([]byte(err.Error()))
return
}
var u = fmt.Sprint(values.Get("url"))
c := utils.NewDefaultHTTPClient()
c.Timeout = 10 * time.Second
rsp, err := c.Get(u)
if err != nil {
writer.Write([]byte(err.Error()))
return
}
rawResponse, err := utils.HttpDumpWithBody(rsp, true)
if err != nil {
writer.Write([]byte(err.Error()))
return
}
writer.Write(rawResponse)
},
RiskDetected: true,
}
攻击示例:
攻击者在"URL"字段中输入恶意URL,例如:http://127.0.0.1:8787/ssrf``/flag
服务端接收到POST请求后,提取"URL"参数,并将其作为目标发起HTTP请求
防御措施:
- 白名单验证:限制允许请求的目标URL,只允许特定的域名、IP地址或URL路径。这将减少攻击者可以发起的恶意请求的范围。
- 使用URL解析库:在解析用户输入的URL时,使用专门的URL解析库来确保正确解析和规范化URL。这可以帮助识别和过滤恶意的URL结构。
- 禁用不必要的协议:限制允许的协议,例如只允许http和https,不允许file、data等危险协议。
靶场演示:视频SSRF POST 中 URL 参数 (DNS Rebinding)
DNS Rebinding攻击是一种通过在恶意网站和受害者之间建立一个恶意的DNS记录来绕过同源策略的攻击。攻击者可以利用这种漏洞来访问本地网络、绕过防火墙访问内部服务、窃取敏感信息等。
示例代码:
以下是一个简单的示例代码,演示了一个在POST请求中存在SSRF漏洞的情况,攻击者可以利用这个漏洞进行DNS Rebinding攻击。
{
DefaultQuery: "",
Path: "/rebinding/in-post",
Title: "SSRF POST 中 URL 参数 (DNS Rebinding)",
Handler: func(writer http.ResponseWriter, request *http.Request) {
if request.Method == "GET" {
// ...省略表单HTML代码...
return
}
raw, err := ioutil.ReadAll(request.Body)
if err != nil {
writer.Write([]byte(err.Error()))
return
}
values, err := url.ParseQuery(string(raw))
if err != nil {
writer.Write([]byte(err.Error()))
return
}
var u = fmt.Sprint(values.Get("url"))
if u == "" || !check(u) {
writer.Write([]byte("check url failed"))
writer.WriteHeader(http.StatusInternalServerError)
return
}
// 发起HTTP请求到恶意的URL
c := utils.NewDefaultHTTPClient()
timeoutSec, err := strconv.Atoi(values.Get("timeout"))
if err != nil {
writer.Write([]byte("Invalid timeout value"))
return
}
c.Timeout = time.Duration(timeoutSec) * time.Second
rsp, err := c.Get(u)
if err != nil {
writer.Write([]byte(err.Error()))
writer.WriteHeader(http.StatusInternalServerError)
return
}
// 返回HTTP响应
rawResponse, err := utils.HttpDumpWithBody(rsp, true)
if err != nil {
writer.Write([]byte(err.Error()))
return
}
writer.Write(rawResponse)
},
RiskDetected: true,
}
攻击示例:
1、修改ceye.io的DNS Rebinding,一个是vps地址,另一个是题目的docker.ip(110.110.2.1)
2、vps建立index.php内容为http://127.0.0.1:8787/ssrf/flag"); ?>
3、启用PHP 内置的 Web 服务器监听除80和8080的任意端口php -S 0.0.0.0:7777
4、url填写为http://r.xxxx.ceye.io:7777 ,爆破数据包至出现flag
参考地址:https://xz.aliyun.com/t/8707
防御措施:
- 白名单验证:仅允许请求特定的受信任域名或IP地址。
- 限制超时时间:限制服务器发起请求的超时时间,减少攻击窗口。
- 检查URL格式:验证URL参数是否合法,避免构造恶意的URL。
- 安全配置:配置服务器和网络设备以限制出站连接,防止与恶意域名建立连接。
- 使用随机Token:为每个请求生成随机的token,并在响应中验证该token,防止请求被滥用。
靶场演示:视频完全开放重定向
完全开放重定向漏洞是一种常见的安全漏洞,发生在应用程序中对外部用户提供的重定向功能上。攻击者可以通过构造恶意的重定向链接,将用户导向恶意网站或恶意内容,从而进行钓鱼攻击、会话劫持等恶意行为。这种漏洞通常发生在没有对用户提供的重定向目标进行充分验证的情况下。
示例代码:
以下是一个示例漏洞代码,模拟了一个完全开放的重定向漏洞:
{
DefaultQuery: "destUrl=/redirect/main",
Path: "/redirect/basic",
Title: "完全开放重定向",
Handler: func(writer http.ResponseWriter, request *http.Request) {
var u = LoadFromGetParams(request, "destUrl")
if strings.Contains(u, `redirect/basic`) {
DefaultRender("<p>forbidden to " + strconv.Quote(u) + "</p>", writer, request)
return
}
writer.Header().Set("Location", u)
writer.WriteHeader(302)
},
RiskDetected: true,
}
攻击示例:
攻击者可以构造恶意链接,利用这个完全开放的重定向漏洞,将用户重定向到恶意网站:
http://127.0.0.1:8787/ssrf/redirect/basic?destUrl=http://127.0.0.1:8787/ssrf/flag
防御措施:
- 验证目标URL:在进行重定向之前,始终验证目标URL是否合法和安全。只允许重定向到受信任的域名或URL。
- 白名单验证:维护一个白名单,只允许重定向到事先定义的合法URL列表。
- 避免用户输入:尽量避免使用用户提供的输入来构造重定向URL。如果必须使用用户输入,对输入进行严格的过滤和验证。
- 参数编码:在构造重定向URL时,对参数进行编码,以防止攻击者在参数中插入恶意内容。
- 不使用用户提供的URL:如果可能的话,避免直接使用用户提供的URL进行重定向,而是使用内部的标识符,然后在后端进行转换。
靶场演示:视频完全开放重定向(无限重定向)
完全开放的重定向漏洞是一种安全漏洞,它允许攻击者通过构造恶意的重定向链接,将用户重定向到任意的URL。在这个特定的案例中,重定向是无限的,会导致服务器不断地将用户重定向到同一个URL,形成一个无限重定向循环,最终可能会导致服务不可用或资源耗尽。
示例代码:
{
DefaultQuery: "destUrl=/redirect/main",
Path: "/redirect/redirect-hell",
Title: "完全开放重定向(无限重定向)",
Handler: func(writer http.ResponseWriter, request *http.Request) {
var u = LoadFromGetParams(request, "destUrl")
writer.Header().Set("Location", u)
writer.WriteHeader(302)
},
RiskDetected: true,
}
攻击示例:
攻击者可以构造一个恶意的URL,将用户重定向到同一个无限循环的重定向页面:
http://127.0.0.1:8787/ssrf/redirect/redirect-hell?destUrl=http://127.0.0.1:8787/ssrf/flag
防御措施:
- 白名单验证:在处理重定向请求时,验证目标URL是否属于合法的白名单范围内。不要允许用户传递任意的URL参数。
- 限制重定向次数:为重定向设置一个合理的最大次数限制,超过该次数则停止重定向并返回错误。
- 避免完全开放重定向:避免使用完全开放的重定向,将重定向链接限制为特定的目标,或者使用相对路径进行重定向。
靶场演示:视频小结
通过本文对 Yakit 靶场中 SSRF 漏洞类型的学习,读者应该对 SSRF 有了一定了解。利用它可以探测内网信息、攻击内网或本地其他服务、穿透防火墙等;当然互联网并非法外之地,使用时需遵守法律法规**。**
SSRF攻击通常涉及利用服务端应用程序的漏洞,使攻击者能够控制和发送请求到服务端可访问的资源。除了SSRF的典型情况,有时候还可以通过后端HTTP请求支持重定向的API,构建一个满足筛选器并导致将请求重定向到所需的后端目标的URL。这次的学习中先给大家呈上了完全开放重定向漏洞的案例学习,下一篇将重点围绕SSRF 重定向,深入探讨 SSRF 参数的多种情况测试。
Loading...完全开放重定向(JS location.href)完全开放重定向(JS location.replace)完全开放重定向(JS location.assign)完全开放重定向(meta延迟跳转)完全开放重定向(meta)完全开放重定向(只重定向path)
本文首发于 Yak Project 公众号,阅读原文。
