TCPサーバの接続情報と、サーバのプログラム treasure.py が与えられた。
このプログラムは、以下の処理をするものであった。
REAL_COORDS、および既知の値FAKE_COORDSとpを用意する。r1, r2を用意する。shares[0] = r1*r2*REAL_COORDS mod pの値を出力する。s1の入力を受け付け、secret = s1^3 / (r1^3 * r2^3 * REAL_COORDS^2) mod p の値を出力する。secretがある条件を満たした場合は、終了する。s1の入力を受け付ける。s1について、s1^3 / (r1^3 * r2^3 * REAL_COORDS^2) mod pの値がFAKE_COORDSでなければ終了する。REAL_COORDSなら、flagを含むデータを出力する。
最初のs1としてshares[0]の値をそのまま入力すると、
REAL_COORDSの値が出力され、終了した。
これを数回繰り返した結果、REAL_COORDSの値は固定のようだった。
そこで、s1^3にFAKE_COORDS / REAL_COORDS (mod p)の値を掛ければ、
s1^3 / (r1^3 * r2^3 * REAL_COORDS^2) mod pの値をFAKE_COORDSにすることができる。
すなわち、s1にFAKE_COORDS / REAL_COORDS (mod p)の3乗根を掛ければよい。
剰余を取る場合の3乗根の求め方を調べたところ、以下のページが見つかった。
Information to connect to a TCP server and a program for the server treasure.py were given.
What the program does is:
REAL_COORDS, and public values FAKE_COORDS and p.r1, r2.shares[0] = r1*r2*REAL_COORDS mod p.s1, and output the value of secret = s1^3 / (r1^3 * r2^3 * REAL_COORDS^2) mod p.secret satisfies a condition.s1 again.s1, exit if the value of s1^3 / (r1^3 * r2^3 * REAL_COORDS^2) mod p is not FAKE_COORDS.REAL_COORDS, output some data that contains the flag.
Entering the value of shares[0] without modifying as the first s1, it printed the value of REAL_COORDS and exited.
Repeating this several times, I found the the value of REAL_COORDS looks fixed.
Now, we can make the value of s1^3 / (r1^3 * r2^3 * REAL_COORDS^2) mod p to be FAKE_COORDS
by multiplying the value of FAKE_COORDS / REAL_COORDS (mod p) to s1^3.
In other words, we should multiply the cube root of FAKE_COORDS / REAL_COORDS (mod p) to s1.
I searched for how to calculate cube roots under modulo, and found this page:
python - Cube root modulo P -- how do I do this? - Stack Overflow
pの値は素数であった。
さらに、pを3で割ると2余ったので、このページよりaの3乗根はpow(a,(2*p - 1)/3, p)となることがわかる。
最初の入力は、0を入力することで処理を続行させることができた。
2番目の入力は、出力されたshares[0]にFAKE_COORDS / REAL_COORDS (mod p)の3乗根を掛け、pで割った余りを入力する。
最後に、REAL_COORDSの値をそのまま入力すると、flagが得られた。
Checking on p is a prime number.
I also found that p modulo 3 is 2, so the cube root of a becomes pow(a,(2*p - 1)/3, p), according to the page.
I succeeded to have it proceed by entering 0 as the first input.
For the second input, I use "the cube root of FAKE_COORDS / REAL_COORDS (mod p)" times shares[0] modulo p.
Finally, I entered the value of REAL_COORDS and obtained the flag.