テンプレートインジェクションとは
テンプレートエンジンはHTMLを描画する際に、その中のプレースホルダーを自動的に埋めることができる機能です。
これにより、サーバーサイドでレンダリングするタイプのWebサイトはPythonやNodeの値を直接HTMLに埋め込むことができます。
テンプレートインジェクションは、テンプレートエンジンがユーザーからの入力を適切にサニタイズせずに描画するときに発生するもので、
リモートコード実行につながる可能性があります。
リアルワールドバグハンティングによると、
テンプレートインジェクションはサーバーサイドとクライアントサイドの2種類が存在します。
テンプレートエンジンの具体例
テンプレートエンジンを使わずに FlaskのみでWebの描画を行おうとすると、以下のようなコードになります。
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
return "<h1>Hi, Flask!</h1>"
if __name__ == "__main__":
app.run(host="0.0.0.0", port=80, debug=True)
シンプルなサイトであればこちらでも問題ないですが、規模が大きくなるとビジネスロジックと描画を分ける必要性が出てきますが、
Pythonではこのようなケースで、 Jinja2
というライブラリが活躍します。
import random
from flask import Flask, render_template
from flask import request
app = Flask(__name__)
@app.route("/",methods=['GET', 'POST'])
def index():
query = 3
if request.method == 'GET':
query = request.args.get('query', '')
return render_template("index.html", query = query)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=80, debug=True)
上記のソースコードで、 index.html
のパスを指定し、ランダムな変数 rand_num
をテンプレートに渡しています。
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Flask</title>
<style>body {padding: 10px;}</style>
</head>
<body>
<h1>あなたがqueryパラメーターに入力したのは</h1>
<p>文字列 : {{query}}</p>
</body>
</html>
渡された変数 rand_num
テンプレートの構文 {{}}
によって描画することができます。
それだけでなく、 {% %}
構文によって比較を行うことも可能です。
このように、テンプレートエンジンによって描画部分とビジネスロジックを明確に分離することが可能です。
テンプレートエンジンを動かしてみる
上記のテンプレートエンジンのソースコードは次のリポジトリからお試しで実行できます。
git clone https://github.com/minegishirei/hacking_lab
テンプレートインジェクションの具体例
テンプレートエンジンでは、上記の通りデータを埋め込むために特定の構文を使って式を埋め込みますが、
外部からユーザーが入力した内容をそのままテンプレートに挿入すると、予期しないコードが実行されるリスクが生じます。
上記のテンプレートは正常な使い方なので問題ないですが、以下のように適切にサニタイズできないと危ないコードになります。
from flask import Flask, request
from jinja2 import Environment
app = Flask(__name__)
Jinja2 = Environment()
@app.route("/")
def page():
name = request.values.get('name')
output = Jinja2.from_string('Hello ' + name + '!').render()
return output
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80)
通常の使い方であれば、 GETのnameパラメーターに自分の名前を入れると思います。
http://localhost/?name=minegishi
と入力するとHello yamada!
と出力されます。
Jinjaをターゲットとしたテンプレートインジェクションでは、{{7*7}}
を入力して、49が出るかどうかを確認するのがよさそうです。
http://localhost/?name={{7*7}}
tplmapのセットアップ
tplmapはgithubのソースコードで、docker-compse
を使用することで起動できます。
git clone https://github.com/epinna/tplmap.git
cd tplmap
cd docker-envs
docker-compose up
page:https://minegishirei.hatenablog.com/entry/2024/11/01/201520