It's obvious, but can you bypass it to win the reward?
Author: BerlianGabriel
Kita diberikan sebuah URL webite dan source code dari webappnya.
Berikut adalah kode utama dari website (app.py).
from flask import Flask, request, render_template, render_template_string
import re
app = Flask(__name__)
# Filter returns True if there is some pesky intruder
def filter(data):
blacklist_words = ['.', '[', ']', '{{', '}}', '"', 'os', 'modules', 'base', 'import', 'application', 'builtins', "*"]
additional_check = ['_', '__']
additional_check = re.compile('|'.join(map(re.escape, additional_check)))
for word in blacklist_words:
if word in data:
return True
return additional_check.match(data)
@app.route("/")
def index():
title = request.args.get('title', 'Your title', type=str)
content = request.args.get('content', "Multiple lines of text that form the lede, informing new readers quickly and efficiently about what's interesting in the content", type=str)
if filter(title) or filter(content):
title = "Oops..."
content = "Nice try, but you got blocked by our super secure filtering"
try:
title = render_template_string(title)
content = render_template_string(content)
except Exception:
title = "Error"
content = "Ouch! Some error has occured"
return render_template("index.html", title=title, content=content)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8888, debug=False)
Pada website ini, kita bis meng-custom title dan content-nya menggunkan GET request. Misalnya, berikut adalah hasil render dari http://103.163.139.198:8888/?title=h4cked&content=payload .
Kerentanan web ini adalah pada kode template HTML-nya yang menonaktifkan fitur bawaan 'safe' dari Jinja2. Dengan begini, syntax dari Jinja dan HTML akan di-render benar-benar seadanya, sehingga kita bisa melakukan serangan SSTI (Server Side Template Injection).
Untungnya, web ini masih menyiapkan filter sehingga syntax yang berpotensi digunakan untuk menyerang web akan di-block. Walaupun begitu, dengan filter seperti ini pun, masih ada beberapa cara untuk membypass-nya.
def filter(data):
blacklist_words = ['.', '[', ']', '{{', '}}', '"', 'os', 'modules', 'base', 'import', 'application', 'builtins', "*"]
additional_check = ['_', '__']
additional_check = re.compile('|'.join(map(re.escape, additional_check)))
for word in blacklist_words:
if word in data:
return True
return additional_check.match(data)
Misalnya, untuk membypass string seperti os, kita bisa menggunakan payload ''.join(['o','s']) . Oh, karakter . juga di-block? Gampang, untuk mengakses atribut dari sebuah objek di Jinja, kita bisa gunakan Object | attr('nama_atribut'), sehingga payloadnya akan menjadi '' | attr('join')([ . Apa? [ dan ] juga di-block? Tenang, atribut join() tidak hanya menerima list, tapi juga tuple, sehingga payloadnya bisa dibuat menjadi '' | attr('join')(('o','s')) .
Dalam serangan SSTI, biasanya tujuan utama kita adalah untuk menjalankan atribut popen , karena dengan itu, kita bisa menjalankan sebagian besar system command yang kita butuhkan. Pada payload di bawah ini, saya mencoba menjalankan ls .
Nah, kalau sudah bekerja seperti ini, tinggal ganti saja commandnya menjadi cat reward/flag.txt tapi karena karakter . di-block, payloadnya perlu kita sesuaikan menjadi '' | attr('join')(('cat reward/flag','\x2e','txt')). Berikut adalah payload akhir yang akan memberikan kita flag-nya.
Berikut write-up dari tim lainnya pada soal yang sama, yang menurut saya bagus untuk sumber belajar:
Intinya, untuk mengerjakan soal ini, kita perlu mencari cara-cara kreatif untuk mencapai tujuan yang sama dengan cara yang berbeda. Selama mengerjakan soal ini, saya merujuk pada .