Merge branch 'main' of github.com:rayhanhanaputra/gemastik18-final
This commit is contained in:
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
GEMASTIK{PLACEHOLDER}
|
||||
@@ -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"]
|
||||
@@ -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()
|
||||
Vendored
-126
@@ -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()
|
||||
@@ -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}
|
||||
@@ -1 +0,0 @@
|
||||
pycryptodome
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec socat tcp-l:8000,reuseaddr,fork exec:"python3 ./chall.py"
|
||||
@@ -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
|
||||
+100
-100
@@ -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?")
|
||||
|
||||
Vendored
+100
-100
@@ -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?")
|
||||
|
||||
Reference in New Issue
Block a user