AlexCTF 2017 write up
チーム yharima で参加したので、write up を書いておく。 暗号ばっかり解いていた。
CR2
問題文を読むと、one time pad を使ったけど one time と呼ばれる意味が分かっていない、的なことが書いてあったので、鍵が使いまわされているんだろうなあと予想。
one time pad といっても色々あるらしいのだが、XORで暗号文を作ると予想して、次のリンクにある通り解読を試みた。
http://crypto.stackexchange.com/questions/59/taking-advantage-of-one-time-pad-key-reuse/64
鍵をK
、平文をT
としたときに、暗号文C
は鍵と平文の XOR をとったもの。
C = K ⊕ T
同じ鍵の暗号文が複数用意されている (C1
, C2
) とき、暗号文どうしの XOR をとると、鍵の影響を排除できる。
C1 = K ⊕ T1 C2 = K ⊕ T2 C1 ⊕ C2 = (K ⊕ T1) ⊕ (K ⊕ T2) = T1 ⊕ T2
C1 ⊕ C2
に対し、平文に入っていそうな単語で適当な位置のXORをとってみて、結果が読める文になるところを探す。見つかった場合、その部分の平文が明らかになったことになる。ただし、元の単語と XOR の結果のどちらが C1
に含まれるのかはわからない。
問題のテキストは 11 行になっていたので、hex から byte に変換してから、適当な2行を選んで思いついた単語が入っているか確認していった。
結果、どうやら3行目に crypt という文字列が含まれているらしいことがわかった。 これで、次のような感じの平文になっていることが判明したので、あとは左右にそれっぽい文字がくるよう適当に伸ばしていけば全部解読できた。
___________________ime I__ ___________________e and__ ___________________crypt__ ___________________hat i__ ___________________ion m__ ___________________tical__ ___________________racke__ ___________________kept __ ___________________f you__ ___________________ this__ ___________________ways.
解読結果はこちら。
Dear Friend, This time I u nderstood my mistake and u sed One time pad encryptio n scheme, I heard that it is the only encryption met hod that is mathematically proven to be not cracked ever if the key is kept se cure, Let me know if you a gree with me to use this e ncryption scheme always.
結局、鍵がフラグだった。
ALEXCTF{HERE_GOES_THE_KEY}
(初めからALEXCTF{
とXORとっていけばよかった)
CR4
RSAの問題。 とりあえず modulus を見てみる。
$ openssl rsa -noout -text -in key.pub -pubin Public-Key: (399 bit) Modulus: 52:a9:9e:24:9e:e7:cf:3c:0c:bf:96:3a:00:96:61: 77:2b:c9:cd:f6:e1:e3:fb:fc:6e:44:a0:7a:5e:0f: 89:44:57:a9:f8:1c:3a:e1:32:ac:56:83:d3:5b:28: ba:5c:32:42:43 Exponent: 65537 (0x10001)
399 bit の RSA コンテストはなかったが、factordb に聞いたら素因数分解してもらえた。
あとは Wikipedia にある通り、例の式に従って復号。
フラグは ALEXCTF{SMALL_PRIMES_ARE_BAD}
CR5
nc でつなぐと、次の数字を教えてもらうか、予想の入力をすることができる。 教えてもらうと乱数列が返ってくるので、これを予想すればいいっぽい
線形合同法では?、と思い次のリンクの通り乱数列の予測を試みた。
security.stackexchange.com
リンク先に書いてある通りだが、ここにもまとめておく。
x[n + 1] = a * x[n] + b (mod m)
より
x[n + 1] - x[n] = a * (x[n] - x[n - 1]) (mod m)
となるので、
y[n] = x[n + 1] - x[n] (mod m)
とおくと、
y[n + 1] = a * y[n] (mod m)
よって
y[n + 2] * y[n] - (y[n + 1])^2 = 0 (mod m)
これにより、y[n + 2] * y[n] - (y[n + 1])^2
を十分な数の n
について集め、最大公約数をとれば、m
が求められる。
あとは、y[1] = a * y[0] (mod m)
を解いて a
を出して、x[1] = a * x[0] + b (mod m)
を解いて b
を出すだけ。
最初の10回くらいは聞いて、それをもとに m
, a
, b
を求め、乱数列を出す。
10回連続で正解すると、フラグを出してくれた。
flag is ALEXCTF{f0cfad89693ec6787a75fa4e53d8bdb5}
書いたスクリプトはこんな感じ。
#!/usr/bin/env python def gcd(a, b): if a < b: return gcd(b, a) while b: a, b = b, a%b return a def egcd(a, b): x, lx = 0, 1 y, ly = 1, 0 while b != 0: q = a // b a, b = b, a % b x, lx = lx - q * x, x y, ly = ly - q * y, y return lx, ly x = [ 4251151823, 2502705517, 4101273005, 1396379746, 4159332548, 3671236567, 433240385, 465003001, 2767252763, 952274152 ] # x[i + 1] = a * x[i] + b (mod m) # y[i + 1] = a * y[i] (mod m) y = [] for i in range(len(x) - 1): y.append(x[i + 1] - x[i]) # z[i] = y[i + 2] * y[i] - (y[i + 1])^2 = 0 (mod m) z = [] for i in range(len(y) - 2): zz = y[i + 2] * y[i] - y[i + 1] * y[i + 1] if zz < 0: zz = -zz z.append(zz) m = z[0] for i in range(len(z)): m = gcd(m, z[i]) for i in range(len(y)): while y[i] < 0: y[i] += m # p * y[0] + q * m = r (mod m) # p * y[0] = r (mod m) p, q = egcd(y[0], m) r = (p * y[0]) % m # y[1] = a * y[0] # p * y[1] = a * p * y[0] = a * r a = ((y[1] / r) * p) % m # a * x[0] + b = x[1] (mod m) # b = x[1] - a * x[0] (mod m) b = (x[1] - a * x[0]) % m print "check y" yy = [] yy.append(y[0]) for i in range(len(y) - 1): t = (a * yy[i]) % m yy.append(t) print y[i + 1], yy[i + 1], (y[i + 1] - yy[i + 1]) print print "check x" xx = [] xx.append(x[0]) for i in range(len(x) - 1): t = (a * xx[i] + b) % m xx.append(t) print x[i + 1], xx[i + 1], (x[i + 1] - xx[i + 1]) print print "show x" xx = [] xx.append(x[0]) for i in range(29): t = (a * xx[i] + b) % m xx.append(t) for i in range(len(xx)): print '{0}\t{1}'.format(i, xx[i])
次CTFに参加するときは暗号以外も解きたい。