# [Web] ziperatops - Cake CTF 2021 ###### tags: `CakeCTF 2021` 一見して`.zip.php`などとすると`.php`のファイルをアップロードできそう。すると任意コードが実行できそう? ```php= /* Check extension */ if (preg_match('/^.+\.zip/', $filename, $result) !== 1) return array($dname, "Invalid extension (Only .zip is allowed)"); ``` ただしそう簡単にはいかなくて、一つはそれが`ZipArchive->open`できるかというチェックが存在する。こちらはzipのコメントにPHPのコードを入れるとか、zipのあとにphpのコードを足すとかでもvalidにできるのであまり記にしなくて良い ```php= /* Check the uploaded zip file */ $zip = new ZipArchive; if ($zip->open($tmpfile) !== TRUE) return array($dname, "Invalid file format"); ``` もう一つはファイルが設置されるディレクトリがランダムになっているという点 ```php= /* Create a working directory */ $dname = sha1(uniqid()); @mkdir("temp/$dname"); // ...snip... /* Move the files */ if (@move_uploaded_file($tmpfile, "temp/$dname/$filename") !== TRUE) return array($dname, "Failed to upload the file: $dname/$filename"); ``` さらにもう一つ、ファイルがすぐに`cleanup`されてしまう点 ```php= /** * Remove a directory and its contents */ function cleanup($dname) { foreach (glob("temp/$dname/*") as $file) { @unlink($file); } @rmdir("temp/$dname"); } ``` したがって、ファイルが削除されてしまうことを避けつつ、`move_uploaded_file`が失敗するようなファイルをアップロードして、エラーメッセージからディレクトリ名を知る必要がある まず `move_uploaded_file` が失敗するようなケースだが、多くのファイルシステムではファイル名の最大長は`255`バイト(文字?)になっており、それ以上の長さのファイルを作成しようとしても失敗する。したがってアップロードするファイルのファイル名をそれ以上にしようとすれば良い 続いて`cleanup`で削除されないようなファイルだが、`glob`では`.`から始まるいわゆる隠しファイルはリストアップされない。したがって`unlink`の対象にならずファイルは残り、空のディレクトリでないので`rmdir`も失敗する すなわち - `.hogehoge.zip.php` のようなファイル - `hogehoge.zip`だが`'a'*256 + '.zip'`という名前でアップロードされるファイル をアップロードすればphpファイルを安全にアップロードでき、任意コードを実行できる