CTF 中常见 Python 题型 SSTI

CTF中Python类题目算是我的苦手,每次看到Python相关就头大,但是大四为了多拿点奖项,必须啃硬骨头,先学一手SSTI.
SSTI
SSTI即服务端模板注入攻击,服务端接受用户输入,将其作为Web应用模板的一部分,渲染编译后执行了恶意内容,导致敏感信息泄露、代码执行等。
我们从Flask
入手,代码是重中之重,所以很有必要去读一下它的文档
来个demo:
from flask import Flask, render_template_string
app = Flask(__name__)
@app.route('/<name>')
def index(name):
template = '<h1>Hello {}!</h1>'.format(name)
return render_template_string(template)
if __name__ == '__main__':
app.run()
将用户输入的字符串渲染进模板中,如果有恶意输入就凉凉,测试一下:4
可以看到表达式字符串被解析执行了,这个就很类似于struts 2
曾经出的那些漏洞,也是表达式被解析执行导致可以执行代码。
按这张图可以测试出具体是什么模板引擎:
以TokyoWesterns CTF的一道题shrine为例,页面中给出源码:
import flask
import os
app = flask.Flask(__name__)
app.config['FLAG'] = os.environ.pop('FLAG')
@app.route('/')
def index():
return open(__file__).read()
@app.route('/shrine/')
def shrine(shrine):
def safe_jinja(s):
s = s.replace('(', '').replace(')', '')
blacklist = ['config', 'self']
return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s
return flask.render_template_string(safe_jinja(shrine))
if __name__ == '__main__':
app.run(debug=True)
可以看到有拼接字符串再渲染的过程,但是有过滤函数,将圆括号替换为空,黑名单词汇有config和self两个。
flag是在配置里,如何读取呢?
本来可以直接输入,如下:
但是有黑名单,所以就要用到Python的魔术方法。
魔术方法
__class__ #返回type类型,查看对象的类型
__bases__ #返回tuple类型,列出该类的基类
__mro__ #返回tuple类型,给出解析方法调用的顺序
__subclasses__() #返回内建方法builtin_function_or_method,获取一个类的子类
__globals__ #返回dict类型,对函数进行操作,获取当前空间下能使用的模块、方法、变量,
利用思路一般是先多获取基类,在获取其子类,之后寻找重载过的init类,再用builtins查看引用,最后在其中寻找可利用的函数。
来看我们第一个demo,假设我们要读取本地的一个文件,尝试构造利用链。
- 获取基类,这里要看清楚第几个是object类,Python2与Python3的个数不同,例子使用的是Python3
''.__class__.__mro__
- 获取object的子类
''.__class__.__mro__[1].__subclasses__()
- 寻找重载过的init类,即其中不包含wrapper字样,可以用循环输出所有的:
for i in range(0, len(''.__class__.__mro__[1].__subclasses__())): print(''.__class__.__mro__[1].__subclasses__()[i].__init__)
- 查看其引用
这里返回的是字典,在字典的keys里寻找可用的函数,如eval、file等。''.__class__.__mro__[1].__subclasses__()[134].__init__.__globals__['__builtins']
上面那道题因为flag在配置信息里,所以就
Author: 白袍
Link: https://eviladan0s.github.io/2020/09/05/py...
本作品采用《CC 协议》,转载必须注明作者和本文链接