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
|
#!/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.Cipher import AES
|
||||||
from Crypto.Util.Padding import pad
|
from Crypto.Util.Padding import pad, unpad
|
||||||
with open("/flag.txt", "rb") as f:
|
|
||||||
|
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()
|
flag = f.read()
|
||||||
|
|
||||||
B = 16
|
|
||||||
opts = (
|
|
||||||
"1) encrypt\n"
|
|
||||||
"2) profit\n"
|
|
||||||
"3) nyerah\n"
|
|
||||||
">> "
|
|
||||||
)
|
|
||||||
|
|
||||||
def exp(prk: bytes, info: bytes, L: int) -> bytes:
|
def read_hex(prompt: str):
|
||||||
return hmac.new(prk, info + b"\x01", hashlib.sha256).digest()[:L]
|
s = input(prompt).strip()
|
||||||
|
try:
|
||||||
|
return binascii.unhexlify(s)
|
||||||
|
except Exception:
|
||||||
|
print("hmm")
|
||||||
|
return None
|
||||||
|
|
||||||
def enc(k: bytes, data: bytes):
|
def enc_cfb(pt: bytes) -> bytes:
|
||||||
iv = os.urandom(B)
|
iv = os.urandom(16)
|
||||||
ct = AES.new(k, AES.MODE_CBC, iv).encrypt(pad(data, B))
|
aes = AES.new(key, AES.MODE_CFB, iv=iv, segment_size=128)
|
||||||
return iv, ct
|
ct = aes.encrypt(pt)
|
||||||
|
return iv + ct
|
||||||
|
|
||||||
def inp_hex(prompt: str) -> bytes:
|
def enc_cbc(data: bytes, iv1: bytes, iv2: bytes, padd: bool) -> bytes:
|
||||||
print(prompt, end="", flush=True)
|
x = pad(data, 16) if padd else data
|
||||||
s = sys.stdin.readline()
|
c1 = AES.new(K1, AES.MODE_CBC, iv=iv1).encrypt(x)
|
||||||
if not s:
|
c2 = AES.new(K2, AES.MODE_CBC, iv=iv2).encrypt(c1)
|
||||||
raise EOFError
|
return c2
|
||||||
return bytes.fromhex(s.strip())
|
|
||||||
|
|
||||||
def rand(rng, d, lo, hi):
|
def menu():
|
||||||
while True:
|
print("""
|
||||||
v = [rng.randint(lo, hi) for _ in range(d)]
|
1. encrypt
|
||||||
if any(v):
|
2. profit
|
||||||
return v
|
3. get third
|
||||||
|
4. exit
|
||||||
|
""")
|
||||||
|
|
||||||
def syst(rng):
|
third = 0
|
||||||
d = rng.choice([2, 3])
|
iv11 = None
|
||||||
m = rng.randint(5, 8)
|
iv22 = None
|
||||||
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)
|
|
||||||
|
|
||||||
def bundle():
|
def alarm():
|
||||||
rng = random.Random(os.urandom(16))
|
time.sleep(180)
|
||||||
systems = []
|
print("zzz")
|
||||||
hidden = []
|
sys.exit(0)
|
||||||
for _ in range(4):
|
|
||||||
pub, x = syst(rng)
|
|
||||||
systems.append(pub)
|
|
||||||
hidden.append(x)
|
|
||||||
return {"systems": systems}, tuple(hidden)
|
|
||||||
|
|
||||||
def get_key(saltx: bytes, salty: bytes, b):
|
threading.Thread(target=alarm, daemon=True).start()
|
||||||
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)
|
|
||||||
|
|
||||||
def main():
|
while True:
|
||||||
a, b = bundle()
|
menu()
|
||||||
print(json.dumps(a, separators=(",", ":")), flush=True)
|
op = input("> ").strip()
|
||||||
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
|
|
||||||
|
|
||||||
if choice == 1:
|
if op == "1":
|
||||||
data = inp_hex("data: ")
|
data = read_hex("pt: ")
|
||||||
iv, ct = enc(key, data)
|
if data is None:
|
||||||
print(iv.hex())
|
print()
|
||||||
print(ct.hex())
|
continue
|
||||||
|
out = enc_cfb(data)
|
||||||
|
print("ct: ", out.hex())
|
||||||
|
print()
|
||||||
|
|
||||||
elif choice == 2:
|
elif op == "2":
|
||||||
print(iv.hex())
|
if iv11 is not None and iv22 is not None:
|
||||||
print(ct.hex())
|
iv1, iv2 = iv11, iv22
|
||||||
print(saltx.hex())
|
iv11 = iv22 = None
|
||||||
print(salty.hex())
|
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:
|
elif op == "3":
|
||||||
print("bubay")
|
if third:
|
||||||
return
|
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:
|
elif op == "4":
|
||||||
print("when you feel like quitting, remember why you started :v (yapping)")
|
break
|
||||||
|
else:
|
||||||
except Exception:
|
print("mabokkkk?")
|
||||||
print("zzz")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
|
|||||||
Vendored
+100
-100
@@ -1,116 +1,116 @@
|
|||||||
#!/usr/bin/env python3
|
#!/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.Cipher import AES
|
||||||
from Crypto.Util.Padding import pad
|
from Crypto.Util.Padding import pad, unpad
|
||||||
with open("/flag.txt", "rb") as f:
|
|
||||||
|
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()
|
flag = f.read()
|
||||||
|
|
||||||
B = 16
|
|
||||||
opts = (
|
|
||||||
"1) encrypt\n"
|
|
||||||
"2) profit\n"
|
|
||||||
"3) nyerah\n"
|
|
||||||
">> "
|
|
||||||
)
|
|
||||||
|
|
||||||
def exp(prk: bytes, info: bytes, L: int) -> bytes:
|
def read_hex(prompt: str):
|
||||||
return hmac.new(prk, info + b"\x01", hashlib.sha256).digest()[:L]
|
s = input(prompt).strip()
|
||||||
|
try:
|
||||||
|
return binascii.unhexlify(s)
|
||||||
|
except Exception:
|
||||||
|
print("hmm")
|
||||||
|
return None
|
||||||
|
|
||||||
def enc(k: bytes, data: bytes):
|
def enc_cfb(pt: bytes) -> bytes:
|
||||||
iv = os.urandom(B)
|
iv = os.urandom(16)
|
||||||
ct = AES.new(k, AES.MODE_CBC, iv).encrypt(pad(data, B))
|
aes = AES.new(key, AES.MODE_CFB, iv=iv, segment_size=128)
|
||||||
return iv, ct
|
ct = aes.encrypt(pt)
|
||||||
|
return iv + ct
|
||||||
|
|
||||||
def inp_hex(prompt: str) -> bytes:
|
def enc_cbc(data: bytes, iv1: bytes, iv2: bytes, padd: bool) -> bytes:
|
||||||
print(prompt, end="", flush=True)
|
x = pad(data, 16) if padd else data
|
||||||
s = sys.stdin.readline()
|
c1 = AES.new(K1, AES.MODE_CBC, iv=iv1).encrypt(x)
|
||||||
if not s:
|
c2 = AES.new(K2, AES.MODE_CBC, iv=iv2).encrypt(c1)
|
||||||
raise EOFError
|
return c2
|
||||||
return bytes.fromhex(s.strip())
|
|
||||||
|
|
||||||
def rand(rng, d, lo, hi):
|
def menu():
|
||||||
while True:
|
print("""
|
||||||
v = [rng.randint(lo, hi) for _ in range(d)]
|
1. encrypt
|
||||||
if any(v):
|
2. profit
|
||||||
return v
|
3. get third
|
||||||
|
4. exit
|
||||||
|
""")
|
||||||
|
|
||||||
def syst(rng):
|
third = 0
|
||||||
d = rng.choice([2, 3])
|
iv11 = None
|
||||||
m = rng.randint(5, 8)
|
iv22 = None
|
||||||
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)
|
|
||||||
|
|
||||||
def bundle():
|
def alarm():
|
||||||
rng = random.Random(os.urandom(16))
|
time.sleep(180)
|
||||||
systems = []
|
print("zzz")
|
||||||
hidden = []
|
sys.exit(0)
|
||||||
for _ in range(4):
|
|
||||||
pub, x = syst(rng)
|
|
||||||
systems.append(pub)
|
|
||||||
hidden.append(x)
|
|
||||||
return {"systems": systems}, tuple(hidden)
|
|
||||||
|
|
||||||
def get_key(saltx: bytes, salty: bytes, b):
|
threading.Thread(target=alarm, daemon=True).start()
|
||||||
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)
|
|
||||||
|
|
||||||
def main():
|
while True:
|
||||||
a, b = bundle()
|
menu()
|
||||||
print(json.dumps(a, separators=(",", ":")), flush=True)
|
op = input("> ").strip()
|
||||||
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
|
|
||||||
|
|
||||||
if choice == 1:
|
if op == "1":
|
||||||
data = inp_hex("data: ")
|
data = read_hex("pt: ")
|
||||||
iv, ct = enc(key, data)
|
if data is None:
|
||||||
print(iv.hex())
|
print()
|
||||||
print(ct.hex())
|
continue
|
||||||
|
out = enc_cfb(data)
|
||||||
|
print("ct: ", out.hex())
|
||||||
|
print()
|
||||||
|
|
||||||
elif choice == 2:
|
elif op == "2":
|
||||||
print(iv.hex())
|
if iv11 is not None and iv22 is not None:
|
||||||
print(ct.hex())
|
iv1, iv2 = iv11, iv22
|
||||||
print(saltx.hex())
|
iv11 = iv22 = None
|
||||||
print(salty.hex())
|
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:
|
elif op == "3":
|
||||||
print("bubay")
|
if third:
|
||||||
return
|
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:
|
elif op == "4":
|
||||||
print("when you feel like quitting, remember why you started :v (yapping)")
|
break
|
||||||
|
else:
|
||||||
except Exception:
|
print("mabokkkk?")
|
||||||
print("zzz")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
|
|||||||
Reference in New Issue
Block a user