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".