この大会は2018/10/16 19:00(JST)~2018/10/18 19:00(JST)に開催されました。
今回もチームで参戦。結果は 1109点で1035チーム中51位でした。
自分で解けた問題をWriteupとして書いておきます。
Relations (Crypto)
いろいろ試してみる。
$ nc arcade.fluxfingers.net 1821 ------------------------------ Welcome to theory world ------------------------------ ------------------------------ Possible Oracles (XOR) Choose XOR Oracle (ADD) Choose ADD Oracle (DEC) For trying to decrypt -----------------------------* XOR Please choose the operand in hex >>> 01 Ciphertext is sY4v3laEDC9hcW7OLMoOkxrz7SVVioYl+4ni7XawrypvCKuodcSPtwpvEJyvNGxDQgEM+qCeKcaq xk1a7I65qQ== ------------------------------ Possible Oracles (XOR) Choose XOR Oracle (ADD) Choose ADD Oracle (DEC) For trying to decrypt -----------------------------* XOR Please choose the operand in hex >>> 0001 Ciphertext is sY4v3laEDC9hcW7OLMoOkxrz7SVVioYl+4ni7XawrypvCKuodcSPtwpvEJyvNGxDQgEM+qCeKcaq xk1a7I65qQ== ------------------------------ Possible Oracles (XOR) Choose XOR Oracle (ADD) Choose ADD Oracle (DEC) For trying to decrypt -----------------------------* XOR Please choose the operand in hex >>> 56 Ciphertext is NWwcbySi44ud+TDvirbaZbwH0P5iXI0DIce9fPsp1PAapdofgXXHF2Up8cVdgmQZff4z9IUxemHh 7vHVQ6pz+w== ------------------------------ Possible Oracles (XOR) Choose XOR Oracle (ADD) Choose ADD Oracle (DEC) For trying to decrypt -----------------------------* ADD Please choose the operand in hex >>> 56 Ciphertext is YGuF1Rl5Xj44kM+21Fazt7IFH0pDb5VV9QhnWghpIfCQr6fjwi2ko9RHEdw+s7dgEMKTWaf3eum/ QeqPcV6Vng== $ nc arcade.fluxfingers.net 1821 ------------------------------ Welcome to theory world ------------------------------ ------------------------------ Possible Oracles (XOR) Choose XOR Oracle (ADD) Choose ADD Oracle (DEC) For trying to decrypt -----------------------------* DEC Enter the key base64 encoded >>> MDEy Traceback (most recent call last): File "/home/chall/rka.py", line 113, in <module> main() File "/home/chall/rka.py", line 107, in main aes = pyaes.AESModeOfOperationECB(key) File "/home/chall/pyaes/aes.py", line 304, in __init__ self._aes = AES(key) File "/home/chall/pyaes/aes.py", line 134, in __init__ raise ValueError('Invalid key size') ValueError: Invalid key size
どうやらAESの鍵にXORやADDして暗号化した結果を表示していると推定できる。各ビットに対して、XORした鍵とADDした鍵が同じ場合は、ビットが立っていないことになることを利用して、鍵を1ビットずつ割り出し、128ビット分判明したら復号する。
import socket import re import base64 def recvuntil(s, tail): data = '' while True: if tail in data: return data data += s.recv(1) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('arcade.fluxfingers.net', 1821)) b_key = '' for i in range(128): print 'Round %d' % (i + 1) print b_key send_data = hex(2**i)[2:].rstrip('L') data = recvuntil(s, '*\n') print data + 'XOR' s.sendall('XOR\n') data = recvuntil(s, '>>> ') print data + send_data s.sendall(send_data + '\n') data = recvuntil(s, '\n\n') pattern = 'Ciphertext is (.+)\n(.+)\n' m = re.search(pattern, data) ciphertext = m.group(1) + m.group(2) print data data = recvuntil(s, '*\n') print data + 'ADD' s.sendall('ADD\n') data = recvuntil(s, '>>> ') print data + send_data s.sendall(send_data + '\n') data = recvuntil(s, '\n\n') pattern = 'Ciphertext is (.+)\n(.+)\n' m = re.search(pattern, data) ciphertext2 = m.group(1) + m.group(2) print data if ciphertext == ciphertext2: b_key = '0' + b_key else: b_key = '1' + b_key key = '' for i in range(0, 128, 8): key += chr(int(b_key[i:i+8], 2)) print key.encode('hex') b64_key = base64.b64encode(key) data = recvuntil(s, '*\n') print data + 'DEC' s.sendall('DEC\n') data = recvuntil(s, '>>> ') print data + b64_key s.sendall(b64_key + '\n') data = recvuntil(s, '\n') print data
flag{r3l4t3d_k3y_der1iviNg_fuNct1on5_h4ve_to_be_a_l1mit3d_cla55}
Multiplayer Part 1 (Crypto)
jsonデータ入力。パラメータは x, y, c, d, groupIDで、以下の形式。
{"x": val, "y": val, "c": val, "d": val, "groupID": val} X = E*1 X == c*P + d*Q response = get_response(data["x"], data["y"], data["c"], data["d"], data["groupID"])
DBにない場合は登録。指定GroupIDのデータを201個以上登録できたら、フラグが表示される。c, dをランダムな値にしてXを算出。x, yを指定すればよい。
import socket import re from gmpy2 import invert from random import randint class EllipticCurve(object): def __init__(self, a, b, p): self.a = a self.b = b self.p = p self.discriminant = -16 * (4 * a * a * a + 27 * b * b) if not self.isSmooth(): raise Exception("The curve %s is not smooth!" % self) def isSmooth(self): return self.discriminant != 0 def testPoint(self, x, y, p): return (y ** 2) % p == (x ** 3 + self.a * x + self.b) % p def __str__(self): return 'y^2 = x^3 + %Gx + %G (mod %G)' % (self.a, self.b, self.p) def __eq__(self, other): return (self.a, self.b, self.p) == (other.a, other.b, other.p) class Point(object): def __init__(self, curve, x, y): self.curve = curve self.x = x self.y = y if not curve.testPoint(x, y, curve.p): raise Exception("The point %s is not on the given curve %s" % (self, curve)) def __neg__(self): return Point(self.curve, self.x, -self.y) def __add__(self, Q): if isinstance(Q, Ideal): return self x_1, y_1, x_2, y_2 = self.x, self.y, Q.x, Q.y if (x_1, y_1) == (x_2, y_2): if y_1 == 0: return Ideal(self.curve) s = (3 * x_1 * x_1 + self.curve.a) * int(invert(2 * y_1, self.curve.p)) else: if x_1 == x_2: return Ideal(self.curve) s = (y_2 - y_1) * int(invert(x_2 - x_1, self.curve.p)) x_3 = (s * s - x_2 - x_1) % self.curve.p y_3 = (s * (x_3 - x_1) + y_1) % self.curve.p return Point(self.curve, x_3, self.curve.p - y_3) def __sub__(self, Q): return self + -Q def __mul__(self, n): if not (isinstance(n, int) or isinstance(n, long)): raise Exception("Can't scale a point by something which isn't an int!") else: if n < 0: return -self * -n if n == 0: return Ideal(self.curve) else: Q = self R = self if n & 1 == 1 else Ideal(self.curve) i = 2 while i <= n: Q = Q + Q if n & i == i: R = Q + R i = i << 1 return R def __rmul__(self, n): return self * n class Ideal(Point): def __init__(self, curve): self.curve = curve def __str__(self): return "Ideal" def __neg__(self): return self def __add__(self, Q): return Q def __mul__(self, n): if not isinstance(n, int): raise Exception("Can't scale a point by something which isn't an int!") else: return self p = 889774351128949770355298446172353873 a = 12345 b = 67890 px = 238266381988261346751878607720968495 py = 591153005086204165523829267245014771 qx = 341454032985370081366658659122300896 qy = 775807209463167910095539163959068826 def recvuntil(s, tail): data = '' while True: if tail in data: return data data += s.recv(1) def make_json(x, y, c, d): groupID = 'n0r4n3c0_m1k3n3c0' json_format = '{"x": "%d", "y": "%d", "c": "%d", "d": "%d", "groupID": "%s"}' json = json_format % (x, y, c, d, groupID) return json s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('arcade.fluxfingers.net', 1822)) E = EllipticCurve(a, b, p) P = Point(E, px, py) Q = Point(E, qx, qy) while True: c = randint(1, p - 1) d = randint(1, p - 1) X = c * P + d * Q x = X.x y = X.y json = make_json(x, y, c, d) print json s.sendall(json + '\n') data = recvuntil(s, '}') if 'flag1' in data: data += recvuntil(s, '}') print data break else: print data
flag{d1str1but3_the_rh0w_p0W3r}
*1:x, y