cscg ist super
This commit is contained in:
28
2026/cscg/crypto/zipper/Dockerfile
Normal file
28
2026/cscg/crypto/zipper/Dockerfile
Normal file
@@ -0,0 +1,28 @@
|
||||
FROM sagemath/sagemath:10.6@sha256:19995db6194f4a4bab18ce9a88556fd15b9ed5e916b4504fefe618a7796ddbdb
|
||||
|
||||
USER root
|
||||
|
||||
ADD --chmod=0755 --checksum=sha256:c125df9762b0c7233459087bb840c0e5dbfc4d9690ee227f1ed8994f4d51d2e0 \
|
||||
https://raw.githubusercontent.com/reproducible-containers/repro-sources-list.sh/v0.1.4/repro-sources-list.sh \
|
||||
/usr/local/bin/repro-sources-list.sh
|
||||
RUN repro-sources-list.sh
|
||||
|
||||
RUN apt-get update && apt-get install -y xinetd
|
||||
|
||||
RUN sage -pip install --no-cache-dir --upgrade pip
|
||||
RUN sage -pip install --no-cache-dir pycryptodome
|
||||
|
||||
RUN mkdir /ctf
|
||||
WORKDIR /ctf
|
||||
|
||||
RUN echo "Connection blocked." > /etc/banner_fail
|
||||
COPY ctf.xinetd /etc/xinetd.d/ctf
|
||||
|
||||
COPY run.sh .
|
||||
COPY challenge.py .
|
||||
|
||||
RUN chown -R root:sage /ctf && chmod -R 750 /ctf && chmod 777 /ctf/run.sh && chmod 770 /ctf
|
||||
|
||||
CMD [ "xinetd", "-dontfork" ]
|
||||
|
||||
EXPOSE 1337
|
||||
90
2026/cscg/crypto/zipper/challenge.py
Normal file
90
2026/cscg/crypto/zipper/challenge.py
Normal file
@@ -0,0 +1,90 @@
|
||||
from sage.all import *
|
||||
from Crypto.Util.number import long_to_bytes
|
||||
from Crypto.Util.Padding import pad
|
||||
import gzip, base64, os, string, random
|
||||
|
||||
FLAG = os.getenv("FLAG", "dach2026{fake_flag}")
|
||||
REQUIRED_WINS = 25
|
||||
|
||||
p = 0x1337
|
||||
Fp = GF(p)
|
||||
|
||||
I = matrix.random(Fp, 4)
|
||||
|
||||
def hash(message: bytes):
|
||||
m = pad(message, 25)
|
||||
assert len(m) % 25 == 0
|
||||
|
||||
sections = []
|
||||
for i in range(0, len(m), 25):
|
||||
block = int(m[i:i+25].hex(), 16)
|
||||
|
||||
digits = []
|
||||
for _ in range(16):
|
||||
digits.append(block % p)
|
||||
block //= p
|
||||
|
||||
sections.append(matrix(Fp, [digits[:4], digits[4:8], digits[8:12], digits[12:]]))
|
||||
|
||||
A = I
|
||||
for S in sections:
|
||||
A *= S
|
||||
|
||||
hashsum = 0
|
||||
for el in sum([list(r) for r in A.rows()], [])[::-1]:
|
||||
hashsum *= p
|
||||
hashsum += int(el)
|
||||
|
||||
return long_to_bytes(hashsum, 25)
|
||||
|
||||
def random_hash():
|
||||
return hash(os.urandom(25))
|
||||
|
||||
def random_message(n):
|
||||
return "".join([random.choice(string.ascii_letters) for _ in range(n)])
|
||||
|
||||
def main():
|
||||
print("Welcome to ZIPPER!")
|
||||
|
||||
wins = 0
|
||||
|
||||
while True:
|
||||
target_message = random_message(32)
|
||||
target_hash = random_hash() # Make this game impossible ( ͡° ͜ʖ ͡°)
|
||||
|
||||
print(f"I am thinking of a gzip file that decompresses to '{target_message}' and has a hash of '{target_hash.hex()}'.")
|
||||
print("What file am I thinking of?")
|
||||
user_input = input("> ")
|
||||
|
||||
try:
|
||||
file = base64.b64decode(user_input)
|
||||
file_hash = hash(file)
|
||||
|
||||
if len(file) == 0:
|
||||
continue
|
||||
|
||||
if file_hash != target_hash:
|
||||
wins = 0
|
||||
print(f"Wrong hash: {file_hash.hex()} != {target_hash.hex()}.")
|
||||
continue
|
||||
|
||||
if gzip.decompress(file).decode() != target_message:
|
||||
wins = 0
|
||||
print("Wrong data!")
|
||||
continue
|
||||
|
||||
wins += 1
|
||||
print(f"CORRECT! You have {REQUIRED_WINS-wins} wins more to go to get a prize!")
|
||||
|
||||
if wins >= REQUIRED_WINS:
|
||||
print("Congratulations, you've outguessed me!")
|
||||
print("\n" + FLAG + "\n")
|
||||
wins = 0
|
||||
except KeyboardInterrupt:
|
||||
exit(0)
|
||||
except:
|
||||
print("Wrong **insert whatever here**!")
|
||||
wins = 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
19
2026/cscg/crypto/zipper/ctf.xinetd
Normal file
19
2026/cscg/crypto/zipper/ctf.xinetd
Normal file
@@ -0,0 +1,19 @@
|
||||
service ctf
|
||||
{
|
||||
disable = no
|
||||
socket_type = stream
|
||||
protocol = tcp
|
||||
wait = no
|
||||
user = sage
|
||||
type = UNLISTED
|
||||
port = 1337
|
||||
bind = 0.0.0.0
|
||||
server = /bin/sh
|
||||
server_args = /ctf/run.sh
|
||||
banner_fail = /etc/banner_fail
|
||||
passenv = FLAG HOME
|
||||
# safety options
|
||||
per_source = 10 # the maximum instances of this service per source IP address
|
||||
rlimit_cpu = 1 # the maximum number of CPU seconds that the service may use
|
||||
#rlimit_as = 1024M # the Address Space resource limit for the service
|
||||
}
|
||||
8
2026/cscg/crypto/zipper/docker-compose.yml
Normal file
8
2026/cscg/crypto/zipper/docker-compose.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
version: "3"
|
||||
services:
|
||||
zipper:
|
||||
image: dach2026-cry-zipper:latest
|
||||
build:
|
||||
context: .
|
||||
ports:
|
||||
- "1337:1337"
|
||||
4
2026/cscg/crypto/zipper/run.sh
Normal file
4
2026/cscg/crypto/zipper/run.sh
Normal file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd /ctf
|
||||
sage -python challenge.py
|
||||
Reference in New Issue
Block a user