safe_of_Unicode

 · 2020-5-5 · 次阅读


摘自:https://xz.aliyun.com/t/5402#toc-0

简介

早期的计算机使用7-bit的ASCII编码来作为字符的编码,只支持少数的一些字符。但随着计算机的不断普及,各个国家和地区开始制造自己的编码规范,同时互相不兼容,因而编码问题逐渐成为一个亟需解决的问题。

什么是Unicode

ISO(国际标准化组织)开始尝试制定包含大部分字母和符号的编码,称为”Universal Multiple-Octet Coded Character Set”,简称UCS,俗称Unicode.

Unicode实际就是一个字符和数字之间的映射关系表,并不制定实际的编码方案。
而它的实际编码方案便是我们熟悉的UTF系列(Unicode TransFormation Formats)
包括UTF-8,UTF-16,UTF-32

Code Point 与 Code Unit

Code Point指Unicode标准里字符的编号,目前Unicode使用了0~0x10FFFF的编码范围,通常用U+xxxx来表示某个字符。

Code Unit值某种Unicode编码方式里编码一个Code POint需要的最少字节数
比如UTF-8最少一个字节,UTF-16最少需要两个字节,UTF-32四个字节,UCS-2两个
UCS-4四个,其中UCS-2,UCS-4,UTF-32是定长编码。

Unicode安全问题

视觉欺骗

视觉问题一般值几个不同的字符在某个字体下看起来较为相同,
之前刷题也遇到了这个问题,大致是这样的
大写的A被过滤了,题目中会对名称进行大写自动转小写,于是Admin会变成admin,但问题是A被过滤了,这时候就考虑到其他的编码ᴀdmin,成功得到了admin权限。这里我们可以看到它看起来是A但又矮一点,因而编码并不是A的编码,这也是视觉欺骗的例子。

视觉欺骗还可能是字符之间一对一相似、多个字符的组合字符和一个字符相似等,这种现象在字体较小的情况下会更加明显,在一些文章中这种问题也被称为同形异义词问题。

  1. 国际化域名
    国际化域名(Internationalized Domain Name,IDN)又称特殊字符域名,是指部分或完全使用特殊的文字或字母组成的互联网域名,包括中文、法语、阿拉伯语、希伯来语或拉丁字母等非英文字母,这些文字经过多字节万国码编码而成。

因为浏览器对国家化域名的支持,这也使得appIe.com(I是U+04CF)与apple.com比较相似。

上诉例子在Chrome中已经完全修复,但Firefox中任然存在问题。

又例如在URL中一个看上去和控制字符类似的Unicode也会造成问题,例如/ 和 ⁄ (U+2044)
还有example.com⁄evil.com 实际上是 com⁄evil.com 的子域名。同样的 ? / . / # 等类似字符也存在这样的问题。

除了上面提到的两种情况,punycode也是一种视觉欺骗的形式,punycode是域名的一种编码,会以 xn– 开头,后面是普通的有效域名,例如 аррӏе.com 对应的punycode就是 xn–80ak6aa92e.com。当chrome认为这是一个视觉问题时,就会主动把域名以punycode显示,以减少混淆的影响。但是反过来,也能应用这种方式来实现视觉欺骗,例如 䕮䕵䕶䕱.com 的punycode形式就是 xn–google.com。

  1. 双向显示

例如一个名为txt.exe的文件加入Unicode控制字符后在用户界面是exe.txt这也会导致用户的误判。

  1. 数字显示

一些国家的数字在显示的时候也可能造成问题,例如孟加拉语的0-9是০ ১ ২ ৩ ৪ ৫ ৬ ৭ ৮ ৯,但是这里的৪ (U+09EA) 实际上是数字4。ASIS CTF 2019 的 Unicorn Shop) 也是从Unicode背后的数字角度出发考虑问题。

非视觉漏洞

  1. 等价形式

在WAF类处理,很容易想到的是 LocalHost 和 localhost 等同,但是 ⓛocaⓛhost 这种情景就不太容易被处理。在SSRF中的防御中,如果没有做对应的处理,这种替换就可以完成一些bypass。

  1. 字符删除

例如在\x3c\x73\x63\x72\xc2\x69\x70\x74\x3e 这个字符串中,而 \xc2 并不是任何一个有效字符的子串,在一些处理逻辑中,可能会删除 \xc2 这个字符,从而导致问题。

  1. 字符替代

一些情况下,字符会被替换为其他的字符 如U+FFFF会被替换成 ?这在一些 ?有明确的语义的情况下就会出现问题。

  1. 缓冲区溢出

在一些大小写转换时,字符会变多,例如 ‘ß’.toUpperCase() 的运行结果是 SS。如果字符串的长度检查在大小写转换之前,就可能会存在缓冲区溢出问题。

CTF实践:

[ASIS 2019]Unicorn shop

进入页面后是如图的一个买马的一个框框:
index
我们尝试购买第一匹宝马,输入ID=1,prize=2.0
得到了如下提示:
one_char

这里我们尝试查看其他地方是否有提示,查看页面源码发现:
html

这里值得关注的是utf-8这个点很重要,因而考虑utf-8也就是编码的安全问题,是否有一个编码可以代表极大的数字。

上图中最大的prize是1337所以我们找一个比1337还大的编码就可以了。
接着找到一个网站:unicode编码转换数字
这上面找一个其数字的值比1337大就可以了。

然后找到了一个ten Thousand值的编码符号:
ten
往下面翻可以看到它的utf-8编码是:0xE1 0X8D 0XBC,那么直接输入这个编码购买?
很明显url仍然会把他处理为多个char,但题目说明了只需要一个char,因而我们将其转换为urlencode即把0x直接改为%E1%8D%BC,这样页面才能正常处理这个参数并将其转化为上图中的一个字符最终买到flag.