由一道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()}}

常见绕过尝试

开发者可能尝试使用其他函数如includerebase,但在bottle框架中:

  • include用于嵌入其他模板文件
  • rebase功能类似
  • 这些函数无法直接读取服务器文件

核心技术:斜体字符绕过

Unicode斜体字符特性

Unicode中存在特殊斜体字符,它们在规范化分解后与普通字符等价:

  1. 数学斜体小写o (𝑜, U+1D46F)
  2. 脚本小写o (ℴ, U+2134)

这些字符经过NFC(Normalization Form C)或NFD(Normalization Form D)规范化后,会被处理为与普通字符相同的形式。

规范化分解原理

Unicode规范化旨在消除字符编码歧义,确保跨平台一致性。例如:

  • 斜体𝑎(U+1D44E)和普通a是不同的码点
  • 但规范化分解后都指向基础字符'a'

绕过技术原理分析

Bottle模板处理流程

  1. 模板适配器:默认使用SimpleTemplate引擎
  2. 渲染入口render()函数
  3. 执行阶段self.execute(stdout, env)
  4. 代码编译compile(self.code)
  5. 编码转换source, encoding = touni(source), 'utf8'

关键点在于touni()函数:

  • 将输入转换为Unicode字符串
  • 在Python3中所有str都是Unicode
  • 斜体字符会被映射到同一常见字符

绕过过程

  1. 使用斜体字符替代被过滤的关键字字符
  2. 输入经过touni()转换
  3. 斜体字符被规范化为基础字符
  4. 最终执行的代码中过滤被绕过

实际利用示例

使用º字符(U+00BA)

  1. 构造payload:{{ºpen('/etc/passwd').read()}}
  2. URL编码:%C2%BA(º的编码)
  3. 删除%C2前缀,仅保留%BA
  4. 成功绕过过滤并执行open

其他可用字符

  1. 艺术字符:ℴ (U+2134)
  2. 上标字符:ᵒ (U+1D452)
  3. 其他样式变体字符

扩展攻击面

其他可绕过场景

  1. 艺术字符:视觉相似但编码不同

    • ℴ (U+2134) vs o
    • 某些字体下几乎无法区分
  2. 符号变形

    • º (U+00BA)在URL编码截断情况下可能被解析为a
    • 精心构造的编码截断可导致解析错误
  3. 组合字符

    • 使用基字符+组合标记构成的字符
    • 可能被规范化为基础字符

防御措施

  1. 规范化输入

    • 在处理前对输入进行Unicode规范化
    • 使用unicodedata.normalize()函数
  2. 严格字符白名单

    • 仅允许ASCII范围内的可打印字符
    • 拒绝所有变体字符
  3. 多重过滤层

    • 在规范化前后都进行检查
    • 使用正则表达式严格匹配关键字
  4. 上下文相关过滤

    • 不仅检查单个字符,还要检查字符组合
    • 考虑字符在特定上下文中的含义

结论

这种基于Unicode斜体字符的WAF绕过技术揭示了现代Web应用安全中的深层次问题。防御者需要理解Unicode规范化机制,并在安全设计中考虑字符编码的复杂性。同时,这种技术也可用于其他类似的模板注入场景,具有广泛的适用性。

WAF绕过技术:斜体字符与Unicode规范化攻击详解 引言 在XYCTF 2025比赛中出现了一道关于bottle框架注入的题目,其WAF绕过手段非常独特。本文将详细分析这种基于Unicode斜体字符的绕过技术,揭示其原理并提供实际应用方法。 题目背景分析 题目代码是一个简单的bottle应用,在 /attack 路由中: 用户输入的payload会被渲染 payload长度受限 过滤了 open 函数和反斜杠 \ 正常情况下的payload 若无限制,正常payload会使用 open 函数读取文件: 常见绕过尝试 开发者可能尝试使用其他函数如 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规范化机制,并在安全设计中考虑字符编码的复杂性。同时,这种技术也可用于其他类似的模板注入场景,具有广泛的适用性。