De1CTF_20190803-web1 writeup

程序分析

程序分为提供哈希值,扫描和读取三大功能。

程序可以从服务器发起请求,访问用户输入的网址或其他信息,然后截取前50字节记录到result.txt。

flag.txt保存在服务器上,但不能从外网访问。此时可以通过ssrf让服务器发起请求,访问flag.txt并记录文本信息,然后使用读取功能读取result.txt,即读取flag。

程序有waf()防火墙:

不允许使用filegopher这两个ssrf读取文件的重要协议。不过实际做题中,并没有用上这两个协议,对此感到惊讶,有点超出预期。

页面分析

/geneSign
提供哈希值的页面。
传入参数:param[GET]
其余参数:action(固定为scan)

/De1ta
扫描和读取的页面
传入参数:param[GET](需要扫描的页面),action[Cookie](scan扫描|read读取|其他),sign[Cookie](哈希值,验证用)

解题过程

首先查看sign生成机制:

首先获取sign和验证sign都是用这个函数。
secert_key:16位随机数,暂时不用管
param:传入的参数,需要扫描的页面
action:scan/read,方法

getSign():可控的只有param,action固定为scan
checkSign():可控的有param,action

然后开始做题:

一看题目貌似很难,首先验证sign,因为获取页面只提供action=scan的sign,要使用read功能则需要构造action=read的sign。
原本要获取到action=read的sign是不可能的,因为/geneSign页面只提供action=scan的sign,要生成自己想要的sign需要爆破secert_key的值,然而这不太现实。

但我们可以通过可控点进行骚操作:

return hashlib.md5(secert_key + param + action).hexdigest()

函数把参数都拼接在一起了,而/De1ta中对action的选取判断并非是==,而是用code in str的形式,即action中有read这个字眼即可进入read功能模块。

重点

思路:
/geneSign页面传入param=url+read,使得生成的sign含有read。在/De1ta页面传入param=url,action=readscan。利用生成sign时并没有对元素分界的疏忽,及对action的判断不严谨使得我们可以使用read功能模块。

获取sign:

利用:

需要注意:
生成时传入的param需要在正常的扫描目录后添加read,这样在生成sign函数时构成的语句为:
str : secert_key+{url+read}(param)+scan(action)
str : secert_key+url+read+scan

而在利用时,传入的param则不需要再带入read了,而action需要拼写为readscan,scan必须放后面,也是为了与生成时相对应,而传入的sign填刚刚获取的sign即可。
在验证时构成的语句:
str : secert_key+{url}(param)+{read+scan}(action)
str : secert_key+url+read+scan

与生成时的语句一样