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.