SSRF 攻击简介

SSRF 攻击概述

SSRF(Server-Side Request Forgery,服务器端请求伪造) 是一种由攻击者构造攻击链传给服务器,服务端执行并发起请求造成安全问题的漏洞,一般用来在外网探测或攻击内网服务。

SSRF 形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。比如从指定URL地址获取网页文本内容,加载指定地址的图片,下载等。

攻击者利用 SSRF 可以实现的攻击有:

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

常见的后端实现(PHP)

主要涉及到三个函数:

  • file_get_contents()
  • fsockopen()
  • curl_exec()

file_get_contents 实现

file_get_contents() 将一个文件读入一个字符串,这个文件可以是本地的,也可以是网络上的(即传入的参数是 url 地址)。如果失败,file_get_contents() 将返回 FALSE。

详细见手册:file_get_contents

实现:

<?php
    if (isset($_GET['url'])){
        $content = file_get_contents($_GET['url']);
        $filename = './images/' . rand() . ';img1.jpg';
        $flag = file_put_contents($filename, $content);
        echo $_GET['url'];
        // echo $content;
        if($flag) echo 'yes';
        else echo 'no';
        $img = "<img src=\"" . $filename . "\"/>";
    }
    echo $img;
?>

注意事项: 默认情况下建立的 images 文件夹没有写权限,需要添加写权限才能正常写入:

sudo chmod o+w images

fsockopen 实现

fsockopen 打开一个网络连接或者一个Unix套接字连接,fsockopen() 将返回一个文件句柄,之后可以被其他文件类函数调用(例如:fgets()fgetss()fwrite()fclose() 还有 feof() )。如果调用失败,将返回FALSE。

详细见手册: fsockopen

实现:

<?php 

function GetFile($host,$port,$link) { 
    $fp = fsockopen($host, intval($port), $errno, $errstr, 30); 
    if (!$fp) { 
        echo "$errstr (error number $errno) \n"; 
    } else { 
        $out  = "GET $link HTTP/1.1\r\n"; 
        $out .= "Host: $host\r\n"; 
        $out .= "Connection: Close\r\n\r\n"; 
        $out .= "\r\n"; 
        fwrite($fp, $out); 
        $contents = ''; 
        while (!feof($fp)) { 
            $contents .= fgets($fp, 1024); 
        } 
        fclose($fp); 
        return $contents; 
    } 
}

$host = "www.zzzsdust.com";
$port = 80;
$link = "/index.php";
$contents = GetFile($host, $port, $link); 
echo $contents;

注意事项:$link 是以 / 开头的,否则会得到 400 错误。

curl_exec 实现

curl_exec 函数通常结合 curl_initcurl_setoptcurl_close 使用。

详细见手册: curl_exec

<?php
    if(isset($_GET['url'])) {
        $url = $_GET['url'];
        $curlobj = curl_init();
        curl_setopt($curlobj, CURLOPT_POST, 0);
        curl_setopt($curlobj, CURLOPT_URL, $url);
        curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1); 
        # CURLOPT_RETURNTRANSFER 为 TRUE 时,将curl_exec()获取的信息以字符串返回,而不是直接输出
        # 即:为 1 时无回显
        $result = curl_exec($curlobj);
        curl_close($curlobj);

        # $filename = './images/' . rand() . '.txt';
        # file_put_contents($filename, $result)
        echo $result;
    }

注意事项: 直接执行会返回 500 错误,因为没有安装 php-curl,解决方法(ubuntu):

sudo apt-get install php-curl
sudo systemctl restart apache2.service

SSRF 漏洞寻找

可以从两方面进行寻找:

  • 从 WEB 功能上寻找
  • 从 URL 关键字中寻找

从 WEB 功能上寻找:

  • 分享:通过 URL 分享网页内容,如:http://widget.renren.com/*****?resourceUrl=https://www.sobug.com
  • 转码服务:通过 URL 地址把原地址的网页内容调优使其适合手机屏幕浏览
  • 在线翻译:通过URL地址翻译对应文本的内容
  • 图片加载与下载:通过URL地址加载或下载图片
  • 图片、文章收藏功能,文章收藏就类似于功能一的分享功能中获取URL地址中title以及文本的内容作为显示,目的还是为了更好的用户体验,而图片收藏就类似于功能四、图片加载。
  • 未公开的api实现以及其他调用URL的功能

从 URL 关键字中寻找:

存在 SSRF 漏洞中 URL 地址多包含以下关键字:

share
wap
url
link
src
target
u
3g
display
sourceURL
imageURL
domain

防御

  • 过滤返回信息,验证远程服务器对请求的响应是比较容易的方法。如果web应用是去获取某一种类型的文件。那么在把返回结果展示给用户之前先验证返回的信息是否符合标准。
  • 统一错误信息,避免用户可以根据错误信息来判断远端服务器的端口状态
  • 限制请求的端口为http常用的端口,比如,80,443,8080,8090
  • 黑名单内网ip。避免应用被用来获取获取内网数据,攻击内网
  • 禁用不需要的协议。仅仅允许http和https请求。可以防止类似于file:///,gopher://,ftp:// 等引起的问题
  • 禁用 302 跳转

(

关于 302 跳转的解释:可能你会怀疑访问不是代理机发出的么?怎么会进入目标机的内网?(刚开始我这样想的),后来一想这是 302 重定向啊!!!,虽然代码在代理机上,但代理机会将访问请求发送给目标机,并让目标机进行访问,所以可以访问目标机内网。其实就是对 302 跳转的理解 : )。

)

参考链接: