diff --git a/receiver/challenges/test_sheesh_standalone.py b/receiver/challenges/test_sheesh_standalone.py new file mode 100644 index 0000000..3512f6d --- /dev/null +++ b/receiver/challenges/test_sheesh_standalone.py @@ -0,0 +1,191 @@ +from .Challenge import Challenge + +import subprocess +import time +import re +import os + +class Sheesh(Challenge): + flag_location = 'flags/sheesh.txt' + history_location = 'history/sheesh.txt' + + _CONTAINER = "sheesh_container" + _SERVICE_CMD = ["docker", "exec", "-i", _CONTAINER, "python3", "/usr/local/bin/chall.py"] + _HEX_RE = re.compile(r'^[0-9a-fA-F]+$') + + def _read_container_flag(self) -> str: + out = subprocess.run(["docker", "exec", self._CONTAINER, "cat", "/flag.txt"], + capture_output=True, text=True) + if out.returncode != 0 or not out.stdout.strip(): + raise FileNotFoundError("Flag not found in container (/flag.txt)") + return out.stdout.strip() + + def _spawn(self): + return subprocess.Popen( + self._SERVICE_CMD, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + bufsize=0, + ) + + def _read_until(self, proc, token, timeout=5.0, max_bytes=1_000_000): + start = time.time() + buf = [] + r = proc.stdout.read + while True: + if time.time() - start > timeout: + tail = ''.join(buf)[-500:] + raise TimeoutError(f"Timeout waiting for '{token}'. Got so far:\n{tail}") + ch = r(1) + if ch == "" and proc.poll() is not None: + raise RuntimeError(f"Process ended while waiting for '{token}'. Output:\n{''.join(buf)}") + buf.append(ch) + if len(buf) > max_bytes: + raise RuntimeError("Exceeded max read size") + if token in "".join(buf): + return "".join(buf) + + def _send_line(self, proc, s: str): + proc.stdin.write(s + "\n") + proc.stdin.flush() + + def _expect_hex_field(self, text: str, label: str) -> str: + m = re.search(rf"{re.escape(label)}\s*:\s*([0-9a-fA-F]+)", text) + assert m, f"Missing '{label}' in output. Tail:\n{text[-400:]}" + hx = m.group(1) + assert self._HEX_RE.match(hx), f"{label} is not hex" + return hx + + def distribute(self, flag): + try: + os.makedirs(os.path.dirname(self.flag_location), exist_ok=True) + with open(self.flag_location, 'w') as f: + f.write(flag) + + os.makedirs(os.path.dirname(self.history_location), exist_ok=True) + with open(self.history_location, 'a') as f: + f.write(flag + '\n') + + self.logger.info(f'Flag {flag} written to {self.flag_location}') + return True + except Exception as e: + self.logger.error(f'Could not write flag to {self.flag_location}: {e}') + return False + + def check(self): + try: + with open(self.flag_location, 'r') as f: + host_flag = f.read().strip() + container_flag = self._read_container_flag() + assert host_flag == container_flag, 'Flag mismatch between host and container' + self.logger.info('[ok] flag parity (sheesh)') + + proc = self._spawn() + + def menu(): + self._read_until(proc, "> ", timeout=5.0) + + menu() + + self._send_line(proc, "1") + self._read_until(proc, "pt: ", timeout=3.0) + pt_hex = "414243444546" # "ABCDEF" + self._send_line(proc, pt_hex) + out = self._read_until(proc, "\n\n", timeout=3.0) + ct_hex = self._expect_hex_field(out, "ct") + ct = bytes.fromhex(ct_hex) + assert len(ct) == 16 + len(bytes.fromhex(pt_hex)), "CFB ct length mismatch (IV+PT)" + iv_a = ct[:16] + self.logger.info("[ok] encrypt(1) basic") + + menu() + self._send_line(proc, "1") + self._read_until(proc, "pt: ", timeout=3.0) + pt_hex2 = "00" * 8 + self._send_line(proc, pt_hex2) + out2 = self._read_until(proc, "\n\n", timeout=3.0) + ct2_hex = self._expect_hex_field(out2, "ct") + ct2 = bytes.fromhex(ct2_hex) + assert len(ct2) == 16 + len(bytes.fromhex(pt_hex2)), "Second CFB ct length mismatch" + iv_b = ct2[:16] + assert iv_a != iv_b, "CFB IV appears reused" + self.logger.info("[ok] encrypt(1) IV rotates") + + menu() + self._send_line(proc, "3") + self._read_until(proc, "pt: ", timeout=3.0) + self._send_line(proc, "00" * 15) + out3a = self._read_until(proc, "\n", timeout=3.0) + assert "hmmm" in out3a.lower(), "Option 3 must reject non-16-byte input (15B)" + + menu() + self._send_line(proc, "3") + self._read_until(proc, "pt: ", timeout=3.0) + self._send_line(proc, "00" * 17) + out3b = self._read_until(proc, "\n", timeout=3.0) + assert "hmmm" in out3b.lower(), "Option 3 must reject non-16-byte input (17B)" + + menu() + self._send_line(proc, "3") + self._read_until(proc, "pt: ", timeout=3.0) + self._send_line(proc, "11" * 16) + out3 = self._read_until(proc, "\n\n", timeout=3.0) + ct3_hex = self._expect_hex_field(out3, "ct") + ct3 = bytes.fromhex(ct3_hex) + assert len(ct3) in (16, 32), f"Unexpected CT length for option 3: {len(ct3)} (expected 16 or 32)" + if len(ct3) == 16: + self.logger.info("[ok] get third(3): vuln flavor (16-byte CT)") + else: + self.logger.info("[ok] get third(3): patched flavor (32-byte CT)") + + menu() + self._send_line(proc, "3") + out4 = self._read_until(proc, "\n", timeout=3.0) + assert "sheesh" in out4.lower(), "Second call to option 3 should be rejected with 'sheesh'" + self.logger.info("[ok] get third(3) lockout") + + menu() + self._send_line(proc, "2") + out5 = self._read_until(proc, "\n\n", timeout=3.0) + iv1_hex = self._expect_hex_field(out5, "iv1") + iv2_hex = self._expect_hex_field(out5, "iv2") + ct5_hex = self._expect_hex_field(out5, "ct") + assert len(bytes.fromhex(iv1_hex)) == 16, "iv1 length invalid" + assert len(bytes.fromhex(iv2_hex)) == 16, "iv2 length invalid" + assert len(bytes.fromhex(ct5_hex)) >= 16 and len(bytes.fromhex(ct5_hex)) % 16 == 0, "CBC ct invalid length" + self.logger.info("[ok] profit(2) first call") + + menu() + self._send_line(proc, "2") + out6 = self._read_until(proc, "\n\n", timeout=3.0) + iv1_hex_2 = self._expect_hex_field(out6, "iv1") + iv2_hex_2 = self._expect_hex_field(out6, "iv2") + assert iv1_hex_2 != iv1_hex or iv2_hex_2 != iv2_hex, "IVs did not change between consecutive '2' calls" + self.logger.info("[ok] profit(2) fresh IVs") + + menu() + self._send_line(proc, "4") + try: + proc.wait(timeout=2.0) + except subprocess.TimeoutExpired: + proc.kill() + raise AssertionError("Program did not exit after option 4") + self.logger.info("[ok] service exit on 4") + + proc_alarm = self._spawn() + self._read_until(proc_alarm, "zzz", timeout=190.0) # 180s + slack + try: + proc_alarm.wait(timeout=5.0) + except subprocess.TimeoutExpired: + proc_alarm.kill() + raise AssertionError("Alarm fired but process did not exit") + self.logger.info("[ok] alarm fired ('zzz') and process self-terminated") + + self.logger.info('Check passed for sheesh') + return True + + except Exception as e: + self.logger.error(f'Could not check sheesh: {e}') + return False diff --git a/receiver/flags/sheesh.txt b/receiver/flags/sheesh.txt new file mode 100644 index 0000000..3fe32e3 --- /dev/null +++ b/receiver/flags/sheesh.txt @@ -0,0 +1 @@ +GEMASTIK{PLACEHOLDER} diff --git a/services/phew/Dockerfile b/services/phew/Dockerfile deleted file mode 100644 index 0d0920d..0000000 --- a/services/phew/Dockerfile +++ /dev/null @@ -1,32 +0,0 @@ -FROM python:3.12-slim - -ARG PASSWORD=root -ENV DEBIAN_FRONTEND=noninteractive -ENV HOME=/home/ctf -WORKDIR /home/ctf/chall - -RUN apt-get update && apt-get install -y --no-install-recommends \ - openssh-server \ - build-essential \ - libffi-dev \ - libssl-dev \ - python3-dev \ - bash \ - && rm -rf /var/lib/apt/lists/* - -RUN useradd -m -d /home/ctf -s /bin/bash ctf && \ - echo "ctf:${PASSWORD}" | chpasswd - -RUN mkdir -p /var/run/sshd - -COPY requirements.txt /tmp/requirements.txt -RUN pip install --no-cache-dir -r /tmp/requirements.txt - -COPY ./src /home/ctf/chall/src -COPY ./start.sh /start.sh -RUN chmod +x /start.sh /home/ctf/chall/src/run.sh - -RUN chown -R root:root /home/ctf/chall && chmod -R 555 /home/ctf/chall - -EXPOSE 8000 22 -CMD ["/start.sh"] diff --git a/services/phew/chall.py b/services/phew/chall.py deleted file mode 100644 index a7bea1b..0000000 --- a/services/phew/chall.py +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env python3 - -import os, sys, json, random, hashlib, hmac -from Crypto.Cipher import AES -from Crypto.Util.Padding import pad -with open("/flag.txt", "rb") as f: - flag = f.read() - -menu = ( - "1) encrypt\n" - "2) profit\n" - "3) nyerah\n" - ">> " -) - - -k = 1024 -n = 169 - -rng = random.SystemRandom() - -def rand(k_bits: int) -> int: - return rng.randrange(1, 1 << k_bits) - -def gen(n: int, k_bits: int): - a = [rand(k_bits) for _ in range(n)] - return a - -def b2b(b: bytes) -> list[int]: - out = [] - for byte in b: - for i in range(8): - out.append((byte >> i) & 1) - return out - -def pack(bits) -> bytes: - out = bytearray() - for i in range(0, len(bits), 8): - chunk = bits[i:i+8] - val = 0 - for j, bit in enumerate(chunk): - val |= (bit & 1) << j - out.append(val) - return bytes(out) - -def gen_key(x_bits: list[int], saltx: bytes, salty: bytes, length: int = 16) -> bytes: - material = pack(x_bits) - prk = hashlib.pbkdf2_hmac("sha256", material, saltx, 131072, dklen=32) - return hmac.new(prk, b"afk-players-wanted-now" + salty + b"\x01", hashlib.sha256).digest()[:length] - -def enc(k: bytes, data: bytes): - iv = os.urandom(16) - ct = AES.new(k, AES.MODE_CBC, iv).encrypt(pad(data, 16)) - return iv, ct - -def add(a, x_bits) -> int: - return sum(ai for ai, xi in zip(a, x_bits) if xi) - -def main(): - a = gen(n, k) - x_bits = b2b(flag) - if len(x_bits) < n: - x_bits += [rng.randrange(0, 2) for _ in range(n - len(x_bits))] - else: - x_bits = x_bits[:n] - - s = add(a, x_bits) - - saltx = os.urandom(16) - salty = os.urandom(16) - key = gen_key(x_bits, saltx, salty) - - iv, ct = enc(key, flag) - - header = { - "n": n, - "k_bits": k, - } - print(json.dumps(header, separators=(",", ":")), flush=True) - - while True: - try: - print(menu, end="", flush=True) - line = sys.stdin.readline() - if not line: - break - try: - choice = int(line.strip()) - except ValueError: - print("sheesh") - continue - - if choice == 1: - print("data: ", end="", flush=True) - dline = sys.stdin.readline() - if not dline: - break - try: - data = bytes.fromhex(dline.strip()) - except Exception: - print("hmmm") - continue - iv, ct = enc(key, data) - print(iv.hex()) - print(ct.hex()) - - elif choice == 2: - print(json.dumps({"a": a}, separators=(",", ":"))) - print(str(s)) - print(saltx.hex()) - print(salty.hex()) - print(iv.hex()) - print(ct.hex()) - - elif choice == 3: - print("bubay") - return - - else: - print("tidak ada yang mustahil, hehehe") - - except Exception: - print("zzz") - -if __name__ == "__main__": - main() diff --git a/services/phew/dist/chall.py b/services/phew/dist/chall.py deleted file mode 100644 index a7bea1b..0000000 --- a/services/phew/dist/chall.py +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env python3 - -import os, sys, json, random, hashlib, hmac -from Crypto.Cipher import AES -from Crypto.Util.Padding import pad -with open("/flag.txt", "rb") as f: - flag = f.read() - -menu = ( - "1) encrypt\n" - "2) profit\n" - "3) nyerah\n" - ">> " -) - - -k = 1024 -n = 169 - -rng = random.SystemRandom() - -def rand(k_bits: int) -> int: - return rng.randrange(1, 1 << k_bits) - -def gen(n: int, k_bits: int): - a = [rand(k_bits) for _ in range(n)] - return a - -def b2b(b: bytes) -> list[int]: - out = [] - for byte in b: - for i in range(8): - out.append((byte >> i) & 1) - return out - -def pack(bits) -> bytes: - out = bytearray() - for i in range(0, len(bits), 8): - chunk = bits[i:i+8] - val = 0 - for j, bit in enumerate(chunk): - val |= (bit & 1) << j - out.append(val) - return bytes(out) - -def gen_key(x_bits: list[int], saltx: bytes, salty: bytes, length: int = 16) -> bytes: - material = pack(x_bits) - prk = hashlib.pbkdf2_hmac("sha256", material, saltx, 131072, dklen=32) - return hmac.new(prk, b"afk-players-wanted-now" + salty + b"\x01", hashlib.sha256).digest()[:length] - -def enc(k: bytes, data: bytes): - iv = os.urandom(16) - ct = AES.new(k, AES.MODE_CBC, iv).encrypt(pad(data, 16)) - return iv, ct - -def add(a, x_bits) -> int: - return sum(ai for ai, xi in zip(a, x_bits) if xi) - -def main(): - a = gen(n, k) - x_bits = b2b(flag) - if len(x_bits) < n: - x_bits += [rng.randrange(0, 2) for _ in range(n - len(x_bits))] - else: - x_bits = x_bits[:n] - - s = add(a, x_bits) - - saltx = os.urandom(16) - salty = os.urandom(16) - key = gen_key(x_bits, saltx, salty) - - iv, ct = enc(key, flag) - - header = { - "n": n, - "k_bits": k, - } - print(json.dumps(header, separators=(",", ":")), flush=True) - - while True: - try: - print(menu, end="", flush=True) - line = sys.stdin.readline() - if not line: - break - try: - choice = int(line.strip()) - except ValueError: - print("sheesh") - continue - - if choice == 1: - print("data: ", end="", flush=True) - dline = sys.stdin.readline() - if not dline: - break - try: - data = bytes.fromhex(dline.strip()) - except Exception: - print("hmmm") - continue - iv, ct = enc(key, data) - print(iv.hex()) - print(ct.hex()) - - elif choice == 2: - print(json.dumps({"a": a}, separators=(",", ":"))) - print(str(s)) - print(saltx.hex()) - print(salty.hex()) - print(iv.hex()) - print(ct.hex()) - - elif choice == 3: - print("bubay") - return - - else: - print("tidak ada yang mustahil, hehehe") - - except Exception: - print("zzz") - -if __name__ == "__main__": - main() diff --git a/services/phew/docker-compose.yml b/services/phew/docker-compose.yml deleted file mode 100644 index 48b947b..0000000 --- a/services/phew/docker-compose.yml +++ /dev/null @@ -1,16 +0,0 @@ -version: "3.8" - -services: - phew: - container_name: phew_container - hostname: phew - restart: always - build: - context: . - args: - - PASSWORD=root - ports: - - "13000:8000" - - "13022:22" - environment: - - FLAG=GEMASTIK{local_flag} diff --git a/services/phew/requirements.txt b/services/phew/requirements.txt deleted file mode 100644 index c21b6ec..0000000 --- a/services/phew/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -pycryptodome \ No newline at end of file diff --git a/services/phew/run.sh b/services/phew/run.sh deleted file mode 100644 index 6ae49cb..0000000 --- a/services/phew/run.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -exec socat tcp-l:8000,reuseaddr,fork exec:"python3 ./chall.py" diff --git a/services/phew/start.sh b/services/phew/start.sh deleted file mode 100644 index 7b40126..0000000 --- a/services/phew/start.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -set -e - -ssh-keygen -A - -# Configure SSH -grep -q "^PermitRootLogin" /etc/ssh/sshd_config && \ - sed -i "s/^PermitRootLogin.*/PermitRootLogin no/" /etc/ssh/sshd_config || \ - echo "PermitRootLogin no" >> /etc/ssh/sshd_config - -grep -q "^PasswordAuthentication" /etc/ssh/sshd_config && \ - sed -i "s/^PasswordAuthentication.*/PasswordAuthentication yes/" /etc/ssh/sshd_config || \ - echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config - -echo "AllowUsers ctf" >> /etc/ssh/sshd_config - -/usr/sbin/sshd - -if [ -n "$FLAG" ]; then - echo "$FLAG" > /flag.txt - chmod 644 /flag.txt - chown root:root /flag.txt -fi - -exec su -c "cd /home/ctf/chall/src && ./run.sh" -s /bin/bash ctf diff --git a/services/sheesh/chall.py b/services/sheesh/chall.py index 1b507bf..a3eca5f 100644 --- a/services/sheesh/chall.py +++ b/services/sheesh/chall.py @@ -1,116 +1,116 @@ #!/usr/bin/env python3 -import os, sys, json, random, hashlib, hmac +import os +import binascii +import hashlib +import threading +import time +import sys from Crypto.Cipher import AES -from Crypto.Util.Padding import pad -with open("/flag.txt", "rb") as f: +from Crypto.Util.Padding import pad, unpad + +seed_bits = 23 +seed_max = 1 << seed_bits +seed_len = (seed_bits + 7) // 8 +key = os.urandom(16) + +def hash_seed(seed_int: int) -> bytes: + sb = seed_int.to_bytes(seed_len, "big") + return hashlib.sha256(sb).digest()[:16] + +seed = int.from_bytes(os.urandom(4), "big") % seed_max +seed2 = int.from_bytes(os.urandom(4), "big") % seed_max +K1 = hash_seed(seed) +K2 = hash_seed(seed2) + +with open("./flag.txt", "rb") as f: flag = f.read() - -B = 16 -opts = ( - "1) encrypt\n" - "2) profit\n" - "3) nyerah\n" - ">> " -) -def exp(prk: bytes, info: bytes, L: int) -> bytes: - return hmac.new(prk, info + b"\x01", hashlib.sha256).digest()[:L] +def read_hex(prompt: str): + s = input(prompt).strip() + try: + return binascii.unhexlify(s) + except Exception: + print("hmm") + return None -def enc(k: bytes, data: bytes): - iv = os.urandom(B) - ct = AES.new(k, AES.MODE_CBC, iv).encrypt(pad(data, B)) - return iv, ct +def enc_cfb(pt: bytes) -> bytes: + iv = os.urandom(16) + aes = AES.new(key, AES.MODE_CFB, iv=iv, segment_size=128) + ct = aes.encrypt(pt) + return iv + ct -def inp_hex(prompt: str) -> bytes: - print(prompt, end="", flush=True) - s = sys.stdin.readline() - if not s: - raise EOFError - return bytes.fromhex(s.strip()) +def enc_cbc(data: bytes, iv1: bytes, iv2: bytes, padd: bool) -> bytes: + x = pad(data, 16) if padd else data + c1 = AES.new(K1, AES.MODE_CBC, iv=iv1).encrypt(x) + c2 = AES.new(K2, AES.MODE_CBC, iv=iv2).encrypt(c1) + return c2 -def rand(rng, d, lo, hi): - while True: - v = [rng.randint(lo, hi) for _ in range(d)] - if any(v): - return v +def menu(): + print(""" +1. encrypt +2. profit +3. get third +4. exit + """) -def syst(rng): - d = rng.choice([2, 3]) - m = rng.randint(5, 8) - x = rand(rng, d, -3, 3) - rows = [] - for _ in range(m): - base = rand(rng, d, -3, 3) - r = rng.randint(1, 7) - scaled = [r * a for a in base] - e = rng.randint(0, 1) - bi = sum(ai * xi for ai, xi in zip(scaled, x)) + e - rows.append((scaled, bi)) - rng.shuffle(rows) - A = [row for (row, _) in rows] - B = [b for (_, b) in rows] - pub = {"dim": d, "A": A, "b": B} - return pub, tuple(x) +third = 0 +iv11 = None +iv22 = None -def bundle(): - rng = random.Random(os.urandom(16)) - systems = [] - hidden = [] - for _ in range(4): - pub, x = syst(rng) - systems.append(pub) - hidden.append(x) - return {"systems": systems}, tuple(hidden) +def alarm(): + time.sleep(180) + print("zzz") + sys.exit(0) -def get_key(saltx: bytes, salty: bytes, b): - parts = [] - for x in b: - parts.append(",".join(str(t) for t in x)) - material = "|".join(parts).encode() - prk = hashlib.pbkdf2_hmac("sha256", material, saltx, 131072, dklen=32) - return exp(prk, b"g3m4zzzt1q" + salty, 16) +threading.Thread(target=alarm, daemon=True).start() -def main(): - a, b = bundle() - print(json.dumps(a, separators=(",", ":")), flush=True) - saltx = os.urandom(16) - salty = os.urandom(16) - key = get_key(saltx, salty, b) - iv, ct = enc(key, flag) - while True: - try: - print(opts, end="", flush=True) - line = sys.stdin.readline() - if not line: - break - try: - choice = int(line.strip()) - except ValueError: - print("sheesh") - continue +while True: + menu() + op = input("> ").strip() - if choice == 1: - data = inp_hex("data: ") - iv, ct = enc(key, data) - print(iv.hex()) - print(ct.hex()) + if op == "1": + data = read_hex("pt: ") + if data is None: + print() + continue + out = enc_cfb(data) + print("ct: ", out.hex()) + print() - elif choice == 2: - print(iv.hex()) - print(ct.hex()) - print(saltx.hex()) - print(salty.hex()) + elif op == "2": + if iv11 is not None and iv22 is not None: + iv1, iv2 = iv11, iv22 + iv11 = iv22 = None + else: + iv1 = os.urandom(16) + iv2 = os.urandom(16) + ct = enc_cbc(flag, iv1, iv2, padd=True) + print("iv1: ", iv1.hex()) + print("iv2: ", iv2.hex()) + print("ct: ", ct.hex()) + print() - elif choice == 3: - print("bubay") - return + elif op == "3": + if third: + print("sheesh") + continue + block = read_hex("pt: ") + if block is None: + print() + continue + if len(block) != 16: + print("hmmm\n") + continue + iv1 = os.urandom(16) + iv2 = os.urandom(16) + ct = enc_cbc(block, iv1, iv2, padd=False) + iv11, iv22 = iv1, iv2 + print("ct: ", ct.hex()) + third = 1 + print() - else: - print("when you feel like quitting, remember why you started :v (yapping)") - - except Exception: - print("zzz") - -if __name__ == "__main__": - main() + elif op == "4": + break + else: + print("mabokkkk?") diff --git a/services/sheesh/dist/chall.py b/services/sheesh/dist/chall.py index 1b507bf..a3eca5f 100644 --- a/services/sheesh/dist/chall.py +++ b/services/sheesh/dist/chall.py @@ -1,116 +1,116 @@ #!/usr/bin/env python3 -import os, sys, json, random, hashlib, hmac +import os +import binascii +import hashlib +import threading +import time +import sys from Crypto.Cipher import AES -from Crypto.Util.Padding import pad -with open("/flag.txt", "rb") as f: +from Crypto.Util.Padding import pad, unpad + +seed_bits = 23 +seed_max = 1 << seed_bits +seed_len = (seed_bits + 7) // 8 +key = os.urandom(16) + +def hash_seed(seed_int: int) -> bytes: + sb = seed_int.to_bytes(seed_len, "big") + return hashlib.sha256(sb).digest()[:16] + +seed = int.from_bytes(os.urandom(4), "big") % seed_max +seed2 = int.from_bytes(os.urandom(4), "big") % seed_max +K1 = hash_seed(seed) +K2 = hash_seed(seed2) + +with open("./flag.txt", "rb") as f: flag = f.read() - -B = 16 -opts = ( - "1) encrypt\n" - "2) profit\n" - "3) nyerah\n" - ">> " -) -def exp(prk: bytes, info: bytes, L: int) -> bytes: - return hmac.new(prk, info + b"\x01", hashlib.sha256).digest()[:L] +def read_hex(prompt: str): + s = input(prompt).strip() + try: + return binascii.unhexlify(s) + except Exception: + print("hmm") + return None -def enc(k: bytes, data: bytes): - iv = os.urandom(B) - ct = AES.new(k, AES.MODE_CBC, iv).encrypt(pad(data, B)) - return iv, ct +def enc_cfb(pt: bytes) -> bytes: + iv = os.urandom(16) + aes = AES.new(key, AES.MODE_CFB, iv=iv, segment_size=128) + ct = aes.encrypt(pt) + return iv + ct -def inp_hex(prompt: str) -> bytes: - print(prompt, end="", flush=True) - s = sys.stdin.readline() - if not s: - raise EOFError - return bytes.fromhex(s.strip()) +def enc_cbc(data: bytes, iv1: bytes, iv2: bytes, padd: bool) -> bytes: + x = pad(data, 16) if padd else data + c1 = AES.new(K1, AES.MODE_CBC, iv=iv1).encrypt(x) + c2 = AES.new(K2, AES.MODE_CBC, iv=iv2).encrypt(c1) + return c2 -def rand(rng, d, lo, hi): - while True: - v = [rng.randint(lo, hi) for _ in range(d)] - if any(v): - return v +def menu(): + print(""" +1. encrypt +2. profit +3. get third +4. exit + """) -def syst(rng): - d = rng.choice([2, 3]) - m = rng.randint(5, 8) - x = rand(rng, d, -3, 3) - rows = [] - for _ in range(m): - base = rand(rng, d, -3, 3) - r = rng.randint(1, 7) - scaled = [r * a for a in base] - e = rng.randint(0, 1) - bi = sum(ai * xi for ai, xi in zip(scaled, x)) + e - rows.append((scaled, bi)) - rng.shuffle(rows) - A = [row for (row, _) in rows] - B = [b for (_, b) in rows] - pub = {"dim": d, "A": A, "b": B} - return pub, tuple(x) +third = 0 +iv11 = None +iv22 = None -def bundle(): - rng = random.Random(os.urandom(16)) - systems = [] - hidden = [] - for _ in range(4): - pub, x = syst(rng) - systems.append(pub) - hidden.append(x) - return {"systems": systems}, tuple(hidden) +def alarm(): + time.sleep(180) + print("zzz") + sys.exit(0) -def get_key(saltx: bytes, salty: bytes, b): - parts = [] - for x in b: - parts.append(",".join(str(t) for t in x)) - material = "|".join(parts).encode() - prk = hashlib.pbkdf2_hmac("sha256", material, saltx, 131072, dklen=32) - return exp(prk, b"g3m4zzzt1q" + salty, 16) +threading.Thread(target=alarm, daemon=True).start() -def main(): - a, b = bundle() - print(json.dumps(a, separators=(",", ":")), flush=True) - saltx = os.urandom(16) - salty = os.urandom(16) - key = get_key(saltx, salty, b) - iv, ct = enc(key, flag) - while True: - try: - print(opts, end="", flush=True) - line = sys.stdin.readline() - if not line: - break - try: - choice = int(line.strip()) - except ValueError: - print("sheesh") - continue +while True: + menu() + op = input("> ").strip() - if choice == 1: - data = inp_hex("data: ") - iv, ct = enc(key, data) - print(iv.hex()) - print(ct.hex()) + if op == "1": + data = read_hex("pt: ") + if data is None: + print() + continue + out = enc_cfb(data) + print("ct: ", out.hex()) + print() - elif choice == 2: - print(iv.hex()) - print(ct.hex()) - print(saltx.hex()) - print(salty.hex()) + elif op == "2": + if iv11 is not None and iv22 is not None: + iv1, iv2 = iv11, iv22 + iv11 = iv22 = None + else: + iv1 = os.urandom(16) + iv2 = os.urandom(16) + ct = enc_cbc(flag, iv1, iv2, padd=True) + print("iv1: ", iv1.hex()) + print("iv2: ", iv2.hex()) + print("ct: ", ct.hex()) + print() - elif choice == 3: - print("bubay") - return + elif op == "3": + if third: + print("sheesh") + continue + block = read_hex("pt: ") + if block is None: + print() + continue + if len(block) != 16: + print("hmmm\n") + continue + iv1 = os.urandom(16) + iv2 = os.urandom(16) + ct = enc_cbc(block, iv1, iv2, padd=False) + iv11, iv22 = iv1, iv2 + print("ct: ", ct.hex()) + third = 1 + print() - else: - print("when you feel like quitting, remember why you started :v (yapping)") - - except Exception: - print("zzz") - -if __name__ == "__main__": - main() + elif op == "4": + break + else: + print("mabokkkk?")