cscg24-haunted

CSCG 2024 Challenge 'Haunted'
git clone https://git.sinitax.com/sinitax/cscg24-haunted
Log | Files | Refs | sfeed.txt

commit 29cd7d3e26fb5065cfe3394fb27be09f1981f568
parent a97e078890abc0a33a65cd3b20d267791a034cc1
Author: Louis Burda <quent.burda@gmail.com>
Date:   Sun, 28 Apr 2024 17:27:59 +0200

State

Diffstat:
Asolve/.gitignore | 1+
Asolve/BOOTX64.efi | 0
Asolve/BOOTX64.efi.bndb | 0
Asolve/Dockerfile | 27+++++++++++++++++++++++++++
Asolve/OVMF_CODE.fd | 0
Asolve/OVMF_VARS.fd | 0
Asolve/disk.img | 0
Asolve/docker-compose.yml | 6++++++
Asolve/edk2 | 1+
Asolve/server.py | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asolve/solve | 16++++++++++++++++
11 files changed, 134 insertions(+), 0 deletions(-)

diff --git a/solve/.gitignore b/solve/.gitignore @@ -0,0 +1 @@ +edk2 diff --git a/solve/BOOTX64.efi b/solve/BOOTX64.efi Binary files differ. diff --git a/solve/BOOTX64.efi.bndb b/solve/BOOTX64.efi.bndb Binary files differ. diff --git a/solve/Dockerfile b/solve/Dockerfile @@ -0,0 +1,27 @@ +# docker build -t haunted . && docker run -p 1024:1024 --rm -it haunted +FROM ubuntu@sha256:f9d633ff6640178c2d0525017174a688e2c1aef28f0a0130b26bd5554491f0da + +ADD --chmod=0755 --checksum=sha256:4e7e6536b206488b2414d1fa2272e8bbf17fbe7d11e5648eb51284c8fa96b0a9 \ + https://raw.githubusercontent.com/reproducible-containers/repro-sources-list.sh/v0.1.1/repro-sources-list.sh \ + /usr/local/bin/repro-sources-list.sh + +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + /usr/local/bin/repro-sources-list.sh && \ + apt-get update && \ + DOCKER_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + python3 qemu-system-x86 + +RUN useradd --create-home --shell /bin/bash ctf + +COPY server.py OVMF_CODE.fd OVMF_VARS.fd /home/ctf/ + +RUN chown -R root:ctf /home/ctf && \ + chmod -R 0000 /home/ctf/* && \ + chmod 770 /home/ctf && \ + chmod 040 /home/ctf/OVMF_CODE.fd /home/ctf/OVMF_VARS.fd /home/ctf/server.py + +WORKDIR /home/ctf/ +USER ctf +EXPOSE 1024 +ENTRYPOINT ["python3", "/home/ctf/server.py"] diff --git a/solve/OVMF_CODE.fd b/solve/OVMF_CODE.fd Binary files differ. diff --git a/solve/OVMF_VARS.fd b/solve/OVMF_VARS.fd Binary files differ. diff --git a/solve/disk.img b/solve/disk.img Binary files differ. diff --git a/solve/docker-compose.yml b/solve/docker-compose.yml @@ -0,0 +1,6 @@ +services: + haunted: + build: + context: . + ports: + - "1024:1024" diff --git a/solve/edk2 b/solve/edk2 @@ -0,0 +1 @@ +Subproject commit c0dfe3ec1f364dbdaf6b241e01343e560b21dd03 diff --git a/solve/server.py b/solve/server.py @@ -0,0 +1,83 @@ +import os +import selectors +import shutil +import signal +import socketserver +import subprocess +import tempfile +from os import fdopen + +TIMEOUT = 60 * 10 # timeout after ten minutes + + +class Handler(socketserver.BaseRequestHandler): + def handle(self): + self.request.sendall( + f"[?] Please provide the boot disk in hex format.\n".encode() + ) + self.request.sendall(f'[*] End your input with "EOF"\n'.encode()) + + buffer = b"" + while b"EOF" not in buffer: + buffer += self.request.recv(1024) + buffer = buffer.replace(b"EOF", b"").lower() + try: + buffer = bytes(list(filter(lambda x: chr(x) in "0123456789abcdef", buffer))) + + data = bytes.fromhex(buffer.decode()) + except: + self.request.sendall(f"[!] Invalid input... bye!\n".encode()) + return + + fd, disk_path = tempfile.mkstemp() + with fdopen(fd, "wb") as f: + f.write(data) + + # make sure we use the fresh vars every time + shutil.copy("OVMF_VARS.fd", "OVMF_VARS_CURRENT.fd") + os.chmod("OVMF_VARS_CURRENT.fd", 0o660) + + cmd = [ + "/usr/bin/qemu-system-x86_64", + "-cpu", + "max", + "-machine", + "q35", + "-drive", + "if=pflash,format=raw,readonly=on,unit=0,file=OVMF_CODE.fd", + "-drive", + "if=pflash,format=raw,unit=1,file=OVMF_VARS_CURRENT.fd", + "-drive", + f"file={disk_path},if=none,id=disk1,format=raw", + "-device", + "ide-hd,drive=disk1,bootindex=1", + "-monitor", + "none", + "-display", + "none", + "-nographic", + ] + + self.request.sendall(f"[*] Starting qemu, good luck!\n".encode()) + + signal.signal( + signal.SIGALRM, + lambda _n, _f: [self.request.sendall(b"[!] Timed out..\n"), exit(1)], + ) + signal.alarm(TIMEOUT) + subprocess.call( + cmd, + stdin=subprocess.DEVNULL, + stdout=self.request.fileno(), + stderr=self.request.fileno(), + ) + + +with socketserver.ForkingTCPServer(("0.0.0.0", 1024), Handler) as server: + server.allow_reuse_address = True + with selectors.PollSelector() as selector: + selector.register(server, selectors.EVENT_READ) + while True: + ready = selector.select(0.5) + if ready: + server._handle_request_noblock() diff --git a/solve/solve b/solve/solve @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 + +from tqdm import tqdm +from pwn import * + +args = sys.argv[1:] +if len(args) == 0: + args = ["nc", "127.0.0.1", "1024"] +io = process(args) + +print(io.readline()) +msg = (open("disk.img", "rb").read().hex() + "EOF").encode() +for i in tqdm(range(0, len(msg), 1024)): + io.send(msg[i:i+1024]) +context.log_level = "DEBUG" +io.interactive()