前言
生活破破烂烂,牛牛缝缝补补。师傅们辛苦工作一周,终于迎来周五啦!
上周说到导致XSS的原因Yakit靶场通关教程|XSS多场景(二),本周放送的靶场新类型有相似之处。从外网通过SSRF攻击访问内网,接着对内网的应用展开攻击,像这类攻击者利用应用程序中的漏洞,使得服务器端发起未经授权的请求,访问可能不能被访问的资源或系统,就是SSRF 服务器端请求伪造。
本周牛牛将针对SSRF典型场景呈上教学,废话少说!接下来就请师傅和牛牛更换武器装备,一起开启新的靶场关卡!
SSRF 形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能,且没有对目标地址做过滤与限制,比如从指定URL地址获取网页文本内容,文档等。概括来说一句话:利用存在缺陷的web应用作为代理攻击远程和本地的服务器。其因为在攻击过程中穿透了网络边界,对内网的应用危害比较大,师傅们开发过程中,要尽量避免产生SSRF漏洞。
案例分享及教学
SSRF JSON Body SSRF
示例代码:
{
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)
END
更新日志
Yaklang 1.2.8-sp4
1. 修复了 file:line 的分行非预期行为
2. 修复了 Yaml PoC 的RootURL非预期行为
3. 修复了 HTTP 请求走私插件的一些误报情况
4. 新的批量扫描接口(仅gRPC)
5. Web Fuzzer Fuzztag 支持更精细的渲染模式
Yakit 1.2.7-sp5
1. 修复Webfuzzer批量发包导出数据显示多个弹框的问题
2. history增加显示网站树,并可通过网站树筛选数据
3. 修复Webfuzzer导出数据字段缺失的问题
4. 开启替换后,劫持增加提示
5. 修复Fuzz序列拖动组数据会消失的问题
6. 修复Fuzz序列批量发包数据显示不对的问题
7. 可通过Yakit启动节点
YAK官方资源
Yak 语言官方教程:
https://yaklang.com/docs/intro/
Yakit 视频教程:
https://space.bilibili.com/437503777
Github下载地址:
https://github.com/yaklang/yakit
Yakit官网下载地址:
https://yaklang.com/
Yakit安装文档:
https://yaklang.com/products/download_and_install
Yakit使用文档:
https://yaklang.com/products/intro/
常见问题速查:
https://yaklang.com/products/FAQ