TCPサーバの接続情報と、サーバのプログラム server.py が与えられた。
server.py は以下のような処理をするものだった。
pと定数g = 5を用意し、出力する。aを用意する。gのa乗をpで割った余りAを計算し、出力する。1より大きくp - 1未満の整数Bを入力させる。Bのa乗をpで割った余りshared_secretを計算する。shared_secretをlong_to_bytesで変換したデータのSHA-1ハッシュの先頭16バイトを鍵として、FLAGをAES.MODE_ECBで暗号化し、出力する。
shared_secretの計算には、B ^ a === (g ^ b) ^ a === g ^ (ab) (mod p) というコメントがついていた。
この計算を進めると、g ^ (ab) === (g ^ a) ^ b === A ^ b (mod p) となる。
すなわち、適当な数bを用意し、gをb乗してpで割った余りをBとして送信すると、
Aをb乗してpで割ることでshared_secretの値を求めることができる。
サーバに接続すると、例えば以下が出力された。
Information to connect to a TCP server, and a program for the server server.py were given.
What server.py does is:
p and a constant value g = 5, and print them.a.g to the a-th power modulo p as A, and print that.B, which is greater than 1 and less than p - 1.B to the a-th power modulo p as shared_secret.FLAG with AES.MODE_ECB using the first 16 bytes of the SHA-1 hash value of shared_secret converted via long_to_bytes as the key, and print the result.
There was a comment B ^ a === (g ^ b) ^ a === g ^ (ab) (mod p) for the calculation of shared_secret.
Proceeding this calculation yields g ^ (ab) === (g ^ a) ^ b === A ^ b (mod p).
This means that we can obtain the value of shared_secret by calculating A to the b-th power modulo p
after preparing some random value b and sending g to the b-th power modulo p as B.
For an example, this was printed after connecting to the server:
これに対し、Pythonのインタラクティブを用いて以下のようにBとして送信する値を計算できる。
なお、接続が切れる前にBを送信できるよう、gやbの値はサーバに接続する前に用意しておくとよい。
Seeing this, we can calculate the value to send as B using the interactive mode of Python like this.
You should prepare the values of g and b before connecting to the server to make it easier to send B before the connection gets closed.
ここで求めたBの値を送信すると、サーバから以下の出力がされた。
Sending the value of B obtained here, the server sent this:
Pythonのインタラクティブを用い、Bを求めた続きでshared_secretの値を求める。
Then, calculate the value of shared_secret using the interactive mode of Python after obtaining the value of B.
得られたshared_secretの値を
After that, put the calculated value of shared_secret to
From Hex, SHA1, Take bytes - CyberChef
これで暗号化の鍵が求まったが、このままサーバから出力されたciphertextをCyberChefの AES Decrypt で複号しようとすると、「Unable to decrypt input with these parameters.」と出てしまう。
これは、(現在の)CyberChefの AES Decrypt のECBモードではパディングの使用が強制されるためである。
そこで、まず空文字列をこの鍵で暗号化し、パディングのブロックを得る。
ECBモードは各ブロックを独立して暗号化する方式なので、ciphertextのデータは不要である。
Now I got the encryption key, but simply trying to decrypt the ciphertext sent from the server using "AES Decrypt" on CyberChef results in "Unable to decrypt input with these parameters.".
This is because using padding is forced in the ECB mode of "AES Decrypt" of (current) CyberChef.
To overcome this, firstly we should encrypt an empty string with this key to obtaine a padding block.
The ciphertext is not needed here because each blocks are encrypted independently in the ECB mode.
ciphertextの後ろに得られたパディングのブロックを追加し、AES Decrypt を行うと、flagが得られた。
I obtained the flag by adding the obtained padding block after the ciphertext and applying "AES Decrypt".