中文字符形近字的研究

admin 2025年3月10日06:48:29评论11 views字数 3657阅读12分11秒阅读模式

🍊 中文字符形近字的研究

这是橘子杀手的第 59 篇文章
题图摄于:斐济·罗马尼岛

发现问题

前几天对象和我抱怨,有一道数据安全 CTF 题,本意是给一个 csv,然后需要对其中的数据进行脱敏,里面有一列数据的列名就是 “银行卡”。她用 excel 打开这个表格,可以看到“银行卡”这个列。但是她在写 Python 代码提取数据的时候,通过类似 if col == "银行卡" 或者 col["银行卡"] 来进行筛选这个行却拿不到数据,但是打印所有列名的时候却又能看到“银行卡”这个列。

这个现象抽象出来就是这样:

中文字符形近字的研究

b 是手打的。

经过比对,发现这两个字符串的长度是一样的,这就排除了是多了不可见字符的问题。

研究问题

这个时候就有趣了,猜测大概率是形近字,但我的确没遇到过中文本身有如此相似的形近字,中文里的多音字也是音不同,但字是完全一个码。

打印出 unicode 值来看看:

中文字符形近字的研究

可以看出 “行” 这个字是不一样的,手打的 Unicode 值是 34892

那么问题来了,我们知道即使是多音字,这个字也是一模一样的 Unicode 值,不会出现不一样的情况,如果 34892 是真正的 “行”,那 12175 又是什么字呢?

经过一番搜索,答案是康熙部首。“康熙部首”是指《康熙字典》中所采用的汉字部首分类系统,是清朝康熙年间编纂的一部权威汉字字典,它将汉字按照部首进行分类,共分为 214 个部首。这种分类方法主要依据汉字的字形和字义,具有较强的系统性,方便人们检索和排版汉字。按照大模型的说法,这些部首都是没有读音的。

在 Unicode 字符集中,康熙部首符号被分配在 U+2F00 到 U+2FDF 的范围内,共包含 214 个字符。这些符号主要用于汉字字典的编排和检索。

测试脚本

为了方便测试,我写了一段 Python 脚本,如果遇到在这个范围里的汉字,会自动修改成对应部首的字:

import argparse

from colorama import Fore, Style

def put_color(string, color, bold=True):
    if color == "gray":
        COLOR = Style.DIM + Fore.WHITE
    else:
        COLOR = getattr(Fore, color.upper(), "WHITE")

    returnf'{Style.BRIGHT if bold else ""}{COLOR}{str(string)}{Style.RESET_ALL}'

trans_map =  trans_map = { "一""⼀""|""⼁"None: [ "⼃""⼅""⼇""⼌""⼍""⼎""⼐""⼓""⼕""⼖""⼙""⼛""⼞""⼡""⼢""⼣""⼧""⼪""⼬""⼮""⼵""⼶""⼹""⼺""⼻""⼾""⽁""⽎""⽏""⽙""⽦""⽧""⽨""⽰""⽱""⽷""⽾""⾇""⾋""⾌""⾑""⾒""⾓""⾘""⾙""⾞""⾡""⾤""⾧""⾨""⾫""⾭""⾱""⾴""⾵""⾶""⾺""⾻""⾽""⾾""⾿""⿂""⿃""⿄""⿆""⿇""⿈""⿋""⿌""⿍""⿑""⿒""⿓""⿔""⿕", ], "乙""⼄""二""⼆""人""⼈""儿""⼉""入""⼊""八""⼋""几""⼏""刀""⼑""力""⼒""匕""⼔"" 十""⼗""卜""⼘""厂""⼚""又""⼜""口""⼝""土""⼟""士""⼠""大""⼤""女""⼥""子""⼦""寸""⼨""小""⼩""尸""⼫""山""⼭""工""⼯""己""⼰""巾""⼱""干""⼲""幺""⼳""广""⼴""弋""⼷""弓""⼸""心""⼼""戈""⼽""手""⼿""支""⽀""文""⽂""斗""⽃""斤""⽄""方""⽅""无""⽆""日""⽇""曰""⽈""月""⽉""木""⽊""欠""⽋""止""⽌""歹""⽍""比""⽐""毛""⽑""氏""⽒""气""⽓""水""⽔""火""⽕""爪""⽖""父""⽗""爻""⽘""片""⽚""牙""⽛""牛""⽜""犬""⽝""玄""⽞""玉""⽟""瓜""⽠""瓦""⽡""甘""⽢""生""⽣""用""⽤""田""⽥""白""⽩""皮""⽪""皿""⽫""目""⽬""矛""⽭""矢""⽮""石""⽯""禾""⽲""穴""⽳""立""⽴""竹""⽵""米""⽶""缶""⽸""网""⽹""羊""⽺""羽""⽻""老""⽼""而""⽽""耳""⽿""聿""⾀""肉""⾁""臣""⾂""自""⾃""至""⾄""臼""⾅""舌""⾆""舟""⾈""艮""⾉""色""⾊""虫""⾍""血""⾎""行""⾏""衣""⾐""言""⾔""谷""⾕""豆""⾖""豕""⾗""赤""⾚""走""⾛""足""⾜""身""⾝""辛""⾟""辰""⾠""邑""⾢""酉""⾣""里""⾥""金""⾦""阜""⾩""隶""⾪""雨""⾬""非""⾮""面""⾯""革""⾰""韭""⾲""音""⾳""食""⾷""首""⾸""香""⾹""高""⾼""鬲""⿀""鬼""⿁""鹿""⿅""黍""⿉""黑""⿊""鼓""⿎""鼠""⿏""鼻""⿐", } 

parser = argparse.ArgumentParser()
parser.add_argument("-c""--content", type=str, help="输入要转换的文字", required=True)

args = parser.parse_args()

raw_content = args.content
print(
    f"-> {raw_content}",
)
count = 0
print("<- ", end="")
for c in raw_content:
    tc = trans_map.get(c, c)
    if tc != c:
        tc = put_color(tc, "red")
        count += 1

    print(tc, end="")

print(f"nn[*] 修改了 {count} 个字")
中文字符形近字的研究

稍微改改就能用到其他地方,比如这种攻击手法的检测。

一些想法

由于这种部首并没有拼音,因此我推测出题人是五笔打字打出来的,不过我稍微研究了下五笔打字,tfh 打印出来的就是普通的 “行”,也不是康熙部首,不过其他部首的确有些可以打出来。有点奇怪,不知道这是咋打出来的,可能是有康熙部首的字库吧。

那么这个有什么用呢?会造成人眼阅读的结果,与计算机的识别出现差异,从而引发其他安全问题:

  1. 对抗文字内容的检测策略,例如钓鱼邮件的关键字检测绕过,或者是黄赌毒暴恐政文字过滤策略
  2. 对于一些软件的用户名称重复检测,可以通过这样的方式绕过,或许用来做一些欺诈,或者假装靓号装逼
  3. 作为出题人用来折磨参赛选手
  4. ... 待挖掘

对于防御方,可以非常简单地基于 Unicode 范围,快速检测文本中可能混入的康熙部首字符,直接干掉。

之前也有类似的 unicode 的研究,见 从一个绕过长度限制的 XSS 中,我们能学到什么?( https://www.tr0y.wang/2020/08/18/IDN/ )

整个研究过程很短,差不多就 4 小时,但非常有趣


不得不说
我对象的确是吸引各种各样 bug 的体质
中文字符形近字的研究



原文始发于微信公众号(橘子杀手):中文字符形近字的研究

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年3月10日06:48:29
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   中文字符形近字的研究http://cn-sec.com/archives/3820194.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息