SSRF 简介

  • SSRF(Server-Side Request Forgery,服务端请求伪造),是攻击者让服务端发起构造的指定请求链接造成的漏洞。
  • 由于存在防火墙的防护,导致攻击者无法直接入侵内网;这时攻击者可以以服务器为跳板发起一些网络请求,从而攻击内网的应用及获取内网数据。

SSRF与CSRF的区别

  • CSRF是服务器端没有对用户提交的数据进行随机值校验,且对http请求包内的refer字段校验不严,导致攻击者可以利用用户的cookie信息伪造用户请求发送至服务器;
  • SSRF是服务器对用户提供的可控URL过于信任,没有对攻击者提供的URL进行地址限制和足够的检测,导致攻击者可以以此为跳板攻击内网或者其它服务器。

SSRF 原理

  • SSRF形成的原因大都是由于服务端提供了从其他服务器或应用中获取数据的功能,但没有对目标地址做出有效的过滤与限制造成的。
  • 比如,一个正常的Web应用,本应该从指定URL获取网页文本内容或加载指定地址的图片,而攻击者利用漏洞伪造服务器端发出请求,从而突破了客户端获取不到数据的限制,如内网资源、服务器本地资源等。

SSRF 漏洞利用手段

  • 对外网、服务器所在内网、本地进行端口扫描,获取一些服务的banner信息。
  • 攻击运行在内网或本地的应用程序。
  • 对内网Web应用进行指纹识别,识别企业内部的资产信息。
  • 攻击内外网的Web应用,主要是使用HTTP GET请求就可以实现的攻击(比如struts2、SQli等)。
  • 利用file协议读取本地文件等。
  • 漏洞产生相关函数:
    1
    file_get_contents()、fsockopen()、curl_exec()、fopen()、readfile()

file_get_contents()

  • file_get_content函数从用户指定的url获取内容,然后指定一个文件名进行保存,并展示给用户。file_put_content函数把一个字符串写入文件中。
    1
    2
    3
    4
    <?php
    $url = $_GET['url'];;
    echo file_get_contents($url);
    ?>

fsockopen()

  • fsockopen函数实现对用户指定url数据的获取,该函数使用socket(端口)跟服务器建立tcp连接,传输数据。变量host为主机名,port为端口,errstr表示错误信息将以字符串的信息返回,30为时限
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <?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;
    }
    }
    ?>

curl_exec()

  • curl_exec函数用于执行指定的curl会话
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <?php 
    if (isset($_POST['url'])){
    $link = $_POST['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;
    }
    ?>
  • 注意:
  1. 一般情况下PHP不会开启fopen的gopher wrapper
  2. file_get_contents的gopher协议不能URL编码
  3. file_get_contents关于Gopher的302跳转会出现bug,导致利用失败
  4. curl/libcurl 7.43 上gopher协议存在bug(%00截断) 经测试7.49 可用
  5. curl_exec() 默认不跟踪跳转,
  6. file_get_contents() 支持php://input协议

Pikachu-SSRF实验练习

SSRF(curl)

  • 可以先看看curl的用法,因为我也不是很懂这个curl
  • PHP支持的由Daniel Stenberg创建的libcurl库允许你与各种的服务器使用各种类型的协议进行连接和通讯。
  • libcurl目前支持http、https、ftp、gopher、telnet、dict、file和ldap协议。libcurl同时也支持HTTPS认证、HTTP POST、HTTP PUT、 FTP 上传(这个也能通过PHP的FTP扩展完成)、HTTP基于表单的上传、代理、cookies和用户名+密码的认证。
  • 进入到页面,可以看到一个链接,我们点击它
    image.png
  • 应该会出现“假如生活欺骗了你”的内容,但是我这里文件丢失了,请无视,不影响后续操作
  • 我们可以看到url地址
    image.png
  • 因为curl支持多种协议,我们尝试一下

通过网站访问链接

  • 我们直接把后面的url改成百度的网址,很鬼畜,居然重合了
    image.png

利用file协议查看本地文件

  • 直接把url修改成本地文件的地址,就可以查看文件内容
    image.png

dict协议扫描内网主机开放端口

  • 连接上开放的端口,我这里是链接了MySQL数据库
    image.png

SSRF(file_get_content)

file读取本地文件

  • 输入本地文件地址,可以查看本地文件内容
    image.png

http协议请求内网资源

  • 也可以通过http访问内网的资源
    image.png