diff options
Diffstat (limited to 'services/nuldoc/content/posts/2025-01-08')
| -rw-r--r-- | services/nuldoc/content/posts/2025-01-08/phperkaigi-2023-tokens-q1.md (renamed from services/nuldoc/content/posts/2025-01-08/phperkaigi-2023-tokens-q1.dj) | 46 |
1 files changed, 14 insertions, 32 deletions
diff --git a/services/nuldoc/content/posts/2025-01-08/phperkaigi-2023-tokens-q1.dj b/services/nuldoc/content/posts/2025-01-08/phperkaigi-2023-tokens-q1.md index c3a5eb4..407e558 100644 --- a/services/nuldoc/content/posts/2025-01-08/phperkaigi-2023-tokens-q1.dj +++ b/services/nuldoc/content/posts/2025-01-08/phperkaigi-2023-tokens-q1.md @@ -18,10 +18,9 @@ remark = "公開" date = "2025-01-11" remark = "読みやすさのため一部の文言を調整" --- -{#intro} -# はじめに +# はじめに {#intro} -::: note +:::note これは PHPerKaigi 2023 の記事です。今は 2025 年ですが、PHPerKaigi 2023 の記事です。 ::: @@ -42,15 +41,13 @@ PHPerKaigi 当日も [PHPer チャレンジ解説セッション](/slides/2023-0 それぞれの問題はこちらの GitHub リポジトリ ( [nsfisis/PHPerKaigi2023-tokens](https://github.com/nsfisis/PHPerKaigi2023-tokens) ) からも閲覧できる。 -{#quiz} -# Q1: An Art of Computer Programming +# Q1: An Art of Computer Programming {#quiz} 第1問『An Art of Computer Programming』はこちら。  -{#how-to-solve} -# 解き方 +# 解き方 {#how-to-solve} まずはトークンを得る方法を解説抜きで説明する。次のように実行する。 @@ -60,11 +57,9 @@ $ echo "#iwillblog" | php Q1.png >/dev/null 無事に実行できていれば「#ModernPHPisStaticallyTypedLanguage」というトークンが得られる。 -{#commentary} -# 解説 +# 解説 {#commentary} -{#read-as-image} -## 画像として解釈する +## 画像として解釈する {#read-as-image} まずは素直に画像として見てみよう。 全体は QR コードになっている。適当な QR コードリーダで読み込むと、次のようなテキストが表示されるはずだ。 @@ -78,8 +73,7 @@ Guess password. $ echo "password" | php Q1.png >/dev/null 次に QR コードの中央部に目を向けると、小さな文字で「Password is one of the PHPer tokens.」と書かれているのがわかる。 他の PHPer トークンの中から適切な1つを見つけだし、「パスワード」として渡すことで答えとなる PHPer トークンが得られるというわけだ。 -{#password} -## パスワード +## パスワード {#password} 不正なパスワードを使って実行してみると、次のようなエラーメッセージが表示される。 @@ -99,8 +93,7 @@ $ echo "foo" | php Q1.png >/dev/null 問題を置いていたリポジトリにヒントとしてパスワードのトークンが「i」で始まると書いていたのだが、これが意図せずミスリードになってしまった。 これは私のミスである。 -{#png-steganography} -## PNG ステガノグラフィ +## PNG ステガノグラフィ {#png-steganography} QR コードも言っているように、このファイルは PNG 画像であるにもかかわらず PHP で実行することができる。なぜこのようなことが可能なのか。 @@ -122,8 +115,8 @@ CLI で実行する場合、PHP タグよりも前にあるデータは標準出 1. PNG ヘッダ (`IHDR` チャンク) 1. 実際の画像データ (`IDAT` チャンク) 1. PNG フッタ (`IEND` チャンク) -1. *PHP タグ (`<?php`)* -1. *通常の PHP ソースコード* +1. **PHP タグ (`<?php`)** +1. **通常の PHP ソースコード** PNG ファイルとして読むときは PNG フッタ以降は無視され、PHP スクリプトとして読むときは PHP タグ以前が無視されるという仕掛けである。 @@ -155,8 +148,7 @@ Guess password. $ echo "password" | php Q1.png >/dev/null なお、このように PNG 画像などに本来のデータとは異なる別のデータを隠すことを「ステガノグラフィ」( [Wikipedia「ステガノグラフィー」](https://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%86%E3%82%AC%E3%83%8E%E3%82%B0%E3%83%A9%E3%83%95%E3%82%A3%E3%83%BC) ) と呼ぶ。 -{#php-program} -## 実行される PHP プログラム +## 実行される PHP プログラム {#php-program} 画像の正体がわかったところで、画像に隠されていた PHP プログラムについて見ていこう。 先ほどは一部しか記載しなかったので、全体を載せる。 @@ -282,8 +274,7 @@ $b = unpack('C*', file_get_contents(__FILE__)); そう、今回の問題の画像ファイル `Q1.png` は、PHP 製 Piet インタプリタであると同時に、Piet のソースコード画像でもあるのだ。 QR コード中央のカラフルな部分が Piet の命令になっている。 -{#piet-source-code} -## Piet のソースコード +## Piet のソースコード {#piet-source-code} さて、Piet でどのようなコードが書かれて (いや、描かれて) いるのかを解説したいところだが、今の私にはできそうにない。 というのも、すでに述べたように Piet は「難解プログラミング言語」である。 @@ -293,19 +284,12 @@ QR コード中央のカラフルな部分が Piet の命令になっている それぞれの部分はおおよそ次のようなことをやっている (再検証・再読解はしていないので大嘘かもしれない)。 * 左上: 入力受け付け - * 標準入力から1文字ずつ読み込み、入力がなくなるまでスタックに積む。多分。 - * 上辺、右辺: パスワードの検証 - * 入力がパスワードと一致するか (= `#iwillblog` かどうか) を調べる。多分。 - * 下辺、左辺、上辺の3列目、右辺の3列目、下辺の2列目: トークンの出力 - * パスワードと一致していればここに飛んでくる。正解のトークンを出力する。多分。 - * 右辺の2列目、上辺の2列目: 不正解のメッセージ出力 - * パスワードと一致していなければここに飛んでくる。不正解のときのメッセージを出力する。多分。 ところで、先ほど掲載した Piet のインタプリタのソースコード末尾には次のような箇所がある。 @@ -329,8 +313,7 @@ fwrite(STDERR, str_replace('403 Forbidden', '401 Unauthorized', $o)); これを解決するために私が選んだのは、インタプリタを改造し、本来のメッセージとは異なるメッセージを無理やり出力させて帳尻を合わせることだった。 そういうわけでこの Piet インタプリタは完全な Piet インタプリタではなく、「403 Forbidden」というテキストを絶対に出力できない。 -{#misc} -## その他小ネタ +## その他小ネタ {#misc} ここまでで問題の核心部分は説明し終えたので、ここからは残った小ネタを紹介しておく。 @@ -338,8 +321,7 @@ fwrite(STDERR, str_replace('403 Forbidden', '401 Unauthorized', $o)); この問題で得られるトークン「#ModernPHPisStaticallyTypedLanguage」は特に元ネタがあるわけではない。当然のような顔で嘘を主張したかったのでこうなった。 -{#outro} -# おわりに +# おわりに {#outro} この問題の自己評価はこちら。 問題の出題順はおおよそ作成した順になっているのだが、そのせいで難易度高めの問題が1問目に配置されてしまった。 |
