- The Guide to Finding and Reporting Web Vulnerabilities
- About the Author
- About the Tech Reviewer
- Foreword
- Introduction
- Who This Book Is For
- What Is In This Book
- Happy Hacking!
- 1 Picking a Bug Bounty Program
- 2 Sustaining Your Success
- 3 How the Internet Works
- 4 Environmental Setup and Traffic Interception
- 5 Web Hacking Reconnaissance
- 6 Cross-Site Scripting
- 7 Open Redirects
- 8 Clickjacking
- 9 Cross-Site Request Forgery
- 10 Insecure Direct Object References
- 11 SQL Injection
- 12 Race Conditions
- 13 Server-Side Request Forgery
- 14 Insecure Deserialization
- 15 XML External Entity
- 16 Template Injection
- 17 Application Logic Errors and Broken Access Control
- 18 Remote Code Execution
- 19 Same-Origin Policy Vulnerabilities
- 20 Single-Sign-On Security Issues
- 21 Information Disclosure
- 22 Conducting Code Reviews
- 23 Hacking Android Apps
- 24 API Hacking
- 25 Automatic Vulnerability Discovery Using Fuzzers
Bypassing SSRF Protection
What if you submit an SSRF payload, but the server returns this response?
如果你提交了一个 SSRF 攻击负载,但服务器返回了这个响应,会怎样?
Error. Requests to this address are not allowed. Please try again.
This SSRF was blocked by a protection mechanism, possibly a URL allowlist or blocklist. But all is not lost! The site may have protection mechanisms implemented, but this doesn’t mean that the protection is complete. Here are a few more things you can try to bypass a site’s protection.
该 SSRF 被一个保护机制阻止了,可能是一个 URL 允许或禁止列表。但还没有结束!该网站可能已经实施了保护机制,但这并不意味着保护是完全的。下面是一些您可以尝试绕过网站保护的方法。
Bypass Allowlists
Allowlists are generally the hardest to bypass, because they are, by default, stricter than blocklists. But getting around them is still possible if you can find an open redirect vulnerability within the allowlisted domains. (Visit Chapter 7 for more information about these vulnerabilities.) If you find one, you can request an allowlisted URL that redirects to an internal URL. For example, even if the site allows only profile pictures uploaded from one of its subdomains, you can induce an SSRF through an open redirect.
允许清单通常是最难避开的,因为它们默认比阻止清单更严格。但是,如果能在允许列出的域中找到打开重定向漏洞,仍然可能会绕过它们。(有关这些漏洞的更多信息,请访问第 7 章。)如果您找到一个漏洞,您可以请求允许列出的 URL,该 URL 重定向到内部 URL。例如,即使该站点仅允许从其子域上传个人资料图片,您仍可通过打开重定向实现服务器端请求伪造(SSRF)。
In the following request, we utilize an open redirect on pics.example.com to redirect the request to 127.0.0.1, the IP address for the localhost. This way, even though the url
parameter passes the allowlist, it still redirects to a restricted internal address:
在以下请求中,我们利用 pics.example.com 上的开放式重定向,将请求重定向到本地主机的 IP 地址 127.0.0.1。这样,即使 URL 参数通过允许列表,它仍将重定向到受限制的内部地址。
POST /upload_profile_from_url
Host: public.example.com
(POST request body)
user_id=1234&url=https://pics.example.com/123?redirect=127.0.0.1
The server could also have implemented its allowlist via poorly designed regular expressions (regexes). Regexes are often used to construct more flexible allowlists. For example, instead of checking whether a URL string is equal to "example.com"
, a site can check regex expressions like .*example.com.*
to match the subdomains and filepaths of example.com as well. In those cases, you could bypass the regex by placing the allowlisted domain in the request URL. For example, this request will redirect to 127.0.0.1, since pics.example.com is seen as the username portion of the URL:
服务器也可能通过设计不佳的正则表达式(regexes)来实现其允许列表。正则表达式通常用于构建更灵活的允许列表。例如,一个网站可以通过检查 .*example.com.*这样的正则表达式来匹配 example.com 的子域和文件路径,而不是检查 URL 字符串是否等于“example.com”。在这种情况下,您可以通过在请求 URL 中放置允许列表的域来绕过正则表达式。例如,此请求将重定向到 127.0.0.1,因为 pics.example.com 被视为 URL 的用户名部分。
POST /upload_profile_from_url
Host: public.example.com
(POST request body)
user_id=1234&url=https://pics.example.com@127.0.0.1
The following request also redirects to 127.0.0.1, since pics.example.com is seen as the directory portion of the URL:
因为 pics.example.com 被看作 URL 的目录部分,所以以下请求也会重定向到 127.0.0.1:
POST /upload_profile_from_url
Host: public.example.com
(POST request body)
user_id=1234&url=https://127.0.0.1/pics.example.com
You can test whether a site is using an overly flexible regex allowlist by trying URLs like these and seeing if the filter allows it. Note that a regex-based allowlist can be secure if the regex is well constructed. And these URLs won’t always succeed!
如果尝试这些 URL 并且过滤器允许,请验证该站点是否使用过度灵活的正则表达式白名单。请注意,如果正则表达式良好构造,则基于正则表达式的白名单可以安全使用。但这些 URL 并非总是能够成功!
Bypass Blocklists
Since applications often need to fetch resources from a variety of internet sources, most SSRF protection mechanisms come in the form of a blocklist. If you’re faced with a blocklist, there are many ways of tricking the server.
由于应用程序经常需要从各种互联网来源获取资源,大多数 SSRF 保护机制以屏蔽列表的形式出现。如果您面临屏蔽列表,有许多欺骗服务器的方法。
Fooling It with Redirects
First, you can make the server request a URL that you control and that redirects to the blocklisted address. For example, you can ask the target server to send a request to your server:
首先,您可以让服务器请求您控制并重定向到已加入阻止列表的地址的 URL。例如,您可以要求目标服务器向您的服务器发送请求:
https://public.example.com/proxy?url=https://attacker.com/ssrf
Then, on your server at https://attacker.com/ssrf , you can host a file with the following content:
那么,在您的服务器上的 https://attacker.com/ssrf,您可以托管一个具有以下内容的文件:
<?php header("location: http://127.0.0.1"); ?>
This is a piece of PHP code that redirects the request by setting the document’s location to 127.0.0.1. When you make the target server request https://attacker.com/ssrf, the target server is redirected to http://127.0.0.1 , a restricted internal address. This attack will bypass blocklists because the URL submitted to the application does not itself contain any blocklisted addresses.
这是一段 PHP 代码,通过将文档位置设置为 127.0.0.1 来重定向请求。当您发起指向目标服务器的请求 https://attacker.com/ssrf 时,目标服务器将被重定向到 http://127.0.0.1,这是一种受限的内部地址。这种攻击将绕过阻止列表,因为提交给应用程序的 URL 本身不包含任何被阻止的地址。
Using IPv6 Addresses
I mentioned in Chapter 3 that IPv6 addresses are a newer alternative to the more commonly used IPv4 addresses. The Internet Engineering Task Force (IETF) created IPv6 addresses as the world began running out of available IPv4 addresses and needed a format that provided a larger number of possible addresses. IPv6 addresses are 128-bit values represented in hexadecimal notation, and they look like this: 64:ff9b::255.255.255.255.
我在第三章中提到,IPv6 地址是更常用的 IPv4 地址的一种新型替代品。当世界开始用尽可用的 IPv4 地址并需要一个提供更多可能地址的格式时,互联网工程任务组(IETF) 创建了 IPv6 地址。IPv6 地址是用十六进制表示的 128 位值,长这个样子:64:ff9b::255.255.255.255。
Sometimes the SSRF protection mechanisms a site has implemented for IPv4 might not have been implemented for IPv6. That means you can try to submit IPv6 addresses that point to the local network. For example, the IPv6 address ::1 points to the localhost, and fc00:: is the first address on the private network.
有时,网站为 IPv4 实施的 SSRF 保护机制可能并未针对 IPv6 实施。这意味着您可以尝试提交指向本地网络的 IPv6 地址。例如,IPv6 地址::1 指向本地主机,fc00::是私有网络上的第一个地址。
For more information about how IPv6 works, and about other reserved IPv6 addresses, visit Wikipedia: https://en.wikipedia.org/wiki/IPv6_address .
获取有关 IPv6 如何工作以及其他保留 IPv6 地址的更多信息,请访问维基百科:https://en.wikipedia.org/wiki/IPv6_address。
Tricking the Server with DNS
You can also try confusing the server with DNS records, which computers use to translate hostnames into IP addresses. DNS records come in various types, but the ones you’ll hear about most often are A and AAAA records. A records point a hostname to an IPv4 address, whereas AAAA records translate hostnames to an IPv6 address.
你也可以尝试使用 DNS 记录混淆服务器,计算机将使用它来将主机名转换为 IP 地址。DNS 记录有多种类型,但你最常听到的是 A 记录和 AAAA 记录。A 记录将主机名指向 IPv4 地址,而 AAAA 记录将主机名转换为 IPv6 地址。
Modify the A/AAAA record of a domain you control and make it point to the internal addresses on the victim’s network. You can check the current A/AAAA records of your domain by running these commands:
修改你控制的域名的 A/AAAA 记录并将其指向受害者网络上的内部地址。您可以通过运行以下命令来检查您域的当前 A/AAAA 记录:
nslookup DOMAIN
nslookup DOMAIN -type=AAAA
You can usually configure the DNS records of your domain name by using your domain registrar or web-hosting service’s settings page. For instance, I use Namecheap as my domain service. In Namecheap, you can configure your DNS records by going to your account and choosing Domain List ▶ Manage Domain ▶ Advanced DNS ▶ Add New Record. Create a custom mapping of hostname to IP address and make your domain resolve to 127.0.0.1. You can do this by creating a new A record for your domain that points to 127.0.0.1.
通常,您可以通过使用您的域名注册服务商或网站托管服务的设置页面来配置您的域名的 DNS 记录。例如,我使用 Namecheap 作为我的域名服务。在 Namecheap 中,您可以通过进入您的帐户并选择域名列表▶管理域名▶高级 DNS▶添加新记录来配置您的 DNS 记录。创建一个自定义的主机名到 IP 地址的映射,让您的域名解析到 127.0.0.1。您可以通过为您的域名创建一个指向 127.0.0.1 的新 A 记录来实现这一点。
Then you can ask the target server to send a request to your server, like:
然后你可以让目标服务器向你的服务器发送一个请求,例如:
https://public.example.com/proxy?url=https://attacker.com
Now when the target server requests your domain, it will think your domain is located at 127.0.0.1 and request data from that address.
现在当目标服务器请求您的域名时,它会认为您的域名位于 127.0.0.1,并从该地址请求数据。
Switching Out the Encoding
There are many ways of encoding a URL or an address. Character encodings are different ways of representing the same character while preserving its meaning. They are often used to make data transportation or storage more efficient. These encoding methods don’t change how a server interprets the location of the address, but they might allow the input to slip under the radar of a blocklist if it bans only addresses that are encoded a certain way.
有许多方法可以编码 URL 或地址。字符编码是表示相同字符并保留其含义的不同方式。它们经常用于使数据传输或存储更有效。这些编码方法不会改变服务器解释地址位置的方式,但如果禁止某种编码方式的地址,它们可能允许输入逃过阻止列表的屏障。
Possible encoding methods include hex encoding, octal encoding, dword encoding, URL encoding, and mixed encoding. If the URL parser of the target server does not process these encoding methods appropriately, you might be able to bypass SSRF protection. So far, the addresses provided as examples in this book have used decimal encoding , the base-10 format that uses characters ranging from 0 to 9. To translate a decimal-formatted IP address to hex, calculate each dot-delineated section of the IP address into its hex equivalent. You could use a decimal-to-hex calculator to do this, and then put together the entire address. For example, 127.0.0.1 in decimal translates to 0x7f.0x0.0x0.0x1 in hex. The 0x at the beginning of each section designates it as a hex number. You can then use the hex address in the potential SSRF endpoint:
可能的编码方法包括十六进制编码、八进制编码、双字编码、URL 编码和混合编码。如果目标服务器的 URL 解析器不能正确处理这些编码方法,则可能会绕过 SSRF 保护。迄今为止,本书中提供的实例地址使用了十进制编码,这是一种使用从 0 到 9 的字符的十进制格式。要将十进制格式的 IP 地址转换为十六进制格式,可将 IP 地址的每个点划分部分计算为其十六进制等效部分。您可以使用十进制与十六进制转换计算器来完成此操作,然后将整个地址组合在一起。例如,十进制中的 127.0.0.1 在十六进制中将转换为 0x7f.0x0.0x0.0x1。每个部分前面的 0x 表示它是十六进制数。然后可以在潜在的 SSRF 终端中使用十六进制地址。
https://public.example.com/proxy?url=https://0x7f.0x0.0x0.0x1
Octal encoding is a way of representing characters in a base-8 format by using characters ranging from 0 to 7. As with hex, you can translate an IP address to octal form by recalculating each section. You can utilize an online calculator for this too; just search for decimal to octal calculator to find one. For example, 127.0.0.1 translates to 0177.0.0.01. In this case, the leading zeros are necessary to convey that that section is an octal number. Then use it in the potential SSRF endpoint:
八进制编码是一种使用从 0 到 7 范围的字符以八进制格式表示字符的方式。与十六进制一样,您可以通过重新计算每个部分将 IP 地址转换为八进制形式。您也可以使用在线计算器来完成这个过程;只需搜索“十进制到八进制计算器”来找到一个。例如,127.0.0.1 转换为 0177.0.0.01。在这种情况下,前导零是必要的,以传达该部分是八进制数字。然后将其用于潜在的 SSRF 端点。
https://public.example.com/proxy?url=https://0177.0.0.01
The dword , or double word , encoding scheme represents an IP address as a single 32-bit integer (called a dword). To translate an address into a dword, split the address into four octets (groups of 8 bits), and write out its binary representation. For example, 127.0.0.1 is the decimal representation of 01111111.00000000.00000000.00000001. When we translate the entire number, 01111111000000000000000000000001, into one single decimal number, we get the IP address in dword format.
双字(或双字节) 编码方案表示一个 IP 地址为一个 32 位整数(称为双字)。要将地址转换为双字,请将地址分为四个八位组,并编写其二进制表示。例如,127.0.0.1 是 01111111.00000000.00000000.00000001 的十进制表示。当我们将整个数字 01111111000000000000000000000001 转换为一个单独的十进制数字时,我们得到了以双字格式表示的 IP 地址。
What is 127.0.0.1 in dword format? It’s the answer for 127 × 256 3 + 0 × 256 2 + 0 × 256 1 + 1 × 256 0 , which is 2130706433. You could use a binary-to-decimal calculator to calculate this. If you type https://2130706433 instead of https://127.0.0.1 in your browser, it would still be understood, and you could use it in the potential SSRF endpoint:
127.0.0.1 在 dword 格式下是什么?答案是 127 × 2563 + 0 × 2562 + 0 × 2561 + 1 × 2560,即 2130706433。你可以使用二进制转十进制计算器来计算。如果在浏览器中输入 https://2130706433 而不是 https://127.0.0.1,它仍然可以被理解,并且可以在 SSRF 潜在终端点中使用。
https://public.example.com/proxy?url=https://2130706433
When a server blocks requests to internal hostnames like https://localhost, try its URL-encoded equivalent:
当服务器阻止对内部主机名(例如 https://localhost)的请求时,请尝试使用其 URL 编码的等效形式。
https://public.example.com/proxy?url=https://%6c%6f%63%61%6c%68%6f%73%74
Finally, you could use a combination of encoding techniques to try to fool the blocklist. For example, in the address 0177.0.0.0x1, the first section uses octal encoding, the next two use decimal encoding, and the last section uses hex encoding.
最后,你可以使用编码技术的组合来尝试欺骗阻止列表。例如,在地址 0177.0.0.0x1 中,第一节使用八进制编码,接下来的两节使用十进制编码,最后一节使用十六进制编码。
This is just a small portion of bypasses you can try. You can use many more creative ways to defeat protection and achieve SSRF. When you can’t find a bypass that works, switch your perspective by asking yourself, how would I implement a protection mechanism for this feature? Design what you think the protection logic would look like. Then try to bypass the mechanism you’ve designed. Is it possible? Did you miss anything when implementing the protection? Could the developer of the application have missed something too?
这只是你可以尝试的一小部分绕过方法。你可以使用许多更有创意的方式来打败保护并实现 SSRF。当你找不到有效的绕过方法时,试着换个角度思考,问问自己,我会如何为这个功能实现保护机制呢? 设计出你认为的保护逻辑。然后试着绕过你所设计的机制。是否可能?在实施保护时,是否遗漏了什么?应用程序的开发人员也可能会遗漏一些东西吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论