点我

SSRF

image-20250210101110729

一、漏洞概述

  • 定义 :SSRF(Server - Side Request Forgery)即服务器端请求伪造,是一种攻击者通过操纵服务器端的应用程序,使其向攻击者指定的地址发送请求的攻击方式。
  • 背景 :SSRF 漏洞通常发生在服务器端提供了从其他服务器获取数据的功能,但没有对目标地址做过滤与限制的情况下。攻击者可以利用这个漏洞,让服务器向内部网络或外部网络中的任意地址发送请求,从而获取敏感信息或执行攻击操作。

二、漏洞成因

  • 服务器端对用户输入的 URL 过于信任 :服务器端没有对用户输入的 URL 进行严格的过滤和验证,直接使用用户输入的 URL 来发起请求,导致攻击者可以构造恶意的 URL 来控制服务器的请求目标。
  • 缺乏对请求地址的限制 :服务器端没有对请求的地址进行限制,允许服务器向任意地址发送请求,包括内部网络和外部网络中的敏感地址。

三、漏洞危害

  • 内网探测与攻击 :攻击者可以利用 SSRF 漏洞探测服务器所在的内网环境,获取内网中的敏感信息,如服务器的 IP 地址、端口号、服务版本等,进而对内网中的其他服务器或应用进行攻击。
  • 本地文件读取 :攻击者可以通过构造恶意的 URL,利用 SSRF 漏洞读取服务器本地的文件,如配置文件、源代码等,从而获取敏感信息。
  • 拒绝服务攻击(DoS) :攻击者可以利用 SSRF 漏洞向服务器发送大量的请求,消耗服务器的资源,导致服务器无法正常响应合法用户的请求,从而实现拒绝服务攻击。

四、漏洞利用场景

  • 端口扫描与内网探测 :攻击者可以通过 SSRF 漏洞扫描服务器所在的内网或本地端口,获取服务的 banner 信息,从而窥探网络结构。例如,攻击者可以构造一个 URL,让服务器向内网中的某个 IP 地址和端口发送请求,通过分析服务器的响应来判断该端口是否开放以及运行的服务类型。
  • 攻击内网服务 :攻击者可以利用 SSRF 漏洞对内网中的其他服务进行攻击,如对内网中的 Web 应用进行 SQL 注入、命令执行等攻击,获取内网中的敏感数据或控制权。
  • 读取本地文件 :攻击者可以通过构造特定的 URL,利用 SSRF 漏洞读取服务器本地的文件,如使用 file:// 协议读取服务器上的配置文件、源代码等。

在服务器端请求伪造(SSRF)漏洞中,有一些函数如果使用不当,容易导致安全问题。以下是几种常见的危险函数及其详细解释:

五、危险函数

一、PHP中的危险函数

  1. file_get_contents()

函数用途:用于打开一个文件或URL,并读取其内容。它可以读取本地文件(通过file://协议)或者远程URL的内容。

SSRF风险:如果这个函数的参数是由用户输入控制的,并且没有经过严格的验证,攻击者可以构造恶意的URL,让服务器去访问内网资源、本地文件或者其他敏感信息。

php复制

// 危险示例
$url = $_GET['url'];
$content = file_get_contents($url);
echo $content;

在这个示例中,攻击者可以通过提交http://example.com/?url=http://内网IP来让服务器访问内网IP地址的资源,或者通过http://example.com/?url=file:///etc/passwd来读取服务器本地的/etc/passwd文件。

防御建议:对用户输入的URL进行严格的验证,限制其只能访问允许的外部资源,并且避免直接将用户输入作为file_get_contents()的参数。

  1. curl_exec()

函数用途:用于执行一个cURL会话,可以向指定的URL发送HTTP请求。

SSRF风险:如果curl_exec()的URL参数是由用户控制的,攻击者可以利用它来让服务器向任意URL发送请求,包括内网地址和本地文件。

php复制

// 危险示例
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_GET['url']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
curl_close($ch);
echo $output;

攻击者可以构造如http://example.com/?url=http://内网IP的请求,让服务器访问内网资源。

防御建议:对用户输入的URL进行严格的白名单验证,限制请求的目标地址范围,并且在使用cURL时设置合理的超时和其他安全选项。

  1. fsockopen()

函数用途:用于打开一个网络连接或者Unix域套接字连接。它可以连接到指定的主机和端口。

SSRF风险:如果fsockopen()的主机和端口参数是由用户输入控制的,攻击者可以利用它来扫描内网的主机和端口,获取内网信息。

php复制

// 危险示例
$host = $_GET['host'];
$port = $_GET['port'];
$fp = fsockopen($host, $port, $errno, $errstr, 30);
if (!$fp) {
    echo "$errstr ($errno)";
} else {
    fclose($fp);
    echo "连接成功";
}

攻击者可以通过提交http://example.com/?host=内网IP&port=80来扫描内网IP的80端口是否开放。

防御建议:严格限制用户可以输入的主机和端口范围,避免直接使用用户输入作为fsockopen()的参数,并且对连接的目标进行白名单限制。

二、Python中的危险函数

  1. urllib.request.urlopen()

函数用途:用于打开一个网络资源,获取其内容。它可以处理HTTP、HTTPS等协议的请求。

SSRF风险:如果这个函数的URL参数是由用户输入控制的,攻击者可以构造恶意的URL,让服务器去访问内网资源或者其他敏感信息。

Python复制

# 危险示例
import urllib.request
url = input("请输入URL:")
response = urllib.request.urlopen(url)
print(response.read())

攻击者可以输入http://内网IP或者file:///etc/passwd等URL,让服务器访问这些资源。

防御建议:对用户输入的URL进行严格的验证,限制其只能访问允许的外部资源,并且避免直接将用户输入作为urlopen()的参数。

  1. requests.get()

函数用途:用于发送HTTP GET请求,获取指定URL的响应内容。它是Python中非常常用的HTTP请求库。

SSRF风险:如果requests.get()的URL参数是由用户输入控制的,攻击者可以利用它来让服务器向任意URL发送请求,包括内网地址和本地文件。

Python复制

# 危险示例
import requests
url = input("请输入URL:")
response = requests.get(url)
print(response.text)

攻击者可以通过输入恶意的URL来利用这个漏洞。

防御建议:对用户输入的URL进行严格的白名单验证,限制请求的目标地址范围,并且在使用requests库时设置合理的超时和其他安全选项。

三、Java中的危险函数

  1. java.net.URLopenConnection()

函数用途java.net.URL类用于表示一个统一资源定位符,openConnection()方法用于打开到该URL的连接,可以发送和接收数据。

SSRF风险:如果URL对象的地址是由用户输入控制的,攻击者可以构造恶意的URL,让服务器去访问内网资源或者其他敏感信息。

java复制

// 危险示例
String url = request.getParameter("url");
try {
    java.net.URL netUrl = new java.net.URL(url);
    java.net.HttpURLConnection conn = (java.net.HttpURLConnection) netUrl.openConnection();
    InputStream in = conn.getInputStream();
    // 处理输入流
} catch (Exception e) {
    e.printStackTrace();
}

攻击者可以通过提交http://内网IP或者file:///etc/passwd等URL来利用这个漏洞。

防御建议:对用户输入的URL进行严格的验证,限制其只能访问允许的外部资源,并且避免直接将用户输入作为URL对象的参数。

  1. java.net.Socket

函数用途:用于创建一个网络套接字连接,可以连接到指定的主机和端口。

SSRF风险:如果Socket的主机和端口参数是由用户输入控制的,攻击者可以利用它来扫描内网的主机和端口,获取内网信息。

java复制

// 危险示例
String host = request.getParameter("host");
int port = Integer.parseInt(request.getParameter("port"));
try {
    java.net.Socket socket = new java.net.Socket(host, port);
    // 连接成功
    socket.close();
} catch (Exception e) {
    e.printStackTrace();
}

攻击者可以通过提交内网IP和端口来扫描内网。

防御建议:严格限制用户可以输入的主机和端口范围,避免直接使用用户输入作为Socket的参数,并且对连接的目标进行白名单限制。

四、其他语言中的危险函数

  1. JavaScript(Node.js)中的http.get()

函数用途:用于发送HTTP GET请求,获取指定URL的响应内容。

SSRF风险:如果http.get()的URL参数是由用户输入控制的,攻击者可以利用它来让服务器向任意URL发送请求,包括内网地址和本地文件。

JavaScript复制

// 危险示例
const http = require('http');
const url = require('url');

const server = http.createServer((req, res) => {
    const targetUrl = req.query.url;
    http.get(targetUrl, (response) => {
        response.pipe(res);
    }).on("error", (err) => {
        res.end("Error: " + err.message);
    });
});

server.listen(3000);

攻击者可以通过提交http://内网IP或者file:///etc/passwd等URL来利用这个漏洞。

防御建议:对用户输入的URL进行严格的白名单验证,限制请求的目标地址范围,并且在使用http.get()时设置合理的超时和其他安全选项。

  1. Ruby中的Net::HTTP.get()

函数用途:用于发送HTTP GET请求,获取指定URL的响应内容。

SSRF风险:如果Net::HTTP.get()的URL参数是由用户输入控制的,攻击者可以利用它来让服务器向任意URL发送请求,包括内网地址和本地文件。

ruby复制

# 危险示例
require 'net/http'
require 'uri'

url = URI.parse(params[:url])
response = Net::HTTP.get(url)
puts response

攻击者可以通过提交恶意的URL来利用这个漏洞。

防御建议:对用户输入的URL进行严格的验证,限制其只能访问允许的外部资源,并且避免直接将用户输入作为Net::HTTP.get()的参数。

六、漏洞防御措施

  • 严格校验用户输入的 URL :对用户输入的 URL 进行严格的过滤和验证,禁止访问不安全的 URL,如内网 IP 地址、本地文件路径等。
  • 限制服务器的网络访问权限 :通过配置服务器的防火墙、网络策略等,限制服务器能够访问的地址范围,禁止服务器访问内网中的敏感地址。
  • 禁用危险协议 :禁用服务器端不需要的协议,如 file://gopher://dict:// 等,只允许使用安全的协议,如 HTTP 和 HTTPS。
  • 统一错误信息 :避免根据错误信息判断端口状态,防止攻击者通过分析错误信息来获取服务器的内部信息。
  • 使用白名单 :实现一个 URL 白名单,只允许服务器访问预定义的、安全的 URL,从而防止服务器访问恶意地址。
分类: WEB安全

评论

-- 评论已关闭 --

目录