程序分析
程序分为提供哈希值,扫描和读取三大功能。
程序可以从服务器发起请求,访问用户输入的网址或其他信息,然后截取前50字节记录到result.txt。
flag.txt保存在服务器上,但不能从外网访问。此时可以通过ssrf让服务器发起请求,访问flag.txt并记录文本信息,然后使用读取功能读取result.txt,即读取flag。
程序有waf()
防火墙:
不允许使用file
和gopher
这两个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
与生成时的语句一样