语法混淆漏洞

语法混淆漏洞:指系统中的两个或多个组件因语法规则的模糊或不一致而以不同方式解释同一输入时所发生的现象。

文件上传漏洞的经典案例

在 HTML 表单中上传文件时,即enctype="multipart/form-data"的请求中,上传文件通常包含如下字段:

1
Content-Disposition: form-data; name="file"; filename="example.txt"

为了支持非 ASCII 的字符,filename参数也可以表示为:

1
Content-Disposition: form-data; name="file"; filename*=UTF-8''example%2Etxt

在这里,filename*=UTF-8''example%2Etxtfilename="example.txt"是等价的:

  • filename*:扩展参数名。
  • UTF-8’’:表示字符编码为 UTF-8,语言标签为空。
  • %2E:URL 编码的点号(.)。

许多开发者只检查filename字段,而忽略filename*,或者仅对一种格式做安全校验(如路径遍历过滤、黑名单扩展名检查等)。这就导致攻击者可通过使用filename*绕过基于 filename的安全策略,这就是一个常见的文件上传漏洞绕过例子。

C++二字符组

一段代码:

1
2
3
4
5
6
// %: == #
%:include <stdio.h>
int main() {
printf("test!\n")
return 0;
}

这里%:会被编译器静默转换成#,这是因为由于历史上某些键盘或字符编码系统(如ISO 646的某些国家变体)不支持#字符。为了解决这个问题,C 和 C++ 标准引入了三字符组和二字符组:

类型 替代序列 等价字符
Trigraph ??= #
Trigraph ??/ \
Trigraph ??' ^
Trigraph ??( [
Trigraph ??) ]
Trigraph ??! `
Trigraph ??< {
Trigraph ??> }
Trigraph ??- ~
Digraph <% {
Digraph %> }
Digraph <: [
Digraph :> ]
Digraph %: #

三字符组在C++17以后没了,但是二字符组到现在还可以用。

作者挖漏洞的流程

  1. 生成语义等价的变体。
  2. 观察每一跳的标准化行为:依次分析请求在浏览器、CDN、WAF/代理、Web 服务器、应用框架、解析库等各组件中的处理差异,识别因解析不一致导致的分歧点。
  3. 故意触发错误路径(fuzz),比如::99999999999999999999%3A%30%30%30%34%34%33
  4. 收集证据:分析原始请求和响应,寻找差异来检测意外行为。

其实我理解就是fuzz。

Python和Perl的例子

其实就是unicode编码,举个例子:

1
print("\N{LATIN CAPITAL LETTER A}") 

输出就是:

1
A

使用\N{名称},编程语言会在内部查找该名称对应的 Unicode 码点,并将其转换为实际字符。

sudo的例子