一、前言
2022年9月13日,Unicode15.0正式版发布。在Unicode15.0中增加了4,489个字符,总共字符数量达到了149,186个。这些新增内容包括2个新脚本,总共脚本数量达到161个,以及20个新的表情符号字符。同时,几个重要的Unicode规范也随着15.0版本进行了更新,这其中就包括Unicode安全机制这个规范,它意在减少因Unicode字符视觉带来的同形异意攻击。
同形异意攻击是非常古老的一种视觉攻击方式。在机械打字机时代,很多打字机为了简化设计和降低制造及维护成本,键盘上没有单独的1和0。打字员会使用小写字母L和大写字母i来代替数字1,使用大写字母O来代替数字0。当这些相同的打字员在70年代和80年代初转变为计算机键盘操作员时,他们的旧键盘习惯在他们的新职业中继续存在,并成为极大混乱的源泉。这应该是视觉混淆、同形异意攻击集中爆发的一个时期。
在此之后,打字机被文字处理器所代替,信息化时代逐步到来,字符编码也开始由ASCII字符集逐渐扩充到Unicode字符集。我们开始使用浏览器或其他应用客户端来呈现文本,那些在某些语境中不适合使用同形字书写URL、公式、源代码、ID等等,其相似的外观继续使得用户可能在视觉上无法区分。
Unicode视觉取决于视觉上可以混淆的字符串:两个Unicode字符串外观上非常相似,在通常的屏幕分辨率下,它们以小尺寸的普通字体出现,很容易让人们误认为是另一个。视觉混淆没有明显的规则:当尺寸足够小时,许多字符都看起来像其他字符。“屏幕分辨率下的小尺寸”是指大多数脚本使用9-12像素的字体。易混淆性还取决于字体的风格:对于传统的希伯来字体,许多字符只能通过细微的差别来区分,而这些细微差别可能在小尺寸时丢失。在某些情况下,字符序列也可用于:例如,“rn”在许多sans-serif字体中与“m”在视觉上混淆。
近些年来,因Unicode编码发生了很多恶意攻击事件,人为或编译器或AI都可能因Unicode产生错误的判断和解析。例如2021年有研究人员在谷歌等商业系统中使用Unicode的这些特殊字符对NLP模型进行对抗攻击。他们通过一些不可察觉的编码注入——比如一个不可见字符、同形符、重新排序或删除的操作字符,可以显著降低一些模型的性能,大多数模型都可能在功能上失灵。
2022年Trezor这款知名的硬件钱包出现了大量的网络钓鱼网站,钓鱼链接https://suite.tr?zor.com。这个钓鱼链接和真实Trezor官方网站trezor.io极为相似。
虽然基于客户端的尤其是浏览器端的抵御视觉的防御措施一直在完善,但并没有办法完全封堵住这种攻击。第一,视觉是一种很难被完全消亡的攻击,因为在足够小的尺寸情况下人自身的生理视觉体系也是无法分辨的;第二,Unicode字符集非常庞大,并且在不断的增加;第三,需要标准组织、浏览器开发商、域名注册商等多方共同协作去完成。
本文主要研究当下Unicode中因字形渲染、混合脚本、PunyCode、双向文本、组合字符引起的视觉问题,结合作者发现的不同类型的Unicode视觉漏洞,分享漏洞挖掘过程方法并给出一些防御的思路。
二、字形渲染带来的安全风险
当字体或渲染引擎对字符或字符序列的支持不足时,就使得本应该在视觉上可以区分的字符或字符序列出现新的问题--视觉混淆。尤其是这些字符被做为关键的信息出现时,比如在浏览器重要的安全指示器地址栏中,这种视觉的危害就会显而易见。浏览器厂商对于地址栏上的IDN问题,一直在做积极的防御,通常是在浏览器里维护一个重要域名列表,如果一个域名和列表中的域名同形异议,则将其转化为Punycode编码显示。
渲染支持不足,直接导致每一个字符的字形含义往往超出我们的预期,这种不确定性使得视觉随时都可能发生。那么字形到底是什么,它和字型、字符、字体有什么关系,包括Unicode中越来越火的Emoji表情它是字符吗?其中一些基本的名词概念非专业人士经常混淆,我们先简要了解下。
字体指的是一组字符的设计,通常包括字母、一组数字和一组标点符号。也常包括表意字符以及制图符号。每个字体都是字形的集合,比如宋体、黑体等。有些字体技术非常强大,比如TrueType/OpenType,它们可以根据分辨率、系统平台、语言等来选择显示最佳的形状。但是,它也可以用于安全攻击,因为它足够强大,可以在打印时将屏幕上的“$100.00”外观更改为“$200.00”。?此外,层叠样式表可以更改为不同的字体,用于打印与屏幕显示,这可以使用更多可混淆字体。这些问题并非特定于Unicode。为了降低此类漏洞利用的风险,程序员和用户应该只允许可信任的字体。
字型是指印刷行业中某一整套具有同样样式和尺码的字形,例如一整套用于内文的宋体5号字、一整套用于标题的10号字就叫一套字型。电脑早期用点阵字,仍然有字型概念,同样一套风格如中易宋体,一套字型是指一整套15×16像素或一整套24×24像素的字。矢量字型出现后,同一套风格字型已不用制作不同像素字型,只需制作一套即可随意缩放,“字型”与“字体”之间的界限开始模楜。一般的英语使用者同样分不清“字型”与“字体”的分别。
字形,又称字图或书形,是指字的形体。中华人民共和国国家标准GB/T16964《信息技术·字型信息交换》中定义字形为“一个可以辨认的抽象的图形符号,它不依赖于任何特定的设计”。在语言学中,字是语意的最基本单位,即语素;字形是指为了表达这个意义的具体表达。同一字可以有不同的字形,而不影响其表达的意思,例如拉丁字母第一个字母可以写作a或ɑ,汉字中的“強/强”、“戶/户/戸”。
在复杂的脚本中,字符可能会根据周围的字符更改形状。
字形可以随周围环境所改变
3个arabicletterheh(U+0647)组合在一起
多个字符可以产生一个字形
f=latinsmallletterf(U+0066)
i=latinsmallletteri(U+0069)
我们来看一个和视觉有关的,当多个不同字符组合后可能视觉外观是相同的。例如字符U+0BB6SHA和U+0BB8SA通常非常不同。但这两个组合的字符序列,视觉感官上完全相同。底层的二进制是不同的。
其实多字符组合不仅仅是视觉,有时这种多字符组合也可以导致系统内存崩溃。CVE-2018-4124这个漏洞可导致macOSHighSierra10.13.3在处理恶意制作的字符串时致堆损坏。????的原始序列是U+0C1CU+0C4DU+0C1EU+200CU+0C3E,这是一个泰卢固语字符序列:辅音ja(?)、virama(?)、辅音nya(?)、零-width非连接符和元音aa(?)。当macOS在处理????这个字符序列时,即可导致系统崩溃。
表情符号是象形文字,通常以彩色卡通形式呈现并在文本中内联使用。它们代表面部,天气,车辆和建筑物,食物和饮料,动物和植物,或代表情感,感觉或活动的图标。Emoji已经无处不在,它正在成为跨越不同文化的所有人通用的语言。但不同人对Emoji的使用理解以及各个操作系统碎片化的支持,也使得带来了一些问题。比如:短期内你也不会看到步的表情符号,U+1F946。Unicode组织包括苹果和微软都反对加入步符号。手和其他武器的Emojis已经使人们陷入了法律的困扰。之前一家法国法院裁定手表情符号可能构成死亡威胁,将一名把的表情发给前女友的男子判处三个月监禁。
在浏览器地址栏中直接渲染U+1F512这个编码也是相当危险的。因为它和HTTPS安全小锁外观上非常相似。攻击者可以对其进行安全小锁的伪造。U+1F512编码曾在Chrome/Firefox浏览器中出现过这样的安全问题。
三、混合脚本带来的安全风险
混合脚本是有很多合法的用途的,例如Ωmega。但视觉上容易混淆的字符通常不会放在一个脚本中。在视觉上容易混淆的字符为提供了许多机会,例如下面这两个域名,希腊小写字母Omicron和拉丁文o外观是非常相似的。
很久之前,域名只允许包含拉丁字母A-Z,数字和一些其他字符。之后大家发现,仅仅支持ASCII码的域名可能是有问题的,因为世界上还有很多非拉丁文语系的国家和地区,他们也渴望在域名中使用自己的语言符号。后来经过多次提案讨论,在2003年发布了国际化域名的规范,它允许大多数的Unicode在域名中使用,普遍将这个规范称为IDNA2003。之后在2010年批准发布了对IDNA2003的修订版,称这个修订版为IDNA2008。但IDNA2003和IDNA2008并没有有效的解决国际化域名中的某些问题。随后,Unicode联盟发布了解决了某些兼容性的问题。
在IDNA中使用PunyCode算法来实现非ASCII域名到ASCII域名的转换。PunyCode算法可以将任何一个非ASCII的Unicode字符串唯一映射为一个仅使用英文字母、数字和连字符的字符串,编码的域名在前面都加上了xn--来表明这是一个PunyCode编码。
国际化域名是在Unicode中定义的任何字符集或脚本中注册的二级或三级域名或Web地址。直到2009年底之前,顶级域名仅限于拉丁字母a-z,之后随着Web全球化发展,IDNTLDs也开始逐渐推广和普及,这加速了全球化进展的同时,也带来了一些安全风险,这点在后面我们会谈到。
在前文中我们已经了解到,Unicode15.0中的字符总量149,186个,脚本数161个。这些脚本中大部分都可以被用于域名注册,并且数量还在增加中。以顶级域名COM为例,Verisign制定了IDN注册的策略,规定了允许和禁止的代码点。并制定了IETF标准、对特定语言的限制、对脚本混淆的限制、ICANN受限Unicode代码、特殊字符这五条验证规则,遵循这五条规则的IDN被认为是有效的注册。
在这五条IDN注册规则中,我们会重点关注“脚本混淆的限制”这条规则,因为这对发现IDN上的视觉问题有帮助意义。
Verisign不允许使用混合的Unicode脚本进行注册。如果IDN中包含两个或多个Unicode脚本代码,将拒绝注册。例如拉丁文脚本中的字符不能和任何西里尔字符在同一个IDN中使用。IDN中的所有代码必须来自同一个Unicode脚本。这样做是为了避免混淆的代码出现在同一个IDN中。
下表列出了允许使用的Unicode脚本。
列举我之前发现的一个漏洞,SpoofAllDomainsContaining‘d’inAppleProducts。我在研究中发现,在苹果产品中编码latinsmallletterdum(U+A771)渲染的字形和latinsmallletterd(U+0064)极为相似。从Unicode中(U+A771)的字形标准可以发现,d后面应该还有一个小撇,但是在苹果产品中把这个完全忽略掉了。
接下来,我去注册了一个真实的域名,使这个IDNSpoof可以正常运行。我们知道在Verisign制定的IDN注册的规则中,不允许使用混合的Unicode脚本进行注册。如果IDN中包含两个或多个Unicode脚本代码,将拒绝注册。而也是属于Latin,应该是符合域名注册商规则的。于是域名成功注册成功了。
我又注册了一个SSL证书,使这个IDNSpoof看的会更加真实完美。效果如下,Safari并没有将这个域名转化为punycode显示,所以我们成功了。
到这里我们确定了整个流程是完全可行的,那么攻击者可以伪造域名中有d的所有域名。在Ggoogle统计的Top10k域名中,大约有超过25%的网站域名中有d这个字符。这些网站的域名都可以被伪造。
https://chromium.googlesource.com/chromium/src/+/master/components/url_formatter/top_domains/alexa_domains.list
?linkedin.com
?baidu.com
?jd.com
?adobe.com
?wordpress.com
?dropbox.com
?godaddy.com
?reddit.com
…………
watchOS4.3.2??https://support.apple.com/zh-cn/HT208935
iOS11.4.1??https://support.apple.com/zh-cn/HT208938
tvOS11.4.1?https://support.apple.com/zh-cn/HT208936
macOSHighSierra10.13.5??https://support.apple.com/zh-cn/HT208937
四、双向文本带来的安全风险
某些字符具有固有的从右到左的书写方向。当这些字符与从左到右显示的其他脚本或符号集的字符混合时,生成的文本称为双向。文档的内存表示与双向文本的显示外观之间的关系由UAX#9:Unicode双向算法管理。
由于某些字符具有弱或中性的方向性,而不是强左向右或从右到左,因此Unicode双向算法使用一组精确的规则来确定最终的视觉呈现。然而,任意文本序列的呈现,可能导致文本序列无法清晰地被阅读,或者可能在视觉上混淆。
在一个URL中,经常会遇到多种方向性的字符同时存在的情况。虽然Unicode双向算法使用一组精确的规则来确定最终的视觉呈现,但是多种方向性的文本序列在呈现时,还是可能导致文本序列无法清晰地被阅读,或者可能在视觉上混淆。
Chrome之前出过这样一个漏洞,在Chrome里访问:
在地址栏中实际渲染为:
CVE-2018-4205是我之前发现的一个漏洞,利用了RTL和空白符导致了URL地址栏。下面就以这个漏洞为例进行讲解。
构造POC-1
访问http://www.apple.com.xn--ggbla3j.xn--ngbc5azd/。可以看到
Chrome/Firefox/Safari三个浏览器地址栏,显示都是一样的。Edge显示punycode。
构造POC-2
在四个浏览器中访问POC-2,我们此时已经发现了问题。在Safari中出现了RTL和空白字符。
构造POC-3
郑重声明: 本文版权归原作者所有, 转载文章仅为传播更多信息之目的, 如作者信息标记有误, 请第一时间联系我们修改或删除, 多谢。