CTF之路:关于Flask模板注入

CTF之路:关于Flask模板注入,第1张

CTF之路:关于Flask模板注入 1.题目

题目叫Simple SSTI
打开网页,显示.
SSTI,即服务器端模板注入。

2.知识点

flask基础

在学习SSTI之前,先把flask的运作流程搞明白。这样有利用更快速的理解原理。
路由

先看一段代码

from flask import flask
@app.route(’/index/’)
def hello_word():
return ‘hello word’

route装饰器的作用是将函数与url绑定起来。例子中的代码的作用就是当你访问http://127.0.0.1:5000/index的时候,flask会返回hello word。

渲染方法

flask的渲染方法有render_template和render_template_string两种。
render_template()是用来渲染一个指定的文件的。使用如下
return render_template(‘index.html’)
render_template_string则是用来渲染一个字符串的。SSTI与这个方法密不可分。

使用方法如下

html = 'This is index page'
return render_template_string(html)

模板

flask是使用Jinja2来作为渲染引擎的。看例子

在网站的根目录下新建templates文件夹,这里是用来存放html文件。也就是模板文件。

test.py

from flask import Flask,url_for,redirect,render_template,render_template_string
@app.route('/index/')
def user_login():
    return render_template('index.html')

/templates/index.html

This is index page

访问127.0.0.1:5000/index/的时候,flask就会渲染出index.html的页面。

模板文件并不是单纯的html代码,而是夹杂着模板的语法,因为页面不可能都是一个样子的,有一些地方是会变化的。比如说显示用户名的地方,这个时候就需要使用模板支持的语法,来传参。

例子

test.py

from flask import Flask,url_for,redirect,render_template,render_template_string
@app.route('/index/')
def user_login():
    return render_template('index.html',content='This is index page.')

/templates/index.html

{{content}}

这个时候页面仍然输出This is index page。

{{}}在Jinja2中作为变量包裹标识符。

模板注入

不正确的使用flask中的render_template_string方法会引发SSTI。那么是什么不正确的代码呢?

xss利用

存在漏洞的代码

@app.route('/test/')
def test():
    code = request.args.get('id')
    html = '''
        %s
    '''%(code)
    return render_template_string(html)

这段代码存在漏洞的原因是数据和代码的混淆。代码中的code是用户可控的,会和html拼接后直接带入渲染。

尝试构造code为一串js代码。

将代码改为如下

@app.route('/test/')
def test():
    code = request.args.get('id')
    return render_template_string('{{ code }}',code=code)

继续尝试

可以看到,js代码被原样输出了。这是因为模板引擎一般都默认对渲染的变量值进行编码转义,这样就不会存在xss了。在这段代码中用户所控的是code变量,而不是模板内容。存在漏洞的代码中,模板内容直接受用户控制的。

模板注入并不局限于xss,它还可以进行其他攻击。
SSTI文件读取/命令执行

基础知识

在Jinja2模板引擎中,{{}}是变量包裹标识符。{{}}并不仅仅可以传递变量,还可以执行一些简单的表达式。

这里还是用上文中存在漏洞的代码

@app.route('/test/')
def test():
    code = request.args.get('id')
    html = '''
        %s
    '''%(code)
    return render_template_string(html)

构造参数{{2*4}},结果如下

可以看到表达式被执行了。

在flask中也有一些全局变量。

3.解析

结合两个提示点
You need pass in a parameter named flag.
You know, in the flask, We often set a secret_key variable.
尝试传参flag={{2*3}}

猜测config里可能有一个变量SECRET_KEY(config里所有变量都是大写)

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5701571.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-18
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存