From b6597bf3130adb77f493f9b6300c4788aa3a5ab8 Mon Sep 17 00:00:00 2001 From: Andreas Tsouloupas Date: Thu, 4 Jul 2024 21:56:00 +0200 Subject: [PATCH] crypto(diffie-helman): add beginner challenge --- crypto/diffie-hellman/challenge.yml | 35 +++++++++ crypto/diffie-hellman/docker-compose.yml | 7 ++ crypto/diffie-hellman/public/server.py | 1 + crypto/diffie-hellman/setup/Dockerfile | 15 ++++ crypto/diffie-hellman/setup/requirements.txt | 1 + crypto/diffie-hellman/setup/secret.py | 1 + crypto/diffie-hellman/setup/server.py | 79 ++++++++++++++++++++ crypto/diffie-hellman/sol/solve.py | 62 +++++++++++++++ 8 files changed, 201 insertions(+) create mode 100644 crypto/diffie-hellman/challenge.yml create mode 100644 crypto/diffie-hellman/docker-compose.yml create mode 120000 crypto/diffie-hellman/public/server.py create mode 100644 crypto/diffie-hellman/setup/Dockerfile create mode 100644 crypto/diffie-hellman/setup/requirements.txt create mode 100644 crypto/diffie-hellman/setup/secret.py create mode 100644 crypto/diffie-hellman/setup/server.py create mode 100644 crypto/diffie-hellman/sol/solve.py diff --git a/crypto/diffie-hellman/challenge.yml b/crypto/diffie-hellman/challenge.yml new file mode 100644 index 0000000..be416c0 --- /dev/null +++ b/crypto/diffie-hellman/challenge.yml @@ -0,0 +1,35 @@ +name: "Diffie-Hellman" +author: "feltf" +category: crypto + +description: | + Play the role of Bob (one of the two parties) in the Diffie-Hellman key + exchange algorithm to obtain the shared secret! + + Then decrypt the encrypted flag that Alice will send to you! + + You don't have to implement the cryptographic algorithms from scratch. Take a look at the + python crypto library [PyCryptodome](https://pycryptodome.readthedocs.io/en/latest/), + it will help you to decrypt the flag. + +value: 500 +type: dynamic_docker +extra: + initial: 500 + minimum: 100 + decay: 25 + redirect_type: direct + compose_stack: !filecontents docker-compose.yml + +flags: + - GTBQ{d1ff1e_h3llm4n_key_exchang3_and_bas1c_crypt0} + +files: + - public/server.py + +tags: + - crypto + - beginner + +state: visible +version: "0.1" \ No newline at end of file diff --git a/crypto/diffie-hellman/docker-compose.yml b/crypto/diffie-hellman/docker-compose.yml new file mode 100644 index 0000000..63191f1 --- /dev/null +++ b/crypto/diffie-hellman/docker-compose.yml @@ -0,0 +1,7 @@ +version: '3' +services: + casino: + build: ./setup/ + image: ghcr.io/cybermouflons/gtbq-2024/diffie-hellman:latest + ports: + - 1337:1337 \ No newline at end of file diff --git a/crypto/diffie-hellman/public/server.py b/crypto/diffie-hellman/public/server.py new file mode 120000 index 0000000..1384cfe --- /dev/null +++ b/crypto/diffie-hellman/public/server.py @@ -0,0 +1 @@ +../setup/server.py \ No newline at end of file diff --git a/crypto/diffie-hellman/setup/Dockerfile b/crypto/diffie-hellman/setup/Dockerfile new file mode 100644 index 0000000..2ee0dd2 --- /dev/null +++ b/crypto/diffie-hellman/setup/Dockerfile @@ -0,0 +1,15 @@ +FROM ubuntu:22.04 + +RUN apt-get update && apt-get install -y socat python3 python3-pip + +RUN mkdir /app +WORKDIR /app + +COPY requirements.txt /app/ +RUN pip install -r requirements.txt + +COPY secret.py/ /app/ +COPY server.py/ /app/ + +EXPOSE 1337 +CMD ["socat", "-v","TCP-LISTEN:1337,reuseaddr,fork", "EXEC:'python3 /app/server.py'"] \ No newline at end of file diff --git a/crypto/diffie-hellman/setup/requirements.txt b/crypto/diffie-hellman/setup/requirements.txt new file mode 100644 index 0000000..08e3598 --- /dev/null +++ b/crypto/diffie-hellman/setup/requirements.txt @@ -0,0 +1 @@ +pycryptodome==3.20.0 diff --git a/crypto/diffie-hellman/setup/secret.py b/crypto/diffie-hellman/setup/secret.py new file mode 100644 index 0000000..1e0ed03 --- /dev/null +++ b/crypto/diffie-hellman/setup/secret.py @@ -0,0 +1 @@ +FLAG = b"GTBQ{d1ff1e_h3llm4n_key_exchang3_and_bas1c_crypt0}" diff --git a/crypto/diffie-hellman/setup/server.py b/crypto/diffie-hellman/setup/server.py new file mode 100644 index 0000000..bb13fae --- /dev/null +++ b/crypto/diffie-hellman/setup/server.py @@ -0,0 +1,79 @@ +import secrets +from secret import FLAG +from Crypto.Protocol.KDF import HKDF +from Crypto.Cipher import AES +from Crypto.Util.Padding import pad +from Crypto.Hash import SHA256 +from Crypto.Util.number import long_to_bytes + +class DiffieHellman: + def __init__(self) -> None: + # Diffie-Hellman group (2048-bit MODP Group) + self.p = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF + self.q = (self.p-1)//2 # group order + self.g = 2 # group generator + + def start(self): + print(""" +============================================================= +| | +| Diffie-Hellman Key Exchange: | +| Derive a secret to decrypt the flag | +| | +============================================================= +| (p,q,g) | +| | +| Alice Bob (you) | +| O O | +| /|\ /|\ | +| / \ / \ | +| flag | +| | +| chose random a in [1,q] | +| A = g^a mod p | +| | +| A | +| ----------------------> | +| | +| chose random b in [1,q] | +| S = A^b mod p | +| B = g^b mod p | +| | +| B | +| <---------------------- | +| | +| S = B^a mod p | +| K = HKDF-SHA256(S, 16, "") | +| | +| c, IV = AES-CBC(K, flag) | +| ----------------------> | +=============================================================""") + + print(f"(Info) p={self.p}") + print(f"(Info) q={self.q}") + print(f"(Info) g={self.g}") + + a = secrets.randbelow(self.q) + 1 # Alice's secret value + A = pow(self.g, a, self.p) # Alice's public group member + print(f"(Alice) Bob A is {A}") + try: + B = int(input("(Bob) Alice B is ")) + except: + print("(Error) B is an integer value member of the group (mod p)") + return + + if pow(B, self.q, self.p) != 1: + print("(Error) B is not in the group (mod p)") + return + + S = pow(B, a, self.p) + K = HKDF(long_to_bytes(S), 16, "", SHA256) + + cipher = AES.new(K, AES.MODE_CBC) + c = cipher.encrypt(pad(FLAG, AES.block_size)) + + print(f"(Alice) Bob the encrypted flag (in hex) is {c.hex()} with IV {cipher.iv.hex()}") + + +dhke = DiffieHellman() +dhke.start() diff --git a/crypto/diffie-hellman/sol/solve.py b/crypto/diffie-hellman/sol/solve.py new file mode 100644 index 0000000..a005d4a --- /dev/null +++ b/crypto/diffie-hellman/sol/solve.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +import os +import secrets + +from telnetlib import Telnet + +from Crypto.Protocol.KDF import HKDF +from Crypto.Cipher import AES +from Crypto.Util.Padding import unpad +from Crypto.Hash import SHA256 +from Crypto.Util.number import long_to_bytes + + +def solve(tn: Telnet): + # Read p + tn.read_until(b"p=") + p = int((tn.read_until(b"\n")[:-1])) + + # Read q + tn.read_until(b"q=") + q = int((tn.read_until(b"\n")[:-1])) + + # Read g + tn.read_until(b"g=") + g = int((tn.read_until(b"\n")[:-1])) + + # Read Alice's public A + tn.read_until(b"Bob A is ") + A = int((tn.read_until(b"\n")[:-1])) + + # chose random b + b = secrets.randbelow(q) + 1 + # compute Bob's public B + B = pow(g, b, p) + # send public B + tn.read_until(b"Alice B is ") + tn.write(str(B).encode() + b"\n") + + # Read encrypted flag + tn.read_until(b"Bob the encrypted flag (in hex) is ") + c = bytes.fromhex(tn.read_until(b" ")[:-1].decode()) + + # Read IV + tn.read_until(b"with IV ") + IV = bytes.fromhex(tn.read_until(b"\n")[:-1].decode()) + + # Until here it can be done manually, i.e., extract info from server responses + S = pow(A, b, p) + K = HKDF(long_to_bytes(S), 16, "", SHA256) + + cipher = AES.new(K, AES.MODE_CBC, IV) + flag = unpad(cipher.decrypt(c), AES.block_size) + print(flag) + +if __name__ == "__main__": + if "REMOTE" in os.environ: + HOSTNAME = "" + else: + HOSTNAME = "localhost" + PORT = 1337 + with Telnet(HOSTNAME, PORT) as tn: + solve(tn)