由一道CTF引发的技术思考(wafbypass)
字数 1551 2025-08-29 22:41:02
WAF绕过技术:斜体字符与Unicode规范化攻击详解
引言
在XYCTF 2025比赛中出现了一道关于bottle框架注入的题目,其WAF绕过手段非常独特。本文将详细分析这种基于Unicode斜体字符的绕过技术,揭示其原理并提供实际应用方法。
题目背景分析
题目代码是一个简单的bottle应用,在/attack路由中:
- 用户输入的payload会被渲染
- payload长度受限
- 过滤了
open函数和反斜杠\
正常情况下的payload
若无限制,正常payload会使用open函数读取文件:
{{open('/etc/passwd').read()}}
常见绕过尝试
开发者可能尝试使用其他函数如include或rebase,但在bottle框架中:
include用于嵌入其他模板文件rebase功能类似- 这些函数无法直接读取服务器文件
核心技术:斜体字符绕过
Unicode斜体字符特性
Unicode中存在特殊斜体字符,它们在规范化分解后与普通字符等价:
- 数学斜体小写o (𝑜, U+1D46F)
- 脚本小写o (ℴ, U+2134)
这些字符经过NFC(Normalization Form C)或NFD(Normalization Form D)规范化后,会被处理为与普通字符相同的形式。
规范化分解原理
Unicode规范化旨在消除字符编码歧义,确保跨平台一致性。例如:
- 斜体
𝑎(U+1D44E)和普通a是不同的码点 - 但规范化分解后都指向基础字符'a'
绕过技术原理分析
Bottle模板处理流程
- 模板适配器:默认使用SimpleTemplate引擎
- 渲染入口:
render()函数 - 执行阶段:
self.execute(stdout, env) - 代码编译:
compile(self.code) - 编码转换:
source, encoding = touni(source), 'utf8'
关键点在于touni()函数:
- 将输入转换为Unicode字符串
- 在Python3中所有str都是Unicode
- 斜体字符会被映射到同一常见字符
绕过过程
- 使用斜体字符替代被过滤的关键字字符
- 输入经过
touni()转换 - 斜体字符被规范化为基础字符
- 最终执行的代码中过滤被绕过
实际利用示例
使用º字符(U+00BA)
- 构造payload:
{{ºpen('/etc/passwd').read()}} - URL编码:
%C2%BA(º的编码) - 删除
%C2前缀,仅保留%BA - 成功绕过过滤并执行
open
其他可用字符
- 艺术字符:ℴ (U+2134)
- 上标字符:ᵒ (U+1D452)
- 其他样式变体字符
扩展攻击面
其他可绕过场景
-
艺术字符:视觉相似但编码不同
- ℴ (U+2134) vs o
- 某些字体下几乎无法区分
-
符号变形:
- º (U+00BA)在URL编码截断情况下可能被解析为a
- 精心构造的编码截断可导致解析错误
-
组合字符:
- 使用基字符+组合标记构成的字符
- 可能被规范化为基础字符
防御措施
-
规范化输入:
- 在处理前对输入进行Unicode规范化
- 使用
unicodedata.normalize()函数
-
严格字符白名单:
- 仅允许ASCII范围内的可打印字符
- 拒绝所有变体字符
-
多重过滤层:
- 在规范化前后都进行检查
- 使用正则表达式严格匹配关键字
-
上下文相关过滤:
- 不仅检查单个字符,还要检查字符组合
- 考虑字符在特定上下文中的含义
结论
这种基于Unicode斜体字符的WAF绕过技术揭示了现代Web应用安全中的深层次问题。防御者需要理解Unicode规范化机制,并在安全设计中考虑字符编码的复杂性。同时,这种技术也可用于其他类似的模板注入场景,具有广泛的适用性。