上周小黑在实战项目中遇到并学习了ssrf漏洞,在实战环境和测试环境中遇到不少的坑,有的问题花费了几天才找到原因,在这里总结一下。
利用ssrf漏洞时,遇到了使用file协议读不出文件的问题,这里总结一下大概有几点原因:
1、权限不够:当前用户对此文件没有可读权限
2、路径输错了:linux系统中,file之后加路径是三个斜线,不能少:比如file:///etc/passwd(其实就是file://和/etc/passwd的组合)
3、存在open_basedir:当open_basedir配置有值时,curl_exec不能使用file协议,并不是受open_basedir的值限制某些文件读不了,而是整个file协议都不能用。这是写在php的curl_exec源码里的,目前没找到绕过的方式。
4、php源码不显示:读取php源码,即使读成功了也不会在浏览器里回显(类似html的注释一样),要在返回包里或者view-source中去看。
5、不回显的ssrf:代码没写echo,返回值赋到变量里,读成功了你也看不到。
自己在虚拟机搭的测试环境有一个很奇怪的现象,http/s和file协议都能正常使用,但是不能指定端口及使用gopher和dict协议,否则就只能发出dns请求,却不能建立tcp的连接(dnslog可以收到请求,nc收不到)。
后面查阅了很多资料,并没有找到明确的答案,只有一个疑似可能的原因:php在编译时没有使用-with-curlwrappers参数会导致这个问题。不过这个参数貌似在高版本被去掉了,所以应该只影响低版本php吧。
在实战中如果遇到这个问题,总不能登目标机器把php重新编译一下吧……(动作太大了,而且都能登机器了还要ssrf有什么用呢),目前没找到什么办法绕过。
测试一下各协议对特殊符号的支持,中文符号不测试,测试的所有符号如下:
`~!@#$%^&*()_-+=/|'";:<>,.?{}[]
【gopher协议】
正常符号:直接传,一次二次url编码都可以
% 直接传可以,但后面接16进制字符就会转义,一次url编码后还是不能接16进制,二次url编码可以
# 会截断,一次url编码绕不过,二次url编码后可以
& 会截断,一次url编码可以,二次url编码也可以
+ 会变成空格,一次二次url编码后都可以
【dict协议】
正常符号:直接传,一次url编码可以,二次url编码不行(不支持二次解码)
以下均不支持二次url解码
% 直接传可以,后面接16进制不行会转义,一次url编码后可以
# 会截断,一次url编码绕不过
& 会截断,一次url编码可以
? 会截断,一次url编码绕不过
+ 会变成空格,一次url编码可以
: 会变成空格,一次url编码绕不过
【http/s协议】
正常符号:直接传,一次url编码可以,二次url编码不行(不支持二次解码)
% 直接传可以,后面接16进制不行会转义,一次url编码后可以
【总结】
%#&+符号容易出问题
dict协议额外不支持?:两个符号,url编码无法绕过
一次url编码可以绕过%&+三种符号,不能绕过#
gopher协议的%需要编码两次绕过,只一次不行
gopher万能协议,支持二次url解码,没有绕不过的特殊符号。
后面如果还继续写ssrf系列的话,会讲一讲具体的利用ssrf打内网应用的案例。不过也有可能写点别的东西,欢迎大家继续关注啦~
http://johnis.online/old/2017/10/10/Curl类库解析url安全简读/
https://geeeez.github.io/2020/02/11/SSRF的那些事/
END.
喵,点个赞再走吧~
本文始发于微信公众号(小黑的安全笔记):ssrf常用协议和特殊符号使用的坑
评论