Slide 1

Slide 1 text

PHPerチャレンジ 解説LT サイボウズ株式会社 そが

Slide 2

Slide 2 text

PHPer チャレンジ、みなさんやっていますか︖ ▌「#{⽂字列}」な形式の PHPer トークンをたくさん⾒つけて、 スコアを稼ぐ企画 ▌今年はサイボウズから PHPer チャレンジ⽤の問題を出題しています https://blog.cybozu.io/entry/phperkaigi2023-sponser その問題の解説を⾏う LT です︕

Slide 3

Slide 3 text

出題&解説の⼈ ▌なまえ︓そが ▌会社︓サイボウズ株式会社 ▌仕事︓弊社製品 Garoon の開発チームで、 テクニカルサポート系 ▌PHP︓仕事柄、書くのは稀で読むことが多い

Slide 4

Slide 4 text

解説🔍

Slide 5

Slide 5 text

Step1 ▌まず、2種類のプログラムがあることを確認 n getPHPerToken.php n getKey.php ▌欲しいのは PHPer トークンなので、 まずは getPHPerToken.php を読んでみる

Slide 6

Slide 6 text

getPHPerToken.php , and of this program. * 2. The decrypt function does not work as expected for some reason. * This should be fixed. **/ $key1=; $key2=; $key3=; function decrypt(array $ciphertext, int $public_key, int $secret_key) { $hex = ""; foreach($ciphertext as $value) { $hex .= dechex($value ** $secret_key % $public_key); } $cleartext=hex2bin($hex); return $cleartext; } $ciphertext = [3181896, 6283063, 4748177, 3723679, 5707941]; $public_key = 8555851; $secret_key = ($key1 + $key2 * 2 + $key3 * 3) ** 2 * 2 ** 3 + $key2 * $key3 + $key2 + $key3 + 3; $cleartext=decrypt($ciphertext, $public_key, $secret_key); if(substr(md5($cleartext),0,30) === "97097d30ceb203d46ab08edf0308ba") { echo "PHPerToken is #" . $cleartext; } else { echo "Failed to get PHPerToken..."; }

Slide 7

Slide 7 text

getPHPerToken.php(冒頭) , and of this program. * 2. The decrypt function does not work as expected for some reason. * This should be fixed. **/ $key1=; $key2=; $key3=; PHPerToken を表⽰できるプログラムだ けど、事前に以下2つをやってね。 1.getKey.php からキーを3つ取得 2.decrypt 関数の修正

Slide 8

Slide 8 text

getPHPerToken.php(冒頭) , and of this program. * 2. The decrypt function does not work as expected for some reason. * This should be fixed. **/ $key1=; $key2=; $key3=; PHPerToken を表⽰できるプログラムだ けど、事前に以下2つをやってね。 1.getKey.phpからキーを3つ取得 2.decrypt 関数の修正 じゃあ、getKey.php を⾒てみよう

Slide 9

Slide 9 text

getKey.php

Slide 10

Slide 10 text

getKey.php

Slide 11

Slide 11 text

getKey.php

Slide 12

Slide 12 text

挙動変化の元ネタ ▌⽂字列と数値の⽐較 n https://www.php.net/manual/ja/migration80.incompatible.php#migration80.incompatible.core. string-number-comparision ▌ビットシフトや加算、減算に対する連結演算⼦の優先順位が変更 n https://www.php.net/manual/ja/migration80.incompatible.php#migration80.incompatible.core. other ▌継承したメソッド内で static 変数を使う n https://www.php.net/manual/ja/migration81.incompatible.php#migration81.incompatible.core. static-variable-inheritance

Slide 13

Slide 13 text

getKey.php の実⾏

Slide 14

Slide 14 text

getPHPerToken.php(冒頭) , and of this program. * 2. The decrypt function does not work as expected for some reason. * This should be fixed. **/ $key1=12; $key2=112; $key3=212; 取得した key1, key2, key3 を⼊れる

Slide 15

Slide 15 text

getPHPerToken.php(冒頭) PHPerToken を表⽰できるプログラムだ けど、事前に以下2つをやってね。 1.getKey.php からキーを3つ取得 2.decrypt 関数の修正 , and of this program. * 2. The decrypt function does not work as expected for some reason. * This should be fixed. **/ $key1=12; $key2=112; $key3=212; ࡁ

Slide 16

Slide 16 text

getPHPerToken.php(decrypt 関数) function decrypt(array $ciphertext, int $public_key, int $secret_key) { $hex = ""; foreach($ciphertext as $value) { $hex .= dechex($value ** $secret_key % $public_key); } $cleartext=hex2bin($hex); return $cleartext; } $ciphertext = [3181896, 6283063, 4748177, 3723679, 5707941]; $public_key = 8555851; $secret_key = ($key1 + $key2 * 2 + $key3 * 3) ** 2 * 2 ** 3 + $key2 * $key3 + $key2 + $key3 + 3; $cleartext=decrypt($ciphertext, $public_key, $secret_key); どこを直す必要が あるかな︖

Slide 17

Slide 17 text

getPHPerToken.php(decrypt 関数) function decrypt(array $ciphertext, int $public_key, int $secret_key) { $hex = ""; foreach($ciphertext as $value) { $hex .= dechex($value ** $secret_key % $public_key); } $cleartext=hex2bin($hex); return $cleartext; } $ciphertext = [3181896, 6283063, 4748177, 3723679, 5707941]; $public_key = 8555851; $secret_key = ($key1 + $key2 * 2 + $key3 * 3) ** 2 * 2 ** 3 + $key2 * $key3 + $key2 + $key3 + 3; $cleartext=decrypt($ciphertext, $public_key, $secret_key); 実際の処理を イメージしてみよう

Slide 18

Slide 18 text

getPHPerToken.php(decrypt 関数) function decrypt(array $ciphertext, int $public_key, int $secret_key) { $hex = ""; foreach($ciphertext as $value) { $hex .= dechex($value ** $secret_key % $public_key); } $cleartext=hex2bin($hex); return $cleartext; } $ciphertext = [3181896, 6283063, 4748177, 3723679, 5707941]; $public_key = 8555851; $secret_key = ($key1 + $key2 * 2 + $key3 * 3) ** 2 * 2 ** 3 + $key2 * $key3 + $key2 + $key3 + 3; $cleartext=decrypt($ciphertext, $public_key, $secret_key); $secret_key は なんだかデカい数が ⼊りそう

Slide 19

Slide 19 text

getPHPerToken.php(decrypt 関数) function decrypt(array $ciphertext, int $public_key, int $secret_key) { $hex = ""; foreach($ciphertext as $value) { $hex .= dechex($value ** $secret_key % $public_key); } $cleartext=hex2bin($hex); return $cleartext; } $ciphertext = [3181896, 6283063, 4748177, 3723679, 5707941]; $public_key = 8555851; $secret_key = ($key1 + $key2 * 2 + $key3 * 3) ** 2 * 2 ** 3 + $key2 * $key3 + $key2 + $key3 + 3; $cleartext=decrypt($ciphertext, $public_key, $secret_key); なんだかデカい数を 使った累乗計算 ※7桁の7桁乗

Slide 20

Slide 20 text

getPHPerToken.php(decrypt 関数) function decrypt(array $ciphertext, int $public_key, int $secret_key) { $hex = ""; foreach($ciphertext as $value) { $hex .= dechex($value ** $secret_key % $public_key); } $cleartext=hex2bin($hex); return $cleartext; } $ciphertext = [3181896, 6283063, 4748177, 3723679, 5707941]; $public_key = 8555851; $secret_key = ($key1 + $key2 * 2 + $key3 * 3) ** 2 * 2 ** 3 + $key2 * $key3 + $key2 + $key3 + 3; $cleartext=decrypt($ciphertext, $public_key, $secret_key); 64bit の範囲では、 正確な計算が 無理そう… ※7桁の7桁乗

Slide 21

Slide 21 text

decrypt 関数の修正⽅針 ▌最終的に出したいのは $public_key で割った余りなので、 合同式の計算の性質が利⽤できる︕ n 𝑎 ≡ b, c ≡ 𝑑 のとき 𝑎b ≡ 𝑐𝑑 $value ** $secret_key % $public_key

Slide 22

Slide 22 text

decrypt 関数の修正⽅針 ▌𝑎! ≡ 𝑥 (mod 𝑛) を次のように計算できる n 𝑎" ≡ 𝑚" n 𝑎# ≡ 𝑎𝑚" ≡ 𝑚# n 𝑎$ ≡ 𝑎𝑚# ≡ 𝑚$ n ・・・ n 𝑎! ≡ 𝑎𝑚!%& ≡ 𝑚! ≡ 𝑥

Slide 23

Slide 23 text

decrypt 関数の修正⽅針 ▌𝑎! ≡ 𝑥 (mod 𝑛) を次のように計算できる n 𝑎" ≡ 𝑚" n 𝑎# ≡ 𝑎𝑚" ≡ 𝑚# n 𝑎$ ≡ 𝑎𝑚# ≡ 𝑚$ n ・・・ n 𝑎! ≡ 𝑎𝑚!%& ≡ 𝑚! ≡ 𝑥 𝑎を1回かけるごとに逐⼀𝑛で割った余りを求めて いけば、⼤きすぎる数(𝑎!)の計算を回避できる︕

Slide 24

Slide 24 text

decrypt 関数の修正⼀案 foreach($ciphertext as $value) { $hex .= dechex($value ** $secret_key % $public_key); } for($i = 0; $i < count($ciphertext); $i++){ $value = 1; for ($count = 0; $count < $secret_key; $count++){ $value = $value * $ciphertext[$i] % $public_key; } $hex .= dechex($value); }

Slide 25

Slide 25 text

decrypt 関数の修正⼀案 foreach($ciphertext as $value) { $hex .= dechex($value ** $secret_key % $public_key); } for($i = 0; $i < count($ciphertext); $i++){ $value = 1; for ($count = 0; $count < $secret_key; $count++){ $value = $value * $ciphertext[$i] % $public_key; } $hex .= dechex($value); } 1回かけるたびに余りを 求める、を繰り返す

Slide 26

Slide 26 text

getPHPerToken.php(さいご) if(substr(md5($cleartext),0,30) === "97097d30ceb203d46ab08edf0308ba") { echo "PHPerToken is #" . $cleartext; } else { echo "Failed to get PHPerToken..."; } あとは実⾏するだけなので、 ぜひ⾃分の⼿で答えを確認してみてください︕

Slide 27

Slide 27 text

getPHPerToken.php の元ネタ ▌RSA 暗号です︕ ▌秘密鍵を計算するための⼿がかりを取得した後、 それを⽤いて RSA 暗号を解くというストーリーになっていました

Slide 28

Slide 28 text

こたえ✐ さっさと答え教えて︕という⽅向け

Slide 29

Slide 29 text

こたえ