commit 83f9035d6b150adf0d5577756e0746c300db9664 Author: kadinho Date: Tue Sep 29 13:06:06 2026 +0100 Initial Docker packaging diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..82e9a94 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,14 @@ +.git +.gitmodules +.env +README.md +compose.yaml +app/.git +app/.github +app/.agents +app/.codex +app/LICENSE +app/README.md +app/serve.py +**/__pycache__ +**/*.pyc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c49bd7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.env diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..5115abc --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "app"] + path = app + url = https://github.com/ntfargo/Relapse-Exploit.git diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f4e4d83 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,28 @@ +ARG PYTHON_IMAGE=python:3.14-alpine +FROM ${PYTHON_IMAGE} + +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 \ + PORT=8080 + +WORKDIR /srv + +COPY payloads.sha256 /tmp/payloads.sha256 +COPY app/index.html /srv/public/index.html +COPY app/src /srv/public/src +COPY app/offsets /srv/public/offsets +COPY app/payloads /srv/public/payloads +COPY docker/server.py /srv/server.py + +RUN cd /srv/public && sha256sum -c /tmp/payloads.sha256 \ + && rm /tmp/payloads.sha256 \ + && chown -R 65532:65532 /srv + +USER 65532:65532 + +EXPOSE 8080 + +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD ["python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8080/', timeout=2).close()"] + +CMD ["python", "/srv/server.py"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..e82106a --- /dev/null +++ b/README.md @@ -0,0 +1,76 @@ +# Relapse Exploit Docker + +Container packaging for [PS5 Relapse Exploit](https://github.com/ntfargo/Relapse-Exploit). +The upstream project is pinned as a Git submodule, and the image build verifies the +SHA-256 digest of every executable payload before including it. + +Use this only on consoles you own or are authorized to test. The exploit can panic +the console, corrupt kernel state, expose administrative services, and execute +arbitrary code with elevated privileges. + +## Clone and build + +```sh +git clone --recurse-submodules +cd relapse-exploit-docker +docker compose build +``` + +For an existing clone: + +```sh +git submodule update --init --recursive +docker compose build +``` + +## Run + +```sh +docker compose up -d +``` + +Open `http://HOST-IP:8000/` from the PS5. View the service status with: + +```sh +docker compose ps +docker compose logs -f +``` + +Stop it with `docker compose down`. + +By default, port 8000 is exposed on every host interface so the PS5 can reach it. +Restrict it to one host address when possible: + +```sh +HOST_BIND=192.168.1.10 HOST_PORT=8000 docker compose up -d +``` + +Do not expose this service to the internet. Prefer an isolated local network. + +## Update upstream + +Review upstream changes before updating because the served JavaScript and payloads +ultimately execute with kernel privileges. + +```sh +git -C app fetch origin +git -C app checkout +sha256sum app/payloads/* +``` + +After reviewing the new binaries, update `payloads.sha256`, rebuild, test, and commit +both the submodule pointer and checksum changes together. + +## Container hardening + +The runtime image: + +- contains only the files required by the exploit page; +- runs as numeric user/group `65532:65532`; +- has a read-only filesystem, all Linux capabilities dropped, and no-new-privileges; +- disables directory listings and browser caching; +- adds restrictive browser security headers; +- does not expose the upstream `.git` directory. + +These controls protect the host-side web server. They do not make the PS5 exploit or +its precompiled payloads intrinsically safe. diff --git a/app b/app new file mode 160000 index 0000000..09f10f5 --- /dev/null +++ b/app @@ -0,0 +1 @@ +Subproject commit 09f10f5b58fab8a9ae9e8df214da37271290b13e diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..3284279 --- /dev/null +++ b/compose.yaml @@ -0,0 +1,15 @@ +services: + relapse-exploit: + build: + context: . + image: relapse-exploit:local + ports: + - "${HOST_BIND:-0.0.0.0}:${HOST_PORT:-8000}:8080" + read_only: true + tmpfs: + - /tmp:size=1m,mode=1777 + cap_drop: + - ALL + security_opt: + - no-new-privileges:true + restart: unless-stopped diff --git a/docker/server.py b/docker/server.py new file mode 100644 index 0000000..4799793 --- /dev/null +++ b/docker/server.py @@ -0,0 +1,46 @@ +import http.server +import mimetypes +import os +from pathlib import Path + + +PUBLIC_ROOT = Path("/srv/public") +PORT = int(os.environ.get("PORT", "8080")) + +mimetypes.add_type("text/javascript", ".js") +mimetypes.add_type("application/octet-stream", ".elf") +mimetypes.add_type("application/octet-stream", ".bin") + + +class Handler(http.server.SimpleHTTPRequestHandler): + def __init__(self, *args, **kwargs): + super().__init__(*args, directory=PUBLIC_ROOT, **kwargs) + + def list_directory(self, path): + self.send_error(404, "Not found") + return None + + def end_headers(self): + self.send_header("Cache-Control", "no-store, max-age=0") + self.send_header("Pragma", "no-cache") + self.send_header("X-Content-Type-Options", "nosniff") + self.send_header("X-Frame-Options", "DENY") + self.send_header("Referrer-Policy", "no-referrer") + self.send_header( + "Content-Security-Policy", + "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; " + "worker-src 'self'; child-src 'self'; connect-src 'self'; img-src 'self' data:; " + "object-src 'none'; base-uri 'none'; frame-ancestors 'none'", + ) + super().end_headers() + + +class Server(http.server.ThreadingHTTPServer): + daemon_threads = True + allow_reuse_address = True + + +if __name__ == "__main__": + with Server(("0.0.0.0", PORT), Handler) as server: + print(f"Serving Relapse Exploit on port {PORT}", flush=True) + server.serve_forever() diff --git a/payloads.sha256 b/payloads.sha256 new file mode 100644 index 0000000..615a3eb --- /dev/null +++ b/payloads.sha256 @@ -0,0 +1,5 @@ +de5dd480d12637527ba2d75e35de851adbb59c455293fa32588c492ef6b44b81 payloads/elfldr-ps5-1360.elf +26034dfbb88dd8be344fee1876c387bfcba0386edb079014e18ec25580368f6d payloads/etaHEN.elf +7cfb3a8cb86db67893c360ae3531f460f800e9f24039797038e6e81fc50f18a9 payloads/kexp_2026_05_25.bin +858880a8adbedaabfaced025384f4f6f908cfe44f1a049070ad8df911c22b972 payloads/kstuff.elf +0b30a1c23b83ebb2aa6523c8caaa5801ee89bde00e90cb36f392a29bb0bdb403 payloads/shadowmountplus.elf