中文字符形近字的研究
本文是中文字符形近字,或者说是中文的同形异义词的研究。
发现问题
前几天对象和我抱怨,有一道数据安全 CTF 题,本意是给一个 csv,然后需要对其中的数据进行脱敏,里面有一列数据的列名就是 “银行卡”。她用 excel 打开这个表格,可以看到“银行卡”这个列。但是她在写 Python 代码提取数据的时候,通过类似 if col == "银行卡"
或者 col["银行卡"]
来进行筛选这个行却拿不到数据,但是打印所有列名的时候却又能看到“银行卡”这个列。
这个现象抽象出来就是这样:
b 是手打的。
经过比对,发现这两个字符串的长度是一样的,这就排除了是多了不可见字符的问题。
研究问题
这个时候就有趣了,猜测大概率是形近字,但我的确没遇到过中文本身有如此相似的形近字,中文里的多音字也是音不同,但字是完全一个码。
打印出 unicode 值来看看:
可以看出 “行” 这个字是不一样的,手打的 Unicode 值是 34892
。
那么问题来了,我们知道即使是多音字,这个字也是一模一样的 Unicode 值,不会出现不一样的情况,如果 34892 是真正的 “行”,那 12175 又是什么字呢?
经过一番搜索,答案是康熙部首。“康熙部首”是指《康熙字典》中所采用的汉字部首分类系统,是清朝康熙年间编纂的一部权威汉字字典,它将汉字按照部首进行分类,共分为 214 个部首。这种分类方法主要依据汉字的字形和字义,具有较强的系统性,方便人们检索和排版汉字。按照大模型的说法,这些部首都是没有读音的。
在 Unicode 字符集中,康熙部首符号被分配在 U+2F00
到 U+2FDF
的范围内,共包含 214 个字符。这些符号主要用于汉字字典的编排和检索。
测试脚本
为了方便测试,我写了一段 Python 脚本,如果遇到在这个范围里的汉字,会自动修改成对应部首的字:
1 |
|
稍微改改就能用到其他地方,比如这种攻击手法的检测。
一些想法
由于这种部首并没有拼音,因此我推测出题人是五笔打字打出来的,不过我稍微研究了下五笔打字,tfh
打印出来的就是普通的 “行”,也不是康熙部首,不过其他部首的确有些可以打出来。有点奇怪,不知道这是咋打出来的,可能是有康熙部首的字库吧。
那么这个有什么用呢?会造成人眼阅读的结果,与计算机的识别出现差异,从而引发其他安全问题:
- 对抗文字内容的检测策略,例如钓鱼邮件的关键字检测绕过,或者是黄赌毒暴恐政文字过滤策略
- 对于一些软件的用户名称重复检测,可以通过这样的方式绕过,或许用来做一些欺诈,
或者假装靓号装逼 作为出题人用来折磨参赛选手- ... 待挖掘
对于防御方,可以非常简单地基于 Unicode 范围,快速检测文本中可能混入的康熙部首字符,直接干掉。
之前也有类似的 unicode 的研究,见 从一个绕过长度限制的 XSS 中,我们能学到什么?
整个研究过程非常短,差不多就 4 小时,但非常有趣。
不得不说
我对象的确是吸引各种各样 bug 的体质