简介:我正在尝试学习目录遍历的基础知识。
问:在尝试理解字符的2 字节Unicode 转换时,我遇到了this_SANS ARTICLE,它解释了目录遍历漏洞。它指出/
表示为,%C0%2F
但表示%C0%AF
也可以帮助成功攻击。
谁能解释为什么这两种表示都有效?如果在二进制级别解释原因将有很大帮助。
简介:我正在尝试学习目录遍历的基础知识。
问:在尝试理解字符的2 字节Unicode 转换时,我遇到了this_SANS ARTICLE,它解释了目录遍历漏洞。它指出/
表示为,%C0%2F
但表示%C0%AF
也可以帮助成功攻击。
谁能解释为什么这两种表示都有效?如果在二进制级别解释原因将有很大帮助。
首先,URL 编码也称为百分比编码,这是一种简单的方案,其中 URL%xx
表示一个字节(0-255 的数字),每个字节x
都是十六进制数字(基数 16:0-9A-F;注意 16*16=256不同字节的数量)。
因此%C0%AF
,在 URL 中对应于将字节C0 AF
放入解码后的 URL,即字节 192 ( 1100 0000
) 和字节 175 ( 1010 1111
),而%C0%2F
对应于字节 192 ( 1100 0000
) 和字节 47 ( 0010 1111
)
现在 ASCII 只定义字节 0-127 的符号。允许特殊符号(例如,对于非英语作者)对 ASCII 最常见的扩展是 unicode。Unicode 将符号转换/
为由数字表示的代码点;例如,/
是第 47 个代码点(十六进制0x2f
),π
是第 960 个代码点(0x3c0
),并且♥
是第 9829 个代码点(0x2665
)。现在要将 unicode 符号放入字节流中,必须对其进行编码,现在最常见的编码是 UTF-8,因为 UTF-8 继续在单个字节(8 位)中编码 ASCII 字符,所以它不会t 搞砸普通旧 ASCII 文档的编码。注意 ASCII 只定义了 128 个符号(介于 0-127 之间),它们的第一位都是 0。
UTF-8 的工作方式是正常的 ASCII 字符仍然像往常一样使用一个字节进行编码,解码应用程序通过注意到第一位是0
. 当您到达要处理的下一个字节时,如果您看到第一位以 a 开头,1
则表明下一个符号跨多个字节序列表示。字节数由第一个字节的形式决定(具体是第一个字节中1
第一个前导数0
)。例如,如果多字节序列的第一个字节的形式110x xxxx
表明下一个符号用两个字节表示。同样1110 xxxx
意味着它是一个三字节序列的开始,1111 0xxx
是一个四字节序列,等等。现在,如果你阅读UTF-8 wikipedia page,你会注意到两个字节序列应该是110i jklm 10no pqrs
用二进制数表示 unicode 代码点的形式ijk lmno pqrs
,原则上可以是从000 0000 0000
(0) 到111 1111 1111
(2047) 的任何二进制数。在我们的第一种情况 ( C0AF
) 中,我们有位 110 0 0000 10 10 1111,它表示代码点00000101111 = 47 = /
。请注意,47 也可以更简单地用一个 ASCII 字符/
来表示,即 bits 0010 1111
。您可能想知道为什么将第二个字节定义为以10
UTF-8 开头,这样您就可以判断一个字符是否是多字节 UTF-8 字符开头的延续,以帮助捕获错误。
所以这似乎允许多种方式来表示每个 unicode 字符。但这在 unicode 标准中是不允许的。两个字节序列应该只有在 128 和 2047 之间的值,所以C0AF
不应该代表 a/
而是一个错误。但是,unicode 库通常设计得很快,人们可能不会考虑安全隐患。因此,某些库可能选择不检查两字节 unicode 字符的值是否在有效范围内(即使 unicode 标准禁止这样做)。或者开发人员决定,如果给定一个C0AF
很可能是一些格式错误的 UTF-8 应用程序来发送2F
,那么决定退回到对用户最方便的最明智的行为(如显示/
似乎比任何其他要显示的字符选择更明智)。
类似地,更有缺陷的%C0%2F
版本也适用于一些糟糕的 unicode 库,因为许多解码 unicode 的应用程序不检查第二个字节的第一位实际上是 a 1
,因为前一个字节已经表明它是一个双字节代码点。那就是错误的解码器接受110i jklm ??no pqrs
为有效的两字节代码点,而不管 ?? 作为10
UTF8 标准的要求。第二个字节的前两个字符是多余的,因此快速而肮脏的 unicode 解码应用程序可能决定不检查这些字符是否匹配正确的值。
因此,现在我们知道了原因%C0%AF
,并且两者最终都使用跳过正确检查的 unicode 解码器%C0%2F
解码为符号。/
至于为什么这会成功地允许目录遍历,经常会发生过滤不正确的输入和解码 unicode 符号是在应用程序的不同阶段完成的。Web 服务器可能足够聪明,不允许有人浏览http://www.example.com/../../../etc/shadow
或什http://www.example.com/..%2f..%2f..%2fetc%2fshadow
至排除不正确的符号。但是,如果 Web 服务器正在提供文件并且解码 unicode 是在防止目录遍历的检查之后完成的,或者由操作系统完成的稍有不同,则此攻击可能会通过过滤器,从而允许攻击起作用。
有关 unicode 的更详细可访问的介绍,我推荐“每个软件开发人员绝对、肯定必须了解 Unicode 和字符集的绝对最低要求(没有借口!)”。