[De1CTF 2019]SSRF Me
以下是审计过程中的一些笔记
1 | #! /usr/bin/env python |
总结
审计从路由开始,然后在慢慢延申出去
这里有三个路由:
- /geneSign
- /De1ta
- /
- 从/De1ta开始看起,首先是创建了一个Task的类,action、sign的值是由cookie得到,而param的值就是直接通过GET方法传递param参数的值得到,ip就是你的ip地址,接着param参数会经过waf,如果过了waf,则执行这个类的Exec。
顺着这个思路,我们追溯到waf这个方法上,通过审计我们知道要绕过waf,param的值不能以 gopher和file开头
接下去执行Task里的Exec方法,通过审计我们发现如果checkSign(self) 为真 ,则可以传递/De1ta页面的param参数进入到scan方法,并的目录下创建一个result.txt ,然后通过scan()函数把参数param的值写到result.txt中,由于param是可控的,所以很容易想到这里把flag.txt传给param。
审计checkSign(self) 函数,发现如果getSign(cookie传入的action, get传入的param)和cookie传入的sign相等则返回True ,否则返回False
审计getSign(),我们发现不知道secert_key的值,但是路由/geneSign有一个return getSign(scan, param),这里我们另/geneSign页面的参数param的值为
flag.txtread
(这里为什么后面会讲到),通过getSign得到的sign值即为md5(secert_key + ‘flag.txtread’ + ‘scan’)回到Task类的Exec方法
if "read" in self.action:
如果read在action里面,则我们可以读取读取result.txt的内容赋值给result,这里result.txt的值实际上是我们传入的param的值在这里就可以解释为什么/geneSign页面我们传入的param的值要为flag.txtread了,因为结合Exec方法,我们要实现写入文件和读出的功能,就必须另//De1ta页面的action为readsacn或scanread,此时的getSign(),返回的值就是hashlib.md5(secert_key + flag.txt + readscan).hexdigest(),而此时只有另/geneSign页面的param参数为flag.txtread才能使
getSign(self.action, self.param) == getSign(flag.txt+readscan) ,
即md5(secret_key+flag.txtread+scan) == md5(secret_key+flag.txt+readscan)
所以这里总的做法就是在/geneSign页面get ?param=flag.txtread,获得mds值,而这个值其实是等于/De1ta页面的sign值的
所以第二步就是在/De1ta页面,get ?param=flag.txt ,cookie action=readscan ,sign=我们在/geneSign页面得到的md5值,这样就可以得到flag了