[【通过】] Unicode & UTF8编码知多少

[复制链接]
SekIa 发表于 2016-12-29 15:25:58 | 显示全部楼层 |阅读模式

正式成员|主题 |帖子 |积分 36

本帖最后由 SekIa 于 2016-12-29 15:25 编辑

0x00 Unicode简介

字符编码的发展随着图形操作系统发展加上各国语系显示的需求,从早期的ASCII到EASCII再到ANSI制定出代码页标准,都没有办法好好地解决字符集太小,无法同时显示全球所有字符的问题。

例如:用代码页936(GBK,简体中文)编码的文字拿去代码页950(BIG5,繁体中文)会变成莫名其妙的文章。

这样的情况在Unicode编码方式(Universal Code)出现后终于得到改善,对世界上大部分的文字系统进行了整理、编码,也能支持多种语言混合的情况,是计算机科学领域里的一项业界标准。

一张包含全世界所有文字的表,把所有的符号一律改成16进制数,没用到也用0来补。(注: Unicode table,https://unicode-table.com/en/)

然而,Unicode是一个字符集,只规定了字符的二进制编码,不同系统对Unicode编码方式的实现方式不同。

为确保传送方与接收方能收到一致的编码内容,以及出于节省空间的目的,而设计出Unicode转换格式(Unicode Transformation Format,简称UTF),常见的种类有UTF-8、UTF-16、UTF-32、GB18030等等。

0x01 UTF

这里简单介绍下各Unicode转换格式的特色,其中因UTF-8兼容ASCII且占用的空间比较小,为目前网页、Email及网络传输应用中优先采用的编码。

UTF-8
  • 一种针对Unicode的可变长度字符编码
  • 兼容 ASCII,不需要特别转换
  • 为目前网页、Email及网络传输应用中优先采用的编码
UTF-16
  • 分为UTF-16 LE(Little-Endian)及UTF-16 BE(Big-Endian)
  • 不相容ASCII,需转换
  • 大部分字符都以固定2个字节来储存
  • 特殊字符以4个字节来储存
UTF-32
  • 每个字符皆固定4个字节来储存

补充:微软Windows操作系统附带的记事本(Notepad)的另存功能中可选择四种编码,分别是ANSI(非Unicode,代码页依语系决定)、Unicode(UTF-16 LE)、Unicode big endian(UTF-16 BE)和UTF-8

0x02 UTF-8编码

上一章节有提到UTF-8采用变动长度编码,且能兼容ASCII,那我们来看下他是如何编码的。

UTF-8编码会依据Unicode字符的区间来决定分割为多少个部份,并分配到对应的位位置。

在U+0080以下的字符都落于单字节编码,刚好对应7位的ASCII字符,其他字符则会被分割成2~4个不等的字节中。

UTF-8编码为了避免与7位的ASCII混淆,每个字节的最高位皆会被设定为1。

下面是编码表: 红色字体表示该位值是固定,蓝色或xxxxx则为编码字符的二进值

0.png


举个例子:「$」,U+0024 (二进值0100100(b)),介于0x000000-0x00007F,使用单字节编码,结果为0x24 (二进值00100100(b)),与原本ASCII值相同。

再个例子:「牛」,U+725B (二进值01110010 01011011(b)),介于0x000800-0x00FFFF,使用三字节编码,依照上表将二进值依序带入x位置,结果为0xE7 0x89 0x9B(二进值11100111 10001001 10011011(b))

科普到这边,下一章节会比较有趣一点的应用。

补充:关于UTF-8详细规格的档案共有好几份,基本原理都是相同的,最主要的差异是支持的字符范围及无效输入的处理方法。
rfc3629 - https://tools.ietf.org/html/rfc3629
The Unicode Standard - http://www.unicode.org/versions/Unicode9.0.0/ch03.pdf#G7404
rfc2279 - https://www.ietf.org/rfc/rfc2279.txt
rfc2044 - https://tools.ietf.org/html/rfc2044


0x03 畸形字节

前一章节讲UTF-8的标准,但是标准归标准,实作归实作,实作与标准上的落差往往就是攻击者的利刃。

那我们来试试畸形编码,不按照Unicode Range规则,硬把单字节编成三字节编码。

如「$」,U+0024 (00100100(b))编码为三字节0xE0 0x80 0xA4(11100000 10000000 10100100(b))

这里提供两个UTF-8 encode/decode功能的网址:
https://sites.google.com/site/nathanlexwww/tools/utf8-convert
https://mothereff.in/utf-8

我们把刚刚编码的0xE0 0x80 0xA4丢进去试试。

1.png
  
可以发现左边的网站即使是畸形UTF-8编码依然可以解出「$」,利用这样的实作落差就有机会绕过防御机制。


在Oracle GlassFish Server 4.1就因为这样的特性被找出Directory Traversal漏洞(根因应是更底层的UTF-8 decode有问题),POC如下(https://www.exploit-db.com/exploits/39441/):

GET /theme/com%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%afwindows/win.ini
(%c0%af即为11000000 10101111(b),「/」的双字节畸形编码)

来个实际例子

2.png

0x04 畸形检查码

前面提到的是字节上的畸形编码,这里再来看另外一种畸形编码,不填入正确的检查码。

例如「/」,U+002F(00101111(b))即有2种变化 1010111100101111,但大部分译码器对第一字节的检查码都很严谨,因此常见的作法是搭配上述的字节畸形。

举个例子:「/」,U+002F(00101111(b)),先转换为双字节11000000 10101111(b)再进行变形。
  • 11000000 10101111(b)
  • 11000000 11101111(b)
  • 11000000 01101111(b)
  • 11000000 00101111(b)

3.png


利用前面提到的译码网站,我们输入4个畸形编码,都能正确解出「/」字符。

那我们实际拿网站来试试,将%c0%af(11000000 10101111(b))改为%c0%2f(11000000 00101111(b)),毫无压力。

4.png

0x05 总结

以前在文章总是看到别人说试试把字符转换成多字节,说不定能绕过。

开始研究后才发现其中的原因,主要是利用系统UTF-8译码规则不严谨所造成的缺陷。

换句话说,并非所有系统都有这样的问题,至于哪些系统有这样的问题,就请大家补充下了,但这不是最要紧的,最要紧的是让我进90先。

最后,附上整理表。

5.png

(从WORD贴过来,样式跑啦。附上投稿时的PDF,样式应该漂亮些)

Unicode&UTF8.pdf

479.58 KB, 下载次数: 245

评分

参与人数 1酒票 +5 收起 理由
管理05 + 5 欢迎加入90!

查看全部评分

allensmile 发表于 2016-12-29 16:01:50 | 显示全部楼层

正式成员|主题 |帖子 |积分 13

感谢楼主写得这么详细,把unicode的前因后果都写出来,之后可以讨论的议题又多了,应该也可以延伸出来其他语法绕过waf。
这类型的漏洞貌似2000年在IIS上就发生,然后每几年就在其他web server上又出现ㄧ次,像是瘟疫ㄧ样。
刚又去翻了一下,在IIS和Tomcat上都有发生过,有时候前面上了patch过,下次重新更版时,搞不好又恢复了。
https://www.exploit-db.com/exploits/189/ (IIS)
https://www.exploit-db.com/exploits/14489/ (Tomcat)


绿剑 发表于 2017-1-2 10:00:17 | 显示全部楼层

正式成员|主题 |帖子 |积分 143

这个编码说的好详细,学习了
快速回复 返回顶部 返回列表