利用Base64编码不规范特性绕过WAF的技术分析
1. Base64编码基础
Base64编码是一种将二进制数据转换为ASCII字符的编码方式,基本原理是将3个字节(24bit)的数据分割为4个6bit的部分,每个6bit部分对应一个Base64字母表中的字符。
标准Base64字母表:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
当数据长度不足3字节时,使用=作为填充字符(padding):
- 剩余1字节:补2个
= - 剩余2字节:补1个
=
2. WAF拦截机制分析
Web应用防火墙(WAF)对Base64编码数据的拦截主要有两种方式:
-
直接匹配编码数据:不进行解码,直接匹配Base64编码后的特征
- 例如匹配
QGluaV9zZXQo(即ini_set(的Base64编码)
- 例如匹配
-
解码后匹配:先解码Base64数据,再匹配解码后的特征
- 例如直接匹配
ini_set(关键字
- 例如直接匹配
3. Base64解码器差异性分析
测试了5种常见语言的Base64解码实现:
- PHP:
base64_decode() - Python:
base64.b64decode() - Go:
encoding/base64.StdEncoding.DecodeString() - Java1:
java.util.Base64.getDecoder().decode() - Java2:
sun.misc.BASE64Decoder().decode()
3.1 换行符处理
测试数据:dG\nVzdA== (标准编码dGVzdA==中插入换行符)
| 解码器 | 结果 |
|---|---|
| PHP | 成功解码为"test" |
| Python | 成功解码为"test" |
| Go | 成功解码为"test" (仅支持\r\n) |
| Java1 | 报错 |
| Java2 | 解码失败 |
绕过应用:在Base64数据中插入换行符,可能使部分WAF解码失败而绕过检测,而后端PHP/Python仍能正常解码。
3.2 非字母表字符处理
测试数据:dG~-VzdA== (插入非Base64字母表字符~-)
| 解码器 | 结果 |
|---|---|
| PHP | 成功解码为"test" (忽略非字母字符) |
| Python | 成功解码为"test" (忽略非字母字符) |
| Go | 报错 |
| Java1 | 报错 |
| Java2 | 解码失败 |
绕过应用:插入非字母表字符可使严格遵循RFC的解码器失败,而PHP/Python仍能正常解码。
3.3 Padding不足处理
测试数据:dGVzdA (缺少2个=填充)
| 解码器 | 结果 |
|---|---|
| PHP | 成功解码为"test" |
| Python | 报错 |
| Go | 报错 |
| Java1 | 成功解码为"test" |
| Java2 | 解码失败 |
绕过应用:去除必要的padding可能使部分WAF解码失败,而后端PHP/Java1仍能正常解码。
3.4 Padding过多处理
测试数据:dGVzdA=== (多1个=)
| 解码器 | 结果 |
|---|---|
| PHP | 成功解码为"test" |
| Python | 成功解码为"test" |
| Go | 报错 |
| Java1 | 报错 |
| Java2 | 成功解码为"test" |
3.5 Padding后增加数据
测试数据:dGVzdA==dGVzdA== (padding后追加相同编码)
| 解码器 | 结果 |
|---|---|
| PHP | 解码为"testFW7@" (异常) |
| Python | 解码为"test" (忽略padding后数据) |
| Go | 报错 |
| Java1 | 报错 |
| Java2 | 解码为"testtest" |
绕过应用:构造形如dGVzdA==payload的数据,WAF可能只解码前部分无害数据,而后端解码完整payload。
4. 绕过WAF的具体技术
基于上述解码器差异,可总结以下绕过技术:
-
插入换行符:在Base64数据中插入
\n或\r\n- 适用场景:WAF使用Java1/Go等严格解码器,后端使用PHP/Python
-
插入非字母字符:在Base64数据中插入
~!@#$等非字母表字符- 适用场景:WAF使用严格解码器,后端使用PHP/Python
-
减少padding:去除必要的
=填充字符- 适用场景:WAF使用Python/Go等,后端使用PHP/Java1
-
增加padding:添加多余的
=字符- 适用场景:WAF使用严格解码器,后端使用PHP/Python/Java2
-
padding后追加数据:在padding后追加有效payload
- 适用场景:WAF类似Python会忽略后续数据,后端类似Java2会完整解码
5. 防御建议
- 统一解码标准:前后端使用相同Base64解码实现
- 严格校验:拒绝包含非字母字符、换行符的Base64数据
- padding检查:验证padding数量是否正确
- 多层检测:同时检测编码前后数据
- 规范化处理:解码前先去除非常规字符并修复padding
6. 参考
- RFC4648: Base64编码规范
- 各语言Base64解码实现源码分析