Files
relapse-exploit-docker/docs/HANDOFF.md
T

366 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Maintainer and agent handoff
Last updated: 2026-10-02
This file is the durable handoff for future sessions. Start work from this
repository rather than from the upstream Relapse Exploit checkout.
## Current status
The Docker wrapper has been created, committed, pushed to the local Gitea, and
deployed successfully. The user confirmed that the exploit worked on the PS5 and
that opening the PS5 User Guide reached an exploit page directly.
The exact destination selected by the external DNS was not independently verified.
Do not assume that the User Guide page came from the local container merely because
it displayed Relapse. The local container is confirmed at the raw IP URL below.
## Repositories
Primary local workspace:
```text
/var/www/code/others/relapse-exploit-docker
```
Gitea push remote:
```text
[email protected]:TinyBacklog/relapse-exploit-docker.git
```
Gitea public clone URL:
```text
http://192.168.20.20:3000/TinyBacklog/relapse-exploit-docker.git
```
Upstream submodule:
```text
https://github.com/ntfargo/Relapse-Exploit.git
```
Pinned upstream commit:
```text
dd8e4e0914c5e9d066ee1f9b056be76cb992c8e0
```
Repository-local Git identity:
```text
kadinho <[email protected]>
```
## Live deployment
- host: `net-utils01`;
- host IP: `192.168.20.30`;
- SSH user used during setup: `root`;
- checkout: `/opt/relapse-exploit-docker`;
- service URL: `http://192.168.20.30:8000/`;
- image name: `relapse-exploit:local`;
- Compose service: `relapse-exploit`;
- container name generated by Compose:
`relapse-exploit-docker-relapse-exploit-1`;
- host port: `8000/TCP`;
- container port: `8080/TCP`;
- restart policy: `unless-stopped`.
The same Compose project also runs `ps5-guide-gateway`, bound specifically to
`192.168.20.30` on DNS UDP/TCP 53 and HTTP/HTTPS TCP 80/443. It resolves
`manuals.playstation.net` locally and forwards only `homebrew.page`, `github.com`
and `release-assets.githubusercontent.com` to the configured upstream resolver
(`1.1.1.1` by default). Every other name receives NXDOMAIN. The HTTP/HTTPS gateway
redirects the User Guide to `http://192.168.20.30:8000/`.
Port `8080` on the host is already used by `unifi-network-application`; do not move
this service there. At the last verification, the Relapse container was healthy,
ran as `65532:65532`, used a read-only root filesystem, and returned HTTP 200 over
the LAN. `/.git/config` returned 404.
No firewall management tool was detected on `net-utils01` during setup.
## Deployment authentication detail
`net-utils01` does not currently have a Gitea SSH client key authorized for cloning.
The deployment clone therefore uses the public HTTP URL. Do not copy personal SSH
private keys to the server or enable SSH agent forwarding as a workaround. If write
or authenticated access becomes necessary, create a repository-scoped deploy key.
The Gitea server's SSH fingerprints were compared with the already trusted local
host before its host keys were added to `/root/.ssh/known_hosts` on `net-utils01`.
## Runtime design
The image is based on `python:3.14-alpine` and uses only Python's standard library.
It copies these upstream assets into `/srv/public`:
- `index.html`;
- `src/`;
- `offsets/`;
- `payloads/`.
The build validates every payload listed in `payloads.sha256`. The server disables
directory listing and caching, sends restrictive browser headers, and runs under
numeric UID/GID 65532. Compose additionally makes the root filesystem read-only,
drops all Linux capabilities, and enables `no-new-privileges`.
The base image tag is not digest-pinned in the Dockerfile. A prior successful build
resolved `python:3.14-alpine` to:
```text
sha256:9e9fde4d32eedce0b661d9ab91e826b62dddf28e928c230ec55f1866cac66b01
```
Treat that as historical build information, not as an instruction to pin it without
checking architecture support and update policy.
## Approved payload hashes
At the pinned upstream commit:
```text
de5dd480d12637527ba2d75e35de851adbb59c455293fa32588c492ef6b44b81 payloads/elfldr-ps5-1360.elf
7cfb3a8cb86db67893c360ae3531f460f800e9f24039797038e6e81fc50f18a9 payloads/kexp_2026_05_25.bin
```
The payloads are precompiled, stripped binaries. Hash matching proves consistency
with the reviewed snapshot; it does not prove that the binaries are safe.
This upstream revision removed etaHEN, KStuff, and ShadowMount+ plus the `R2`
auto-loader because those optional payloads caused compatibility issues. The page
now stops after starting the ELF loader; any additional reviewed ELF must be sent
externally to the PS5 on TCP port 9021.
## External payload candidate evidence
A controlled intake and startup smoke test was completed on 2026-10-02 for
kstuff-lite v1.11 and ShadowMountPlus 1.7beta3. Locally calculated SHA-256 digests
matched the digests published by GitHub's release API. The verified ELFs were sent
once from `net-utils01` to `192.168.40.14:9021`, in that order and separated by
more than two seconds. Both connected and returned successful startup output;
ShadowMountPlus identified firmware 13.20, installed its hooks, synchronized an
empty game library and bound its API only to `127.0.0.1:10101`. The temporary
server copies were removed, and no downloaded binary is stored in this repository.
The normalized, machine-readable evidence and the proposed payload-manager import
contract and test limitations are in
[`docs/payload-evidence/`](payload-evidence/README.md). The required order is
kstuff-lite first, followed by ShadowMountPlus only after kstuff startup has been
confirmed. Catalog entries remain disabled and non-favorite by default despite the
successful smoke test; user selection is separate from evidence.
## PS5 and DNS state
The PS5 now uses the static address:
```text
192.168.40.14
```
The local HTTP endpoint is available and verified at:
```text
http://192.168.20.30:8000/
```
The upstream public DNS `45.56.67.85` was used initially, but the PS5 did not contact
the local container. The local gateway was therefore added. Configure the PS5 with
primary DNS `192.168.20.30` and secondary DNS `0.0.0.0`, then restart the console and
accept the self-signed certificate warning in the User Guide.
The gateway provides allowlisted recursive DNS forwarding only for `homebrew.page`,
`github.com` and `release-assets.githubusercontent.com`. Only those names and
`manuals.playstation.net` resolve; all other names receive NXDOMAIN. This permits
the homebrew store catalog and HTTPS release downloads while continuing to block
PSN and update resolution. The PS5 sends DNS only to `net-utils01`; that host must
be allowed to reach the configured upstream resolver on UDP/TCP 53.
The PS5 was previously identified as `192.168.10.26`; requests from
`192.168.10.6` seen at that time were from a different client. Those addresses
are historical and must not be used as the current payload destination.
The PS5 ELF loader listens on TCP port `9021` after a successful exploit run. On
2026-10-01, a connection-only probe from `net-utils01` to
`192.168.40.14:9021` succeeded after inter-VLAN access was enabled. The probe
used `nc -vz`, sent no ELF payload, and confirmed that a new TCP connection from
the server VLAN to the console VLAN was permitted. `netcat-openbsd` is installed
on `net-utils01` for this diagnostic. Keep the applicable network policy limited
to the required LAN source, destination and TCP port; never expose port `9021`
to the Internet.
The inter-VLAN firewall policy reported as configured is:
| Source | Destination | Protocol/port | Purpose/state |
| --- | --- | --- | --- |
| `net-utils01` (`192.168.20.30`) | PS5 (`192.168.40.14`) | TCP `9021` | payload manager to ELF loader; active |
| PS5 (`192.168.40.14`) | `net-utils01` (`192.168.20.30`) | TCP `80`, `443`, `8000`; UDP/TCP `53` | Relapse page, User Guide gateway and restricted DNS; active |
| PS5 (`192.168.40.14`) | `net-utils01` (`192.168.20.30`) | TCP `8001` | reserved for payload-manager phase 5; enable only during that phase |
| PS5 (`192.168.40.14`) | remaining `192.168.20.0/24` hosts | all | blocked |
| hosts other than `net-utils01` | PS5 (`192.168.40.14`) | TCP `9021` | blocked |
The specific allow rules must be evaluated before the broader deny rules. Keep
TCP `8001` disabled until phase 5 has a reviewed service that requires it. The
successful TCP `9021` probe independently verifies that particular allow path;
the complete firewall policy was not audited from this repository.
Full PS5 instructions and DNS options are in `docs/PS5_SETUP.md`.
### Y2JB controlled test (2026-10-02; kernel/loader startup verified)
The PS5 Pro is on firmware 13.20. Its separate offline test user is `PLAYER1`
(slot 2); ActRemoteLink activated that slot and enabled user/global Remote Play.
Fake sign-in was **not** executed: reviewed implementations also write base
registry state, so isolation from the existing personal account is unproven.
Remote Play pairing remains untested.
The local YouTube PKG metadata identifies `PPSA01652`, version `01.000.030`,
Content ID `JA0004-PPSA01652_00-YOUTUBESIEJA0000`, despite its filename saying EUR.
Y2JB 1.6 was initially placed under `PPSA01650`. A subsequent PSN/DNS dialog loop
persisted with both local restricted DNS and primary DNS `127.0.0.2`.
At that point neither the cause nor successful Y2JB launch had been established;
the later successful run is recorded in
[`docs/Y2JB_TEST_2026-10-02.md`](Y2JB_TEST_2026-10-02.md).
The approved directory correction placed the verified Y2JB 1.6 file at
`/user/download/PPSA01652/download0.dat` (336789504 bytes). Its source and complete
destination reread matched SHA-256
`946fb64427d340a1a302d260e0cc448b50fe15cfcff8ea167a0d33d3aa76f39d`.
An existing, different file was preserved on the PS5 as
`/user/download/PPSA01652/download0.dat.before-y2jb-20261002T150112Z`;
its reread SHA-256 is
`dc553ea85aab9da884316c0fe9bb222da3e8d384ddf2c1fd119779b11c8a79c1`.
The original `PPSA01650` copy remains untouched. Do not delete the backup without
approval. After a normal reboot the user's screenshot confirmed Y2JB 1.6,
firmware 13.20, Title ID PPSA01652, app version 01.000.030, popups disabled, and
Remote JS Loader listening at `192.168.40.14:50000`. This demonstrates working
userland startup without fake sign-in; the exact cause of the earlier loop is
not isolated because both directory and file contents differed.
After the user enabled a temporary net-utils01 → PS5 TCP 50000 exception,
`edisnord/relapse-y2jb` v1.0.0 `relapse.js` (261458 bytes, SHA-256
`f85129b861f43a19f6810be5182aecdcf82a25e59ee5fbcd0604e4a4e2a40d69`)
was sent once. Output identified 13.20 offsets, kernel privileges ready, kexp
return zero, restored eboot descriptors, both real pipe buffers restored with
10/10 writes verified, completed teardown and ELF loader on 9021. A subsequent
connection-only TCP 9021 probe succeeded. The JS temporary copy was removed.
This is a startup smoke test, not proof of long-term stability, safe app closure
on this firmware, Remote Play pairing or homebrew operation in this boot.
The payload leaves three kernel sysctl OIDs modified until reboot, including
`kern.smp.cpus` returning a kernel address instead of a CPU count. App-close safety
is asserted by the output but upstream measured it only on 12.60; do not present
that as independently verified on 13.20. Do not send another kernel exploit in
an already exploited session. Disable temporary TCP 50000 when not needed.
The user then closed YouTube. A connection-only probe confirmed TCP 9021 remained
accessible and no immediate crash was observed. Using that surviving loader,
kstuff-lite v1.11 and ShadowMountPlus 1.7beta3 were downloaded again, verified
against the hashes in `docs/payload-evidence/`, and sent in order with more than
four seconds between them. KStuff reported its app.db and SceShellUI patches;
ShadowMountPlus detected 13.20, installed ShellCore hooks, initialized KStuff
runtime control, synchronized zero games and exposed its API only at
`127.0.0.1:10101`. No mount, game, API, suspend/resume or shutdown test was made.
Temporary payload copies were removed. This confirms the full startup chain
YouTube → Y2JB → Relapse → KStuff → ShadowMountPlus on this boot, not prolonged
stability.
FTP used `ps5-payload-dev/ftpsrv` v0.21.1, SHA-256
`7d4b31c83eae4e056580482a3a074e1db25922efc74ac1e439473b45d71a5938`.
Active-mode tests failed with `550 Bad file descriptor`; passive mode succeeded.
Temporary pfSense exceptions from net-utils01 to PS5 are TCP 2121 and
49152–65535, restricted to those two IPs. FTP was terminated with KILL. Disable
these rules when the test is complete; TCP 31337 (ActRemoteLink) is also temporary.
The obsolete reverse active-FTP exception PS5 → net-utils01 TCP 20212 is not needed.
PKG Manager v1.4.1 runs in memory on PS5 TCP 8844, with Direct Install TCP 18842;
restart the reviewed payload after a PS5 reboot. Access through loopback SSH
forwards, with matching net-utils01 → PS5 firewall exceptions only. This does not
install or start the Y2JB autoloader. itsPLK autoloader v0.9.1 has no supported
kernel exploit for 13.20; v1.0.0-dev-794049f adds Relapse but remains experimental
and has not been installed in this test.
The proposed long-term integration uses the Y2JB Autoloader only for
YouTube/Y2JB → Relapse → ELF loader. The external Payload Manager on net-utils01
retains ownership of post-jailbreak payload discovery, integrity checks,
dependency ordering and audit logs. Do not configure KStuff or ShadowMountPlus
in `autoload.txt` for that design. The autoloader's default loopback-only ELF
loader is incompatible with an external sender; a reviewed LAN-accessible loader
is required, protected by the existing source-specific TCP 9021 firewall rule.
The full contract and session-state model are documented in
`docs/Y2JB_TEST_2026-10-02.md` and `docs/payload-evidence/README.md`.
**Server memory constraint:** net-utils01 has about 1.9 GiB RAM and no swap;
`/tmp` is tmpfs. Staging approximately 622 MiB of Y2JB files there caused severe
memory pressure with SSH/HTTP stalls; removal restored SSH. Use a verified
disk-backed path instead (`/var/tmp` is currently on ext4 `/dev/sda1`, about 70 GiB
free). Check memory and mount type before future payload staging. Test downloads
must be removed explicitly after verification; do not clear service-owned tmp dirs.
## Common operations
Inspect the live service:
```sh
ssh net-utils01
cd /opt/relapse-exploit-docker
docker compose ps
docker compose logs -f
```
Synchronize documentation-only changes:
```sh
cd /opt/relapse-exploit-docker
git pull --ff-only
git submodule update --init --recursive
```
Deploy runtime changes:
```sh
cd /opt/relapse-exploit-docker
git pull --ff-only
git submodule update --init --recursive
docker compose up -d --build
docker compose ps
curl -I http://127.0.0.1:8000/
```
Stop or restart:
```sh
docker compose down
docker compose up -d
# or
docker compose restart
```
## Known risks and review findings
The upstream project deliberately exploits WebKit and the PS5 kernel, escalates the
browser process to root, escapes its sandbox, and executes ELF payloads.
Important upstream findings from the initial static review:
1. Payloads are executable privileged binaries without upstream signature
verification or reproducible-build evidence.
2. The AIO cleanup path marks groups as defused even when cleanup reports failure,
which can leave risky kernel state behind.
3. Some early kernel failures return a result that the UI can misreport as root and
sandbox escape success.
4. The ELF loader on port 9021 is an arbitrary-payload interface by design.
The wrapper's checksum and container hardening mitigate host-side packaging risks;
they do not correct these upstream kernel or payload risks.
## Next-session checklist
1. Read this file, `AGENTS.md`, and `docs/PS5_SETUP.md`.
2. Run `git status --short --branch` and `git submodule status`.
3. Confirm the requested task's scope before changing the upstream submodule.
4. Preserve the payload-integrity and container-hardening invariants.
5. Validate proportionally to the change.
6. Update this handoff if infrastructure or operational state changes.
7. Push `main` to Gitea and, when appropriate, synchronize `net-utils01`.