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

与生成时的语句一样,即生成的sign也一样,验证通过,成功执行,获得flag。

FIX建议

对于题目所展示的漏洞,如果没有足够的细心恐怕很难发掘,即陷入“安全”的错觉。

修复方法:
1,在生成sign的语句中添加元素间隔填充,使得不能通过param带入多余元素生成任意sign:

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

2,对于action的选择判断:
可能题目需要一次执行多种方法,但如果不需要一次执行多种方法,建议使用双等号判断。

发表评论

电子邮件地址不会被公开。 必填项已用*标注