De1CTF2019SSRF Me

1.png

1
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
def Exec(self):
result = {}
result['code'] = 500
if (self.checkSign()):
if "scan" in self.action:
tmpfile = open("./%s/result.txt" % self.sandbox, 'w')
resp = scan(self.param)
if (resp == "Connection Timeout"):
result['data'] = resp
else:
print(resp)
tmpfile.write(resp)
tmpfile.close()
result['code'] = 200
if "read" in self.action:
f = open("./%s/result.txt" % self.sandbox, 'r')
result['code'] = 200
result['data'] = f.read()
if result['code'] == 500:
result['data'] = "Action Error"
result['code'] = 500
else:
result['msg'] = "Sign Error"
return result

def checkSign(self):
if (getSign(self.action, self.param) == self.sign):
return True
else:
return False

2.png

代码量不是特别大

这里首先可以看到三段路由:/ 和 /geneSign 以及 /De1ta

简单跟进一下 / 路由 主要是给我们显示源代码

/geneSign 主要是返回 (secert_key + param + action ) 拼接后 md5加密的值

然后/De1ta 路由的逻辑 就是获取一系列数据,比如cookie 中 sign和 action字段的值等。然后调用waf函数检查一下参数param的值,然后调用Exec函数

然后跟进 Exec函数 ,逻辑就是 先调用那个 checkSign函数,跟进一下checkSign函数,发现这个checkSign函数就是判断sign字段的值是否等于那个md5(secert_key + param + action ) 再判断 cookie 的 sign字段的值里面 是否含有scan,如果有的话,就调用scan()函数,然偶跟进scan()函数,scan()函数这里就是返回 传过来的url的内容。然后把它写到那个result.txt文件里面。最后在判断read在不在action里面 。如果在 ,就读那个result.txt文件,并返回结果。

流程搞清楚了之后,就很容易了。

我们的目的是就是读flag.txt的内容,这里可以利用 scan函数来读。所以我们控制参数param=flag.txt。最后的问题就是解决 sign = md5(secert_key + param + action ) 的问题

总共有三种,我先记录一下最简单的第二种,利用python字符串拼接的特性。还有两种以后消化一下,那个哈希长度攻击暂时先没看。

一开始我们访问:

3.png

这个得到的是 md5(secert_key+flag.txt+scan)的值,也就是 md5(“xxxflag.txtscan”)

如果我们访问:

4.png

得到的就是 md5(“xxxflag.txtreadscan”)的值,这样我们控制sign和这个相等就行了。

然后最后我们访问:

5.png

就可以getflag了。

参考链接: https://xz.aliyun.com/t/5927