From 38e68cf16585383c34cc2e222f7b15c3e8c9e830 Mon Sep 17 00:00:00 2001 From: kadinho Date: Fri, 2 Oct 2026 20:14:53 +0100 Subject: [PATCH] docs: record PS5 payload and Y2JB tests --- README.md | 2 + docs/HANDOFF.md | 123 +++++++++- docs/PS5_SETUP.md | 42 +++- docs/Y2JB_TEST_2026-10-02.md | 161 +++++++++++++ docs/payload-evidence/README.md | 128 +++++++++++ .../manifest-2026-10-02.v1.json | 212 ++++++++++++++++++ 6 files changed, 662 insertions(+), 6 deletions(-) create mode 100644 docs/Y2JB_TEST_2026-10-02.md create mode 100644 docs/payload-evidence/README.md create mode 100644 docs/payload-evidence/manifest-2026-10-02.v1.json diff --git a/README.md b/README.md index 79309be..79d2ece 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ Documentation: - [PS5 setup, DNS, deployment, and troubleshooting](docs/PS5_SETUP.md) - [Maintainer and agent handoff](docs/HANDOFF.md) +- [Y2JB / Relapse controlled test record](docs/Y2JB_TEST_2026-10-02.md) +- [External payload candidate evidence](docs/payload-evidence/README.md) - [Repository instructions for coding agents](AGENTS.md) ## Clone and build diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md index cae8ac7..f4b9830 100644 --- a/docs/HANDOFF.md +++ b/docs/HANDOFF.md @@ -1,6 +1,6 @@ # Maintainer and agent handoff -Last updated: 2026-10-01 +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. @@ -132,8 +132,32 @@ auto-loader because those optional payloads caused compatibility issues. The pag 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 @@ -148,11 +172,104 @@ accept the self-signed certificate warning in the User Guide. The gateway intentionally provides no recursive DNS forwarding. Only `manuals.playstation.net` resolves; all other names receive NXDOMAIN. This blocks PSN and update resolution and keeps the setup independent of a public DNS operator. -The PS5 was identified as `192.168.10.26`; requests from `192.168.10.6` seen earlier -were from a different client. +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. + +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. + +**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: diff --git a/docs/PS5_SETUP.md b/docs/PS5_SETUP.md index 4ada388..ae4d74c 100644 --- a/docs/PS5_SETUP.md +++ b/docs/PS5_SETUP.md @@ -20,6 +20,7 @@ Na rede onde este projeto foi inicialmente instalado: - porta publicada: `8000`. - DNS local: `192.168.20.30:53` (UDP e TCP); - gateway do Guia: `192.168.20.30:80` e `192.168.20.30:443`. +- IP estático atual da PS5: `192.168.40.14`. A porta 8080 do host já pertence ao UniFi e não deve ser reutilizada. @@ -88,7 +89,8 @@ Editar a ligação ativa em: Selecionar a rede, carregar em `Options` e abrir `Definições avançadas`: -- endereço IP: automático; +- endereço IP: manter a configuração estática existente (`192.168.40.14`) nesta + instalação; noutras redes, usar os parâmetros fornecidos pelo administrador; - nome do host DHCP: não especificar; - DNS: manual; - MTU: automático; @@ -167,7 +169,7 @@ Com um DNS que redirecione o manual: 3. abrir `Guia do Utilizador`; 4. confirmar que aparece a página Relapse esperada; 5. aceitar o aviso de certificado self-signed, se aparecer; -6. confirmar nos logs que o cliente `192.168.10.26` consultou o DNS e abriu o +6. confirmar nos logs que o cliente `192.168.40.14` consultou o DNS e abriu o gateway; 7. confirmar que o destino final é `192.168.20.30:8000`. @@ -209,6 +211,19 @@ uma mensagem genérica de conclusão prova que todas as etapas terminaram corret Manter o carregamento de payloads limitado à LAN confiável. Nunca publicar a porta 9021 na Internet e não enviar um ELF que não tenha sido previamente revisto. +Na instalação atual, um teste de ligação sem payload confirmou o caminho +`192.168.20.30` (`net-utils01`) para `192.168.40.14:9021`. A regra entre VLANs +deve permanecer limitada a essa origem, destino, protocolo e porta. + +As regras da instalação permitem ainda que a PS5 alcance apenas os serviços +necessários no `net-utils01`: TCP `80`, `443` e `8000`, e DNS UDP/TCP `53`. O +restante acesso da PS5 à rede `192.168.20.0/24` está bloqueado. Outros hosts não +podem alcançar o ELF loader da PS5 em TCP `9021`. As exceções específicas devem +ser avaliadas antes dos bloqueios gerais na firewall. + +Está prevista uma exceção da PS5 para TCP `8001` no `net-utils01` apenas para a +fase 5 do payload manager. Manter essa exceção desativada até existir um serviço +revisto que precise efetivamente da porta. ## Operação no net-utils01 @@ -279,7 +294,19 @@ docker compose logs --tail=100 ps5-guide-gateway Depois reiniciar completamente a consola para limpar resoluções antigas. Se não existir qualquer consulta proveniente do IP da PS5, verificar regras entre as VLANs -`192.168.10.0/24` e `192.168.20.0/24`, incluindo UDP/TCP 53 e TCP 80/443/8000. +`192.168.40.0/24` e `192.168.20.0/24`, incluindo UDP/TCP 53 e TCP 80/443/8000. + +Para testar apenas se o servidor consegue alcançar o ELF loader, sem enviar um +payload: + +```sh +ssh net-utils01 +nc -vz -w 5 192.168.40.14 9021 +``` + +Executar o teste apenas quando a PS5 apresentar que o loader está à espera na +porta `9021`. Um timeout indica normalmente filtragem ou ausência de caminho; uma +ligação bem-sucedida confirma apenas a conectividade TCP, não valida um payload. ### O build falha nos hashes @@ -307,3 +334,12 @@ Estas proteções não tornam os payloads seguros. Os dois binários incluídos pré-compilados e executados no processo de obter acesso privilegiado à consola. Manter a PS5 numa rede isolada, não usar a conta principal e conservar backups dos dados. + +## Evidência do teste Y2JB / Relapse + +O teste controlado em PS5 Pro 13.20, incluindo versões e hashes, caminhos FTP, +regras temporárias, resultado e limitações, está em +[`Y2JB_TEST_2026-10-02.md`](Y2JB_TEST_2026-10-02.md). Em especial, o teste confirmou +o ELF loader na porta 9021, mas não comprovou estabilidade prolongada nem a +segurança ao fechar YouTube neste firmware. Reiniciar normalmente antes de +repetir a cadeia de exploit. diff --git a/docs/Y2JB_TEST_2026-10-02.md b/docs/Y2JB_TEST_2026-10-02.md new file mode 100644 index 0000000..553c062 --- /dev/null +++ b/docs/Y2JB_TEST_2026-10-02.md @@ -0,0 +1,161 @@ +# Teste YouTube → Y2JB → Relapse (2026-10-02) + +Resultado: Y2JB e Relapse completaram o arranque em PS5 Pro firmware 13.20; o +ELF loader na porta TCP 9021 ficou acessível. O teste não mede estabilidade +prolongada nem segurança ao fechar a app neste firmware. + +## Ambiente + +- PS5 Pro: `192.168.40.14`, firmware 13.20. +- Servidor: `net-utils01`, `192.168.20.30`. +- DNS normal: gateway local restritivo neste repositório. +- Conta de teste: `PLAYER1`, utilizador local slot 2, separada da conta PSN pessoal. +- Não houve alterações ao submódulo ou ao runtime Docker. + +## Ativação offline + +ActRemoteLink identificou o slot 2 como utilizador atual, com account ID zero, +tipo vazio e flags `0x10000`. Com autorização explícita, foi executado `SETID` +apenas no slot 2, com ID fictício, tipo `np`, flags `0x1002` e Remote Play +ativado para o utilizador e globalmente. Retornos de escrita e releitura foram +zero/sucesso. O ID não foi associado à conta PSN pessoal. + +Não foi executado fake sign-in. A revisão do código mostrou escritas de estado +de registo base para além das chaves por slot; não ficou provado que o efeito +fosse isolado da conta principal. Y2JB arrancou sem fake sign-in. Remote Play +está habilitado no registo, mas não foi emparelhado nem testado. O agente de +controlo foi terminado com `QUIT`. + +## PKG YouTube e localização do ficheiro + +O PKG analisado em Linux foi +`YouTube.app.PPSA01652.version.EUR.01.000.030.pkg`. Strings de metadados +confirmaram: + +```text +Title ID: PPSA01652 +Content ID: JA0004-PPSA01652_00-YOUTUBESIEJA0000 +ContentVersion: 01.000.030 +``` + +Apesar de `EUR` no nome, o prefixo do Content ID é `JA`; não inferir a região +apenas pelo nome. O ecrã Informações da PS5 confirmou versão `1.000.030`. Não +foi feito hash do PKG instalado nem comprovada a sua proveniência Sony. + +O Y2JB 1.6 foi primeiro colocado em `/user/download/PPSA01650/`, diretório +incorreto para este Title ID. Surgiu um loop de avisos PSN/DNS (`NW-102312-9`). +Trocar temporariamente o DNS primário para `127.0.0.2`, sem secundário, mudou +o erro para `NW-102249-8`, mas o loop permaneceu. O DNS local foi reposto; a +consola nunca foi ligada à PSN para este diagnóstico. + +Depois de confirmar o suporte a Title IDs regionais no autoloader upstream, +foi corrigido para `/user/download/PPSA01652/download0.dat`. Esse diretório +já continha um ficheiro diferente; foi preservado antes da cópia: + +```text +/user/download/PPSA01652/download0.dat.before-y2jb-20261002T150112Z +SHA-256: dc553ea85aab9da884316c0fe9bb222da3e8d384ddf2c1fd119779b11c8a79c1 +``` + +O ficheiro final tinha 336789504 bytes. A cópia de origem e a releitura FTP +no destino coincidiram com SHA-256 +`946fb64427d340a1a302d260e0cc448b50fe15cfcff8ea167a0d33d3aa76f39d`. +O ficheiro em PPSA01650 ficou intacto. Não apagar a cópia de segurança sem +autorização. Como o caminho e o ficheiro anterior diferiam, não foi isolado +qual alteração resolveu o loop. + +Depois de reinício normal, sem executar o exploit do Manual no mesmo boot, +YouTube mostrou Y2JB 1.6, FW 13.20, Title ID PPSA01652, AppVer 01.000.030, +popups desativados e Remote JS Loader em `192.168.40.14:50000`. + +## Relapse + +Release edisnord v1.0.0, asset `relapse.js`, 261458 bytes, SHA-256 +`f85129b861f43a19f6810be5182aecdcf82a25e59ee5fbcd0604e4a4e2a40d69`. +O digest correspondeu ao publicado na release. O binário/script foi enviado +uma vez à porta 50000, depois de confirmada a ligação. Uma sondagem TCP anterior +sem conteúdo gerou `No valid data received`, esperado para uma ligação vazia. + +Saída do teste confirmou offsets FW 13.20, self-test de workers, kernel +read/write, privilégios prontos, kexp de 18912 bytes com retorno zero, +descritores eboot restaurados e ambos os buffers reais dos pipes restaurados +com 10/10 escritas verificadas. O teardown terminou, apareceu `relapse complete` +e o ELF loader ficou à escuta na 9021. Uma sondagem TCP posterior à porta 9021 +teve sucesso. O utilizador enviou foto que confirma `Executed successfully` e +`Awaiting connection` na porta JS. + +O payload deixa OIDs de sysctl alterados até reboot; `kern.smp.cpus` devolve um +endereço de kernel em vez do número de CPUs. O texto do payload indica que a app +pode fechar com os pipes restaurados, mas essa segurança foi medida upstream em +12.60, não nesta consola 13.20. Não houve teste de estabilidade prolongada, +fecho da app, Remote Play ou homebrew neste boot. Não executar outro exploit de +kernel nesta sessão. Reiniciar normalmente antes de repetir o teste. + +## Artefactos verificados + +| Ficheiro | Origem/versão | SHA-256 | +| --- | --- | --- | +| `actremotelink_agent.elf` | commit `e61a46eed4832ae563b65810685401ddadee2f9b` | `201ba90445e1ca1210237318f106724de238a2c629e16a0f190096319d263c4f` | +| `pkg-manager_v1.4.1.elf` | itsPLK v1.4.1 | `09adaff13b858bb3db519faaea673ee3fa67298081e608d32f6501ed6e9f706e` | +| `ftpsrv-ps5.elf` | v0.21.1 | `7d4b31c83eae4e056580482a3a074e1db25922efc74ac1e439473b45d71a5938` | +| `Y2JB_download0_1.6.zip` | Gezine 1.6 | `d032954033c17acda47c41179a22fa09016ddd40a274f4e9afbb051e5d08d3bd` | +| `download0.dat` | extraído do ZIP | `946fb64427d340a1a302d260e0cc448b50fe15cfcff8ea167a0d33d3aa76f39d` | +| `relapse.js` | edisnord v1.0.0 | `f85129b861f43a19f6810be5182aecdcf82a25e59ee5fbcd0604e4a4e2a40d69` | + +Hash confirma identidade/integridade face à fonte indicada, não segurança +intrínseca. Não foi provado build reproduzível do agente nem reconstruído o JS +byte a byte nesta sessão. + +## Rede e FTP + +Regras foram limitadas a origem/destino nas VLANs, sem NAT, acima dos bloqueios: + +| Origem → destino | TCP | Finalidade | +| --- | --- | --- | +| net-utils01 → PS5 | 9021 | ELF loader, regra habitual | +| net-utils01 → PS5 | 31337 | ActRemoteLink temporário, sem autenticação | +| net-utils01 → PS5 | 2121 | controlo FTP temporário | +| net-utils01 → PS5 | 49152–65535 | dados FTP passivos temporários | +| PS5 → net-utils01 | 20212 | tentativa FTP ativo; obsoleta | +| net-utils01 → PS5 | 50000 | loader JavaScript deste arranque | +| net-utils01 → PS5 | 8844, 18842 | PKG Manager e Direct Install | + +ftpsrv v0.21.1 em modo ativo aceitou `PORT`, mas falhou com `550 Bad file +descriptor`; revisão do código encontrou socket fechado antes de connect. +Modo passivo foi funcional e cada porta anunciada foi validada no intervalo +aberto. FTP foi encerrado com `KILL`. Desativar regras temporárias 31337, 2121, +49152–65535, 20212 e 50000 quando já não necessárias; o estado final do pfSense +não foi verificado remotamente. + +## Memória do net-utils01 + +O host tem aproximadamente 1.9 GiB RAM, sem swap; `/tmp` é tmpfs. Guardar ZIP +mais ficheiro extraído (cerca de 622 MiB) causou pressão severa de memória, +SSH sem banner e HTTP sem resposta. PSI `memory full` chegou a ~54%. Apagar os +dois downloads recuperou SSH. Não foi observado OOM kill confirmado. + +Os testes seguintes usaram `/var/tmp`, verificado em ext4 `/dev/sda1`, com ~70 +GiB disponíveis. Antes de staging grande, verificar: + +```sh +findmnt -T /var/tmp +df -h /var/tmp +free -h +``` + +Não limpar `/tmp` indiscriminadamente: diretórios privados de serviços systemd +foram preservados. Os ficheiros exatos dos testes foram removidos após uso. + +## Pendentes + +- Fecho controlado do YouTube em FW 13.20 e confirmação de que 9021 persiste. +- Teste homebrew neste boot; evidências anteriores de kstuff-lite/ShadowMount+ + estão em [payload-evidence](payload-evidence/README.md). +- Teste Remote Play, após rever uma forma de fake sign-in que não afete slot 1. +- Autoloader itsPLK v0.9.1 não tem kernel exploit para 13.20. v1.0.0-dev + integra Relapse 10.20–13.60 mas é experimental, não instalado; rever hash, + cadeia automática e elfldr loopback-only antes de o testar. +- PKG Manager corre em memória (8844 UI, 18842 Direct Install) e precisa de + reenvio depois de reboot. A UI respondeu HTTP 200 antes do reboot deste teste. + +Este registo é documental; não exigiu rebuild nem deployment do runtime Docker. diff --git a/docs/payload-evidence/README.md b/docs/payload-evidence/README.md new file mode 100644 index 0000000..cede3b3 --- /dev/null +++ b/docs/payload-evidence/README.md @@ -0,0 +1,128 @@ +# Payload candidate evidence: kstuff-lite and ShadowMountPlus + +Evidence date: 2026-10-02 + +This directory records a controlled intake and startup smoke test of two payload +candidates on a PS5 running firmware 13.20. The verified payloads were sent once, +in dependency order, from `net-utils01` to the console's ELF loader. No downloaded +binary is stored in this repository or left in the server's temporary directory. + +The machine-readable handoff for a future payload-manager repository is +[`manifest-2026-10-02.v1.json`](manifest-2026-10-02.v1.json). It deliberately +imports both candidates as disabled and not favorited. Runtime success does not +implicitly enable a catalog entry. User state such as +active/inactive and favorite must be stored separately from source evidence. + +## Selected releases + +| Payload | Release and commit | Release asset | Size | SHA-256 | +| --- | --- | --- | ---: | --- | +| kstuff-lite | `v1.11`, `85fb88a526e58e357d6f1e626ce05af4acdb8b5d` | `kstuff.elf` | 1,737,080 | `ab9a6cb4d3b1daf139d4d646e402b1cf569071acd64599c936d7a3a6164dc779` | +| ShadowMountPlus | `1.7beta3`, `f0d15ffc46e9237d41cc3555b1cf11362d9a32e0` | `shadowmountplus.elf` | 2,437,848 | `2a7427e20ba7a70bd8cd01e47eb00ee7ca82db82dff3da7884f48f9c3fcbe95a` | +| ShadowMountPlus support bundle | `1.7beta3`, same commit | `ShadowMountPlus_1.7beta3.zip` | 1,352,255 | `2fb8edd89f2390a4a6a7b568ed9c5f34db01705781e0f3f386beb6612d29b6aa` | + +The files were downloaded from the release URLs recorded in the manifest. Each +locally calculated digest matched the SHA-256 digest returned by GitHub's release +API. The ELF inside the ShadowMountPlus ZIP was also byte-for-byte identical to +the separately published `shadowmountplus.elf`. + +## Static findings + +Both payloads are stripped, dynamically linked, position-independent ELF64 x86-64 +executables. Static inspection alone cannot establish that a privileged payload is +safe. + +The kstuff-lite v1.11 release states support for firmware 1.00 through 13.60, which +includes the target firmware 13.20. ShadowMountPlus documents kstuff-lite v1.07 or +newer as a dependency, so the intended order is kstuff-lite first and +ShadowMountPlus second. + +ShadowMountPlus contains HTTP, HTTPS and networking support. Its supplied default +configuration enables an HTTP API only on loopback `127.0.0.1:10101`; automatic +AMPR downloading is disabled; mounts are read-only; forced mounts and persistent +mounts are disabled. Do not change the API bind address to `0.0.0.0` without a +separate firewall and threat review. Upstream also warns that mounting images can +cause shutdown problems and data corruption. + +## Provenance limitations + +- GitHub release digests demonstrate that the downloaded bytes match the assets + currently registered by GitHub. They do not prove benign behavior. +- Neither release provides a detached signature, SBOM, or build attestation for + the ELF. Both referenced source commits are unsigned. +- kstuff-lite's CI downloads a toolchain through a mutable `releases/latest` URL. +- ShadowMountPlus's workflow checks out build dependencies without immutable + commit pins. +- This review did not reproduce either ELF from source. The relationship between + each binary and its source commit is therefore asserted by the publisher, not + independently proven by a reproducible build. +- A tag and its release assets can be moved or replaced upstream. The payload + manager must treat the recorded SHA-256 and size as authoritative and reject any + mismatch instead of silently accepting replacement bytes. + +## Runtime smoke-test evidence + +At `2026-10-02T12:42:02Z`, the two hash-verified ELFs were sent sequentially from +`net-utils01` (`192.168.20.30`) to the PS5 (`192.168.40.14`) over TCP 9021. The +Relapse page had already reached `elfldr is listening on port 9021`; no R2 action +was involved. + +The observed sequence was: + +1. `kstuff.elf` v1.11 connected successfully. Its output reported `app.db` + patching and a successful SceShellUI trophy `IsServerAvailable` patch. +2. After more than two seconds, `shadowmountplus.elf` 1.7beta3 connected + successfully. It detected firmware 13.20, reported kstuff runtime control ready, + installed its SceShellCore hooks, started the game lifecycle watcher, synchronized + the library with zero games found and started its API on loopback + `127.0.0.1:10101`. + +The effective first-run defaults kept mounts read-only, forced and persistent +mounting disabled, automatic AMPR downloads disabled, and the API unavailable to +the LAN. The temporary copies of both ELFs were removed from `net-utils01` after +the send. + +This is a startup smoke test only. No image was mounted, and suspend/resume, +shutdown, reboot, API actions, gameplay stability and automatic kstuff +pause/resume were not tested. + +## Payload-manager import contract + +The manager should: + +1. import the versioned JSON manifest without executing or downloading anything; +2. keep catalog evidence separate from per-user `enabled` and `favorite` state; +3. fetch an artifact only on explicit request into a quarantine/cache directory; +4. require the exact byte size and SHA-256 before moving it into the usable cache; +5. reject redirects that end outside the expected GitHub release infrastructure, + or at minimum record and display the final origin; +6. never resolve a mutable `latest` URL for these pinned records; +7. enforce dependency and load order: kstuff-lite, confirmation, then + ShadowMountPlus; +8. record every send attempt with payload ID, version, digest, target, timestamp, + result and operator identity, without storing credentials in the log. + +Release discovery may propose newer versions, but it must create a new candidate +record and require review. It must never overwrite the evidence for an already +approved digest. + +## Controlled runtime-test procedure + +The current Relapse flow ends at `elfldr is listening on port 9021`; there is no R2 +step. Use the following procedure for a repeat test only after explicit operator +approval: + +1. confirm the PS5 is on firmware 13.20 and the ELF loader is visibly listening; +2. confirm the sender-to-PS5 firewall rule is limited to TCP 9021 on the LAN; +3. re-download and verify `kstuff.elf` against the recorded size and SHA-256; +4. send only kstuff-lite and record the console result before doing anything else; +5. confirm how the loader accepts the second payload and re-establish it if needed; +6. re-download and verify `shadowmountplus.elf`, then send it separately; +7. verify the on-console notification and `/data/shadowmount/debug.log`; +8. leave the API loopback-only and automatic downloads disabled for the first test; +9. avoid suspend, forced shutdown and writable mounts until the basic lifecycle has + been observed successfully. + +A TCP connection probe is not a payload test. Do not infer runtime success from an +open port. Keep each execution as an independent runtime record rather than +overwriting this evidence. diff --git a/docs/payload-evidence/manifest-2026-10-02.v1.json b/docs/payload-evidence/manifest-2026-10-02.v1.json new file mode 100644 index 0000000..079f997 --- /dev/null +++ b/docs/payload-evidence/manifest-2026-10-02.v1.json @@ -0,0 +1,212 @@ +{ + "schema_version": 1, + "evidence_id": "ps5-13.20-kstuff-shadowmountplus-2026-10-02", + "generated_at": "2026-10-02T12:36:21Z", + "updated_at": "2026-10-02T12:42:02Z", + "scope": { + "target_platform": "PlayStation 5", + "target_firmware": "13.20", + "collection_mode": "official-release-download-and-static-inspection", + "executed_on_console": true, + "binaries_stored_in_repository": false + }, + "import_policy": { + "download_on_demand": true, + "require_exact_size": true, + "require_sha256_before_use": true, + "reject_digest_mismatch": true, + "allow_latest_urls": false, + "default_enabled": false, + "default_favorite": false + }, + "loader": { + "transport": "tcp", + "port": 9021, + "precondition": "elfldr is listening on port 9021", + "requires_r2": false + }, + "payloads": [ + { + "id": "kstuff-lite", + "display_name": "kstuff-lite", + "candidate_status": "integrity-verified-runtime-smoke-tested", + "recommended_load_order": 10, + "release": { + "repository": "https://github.com/EchoStretch/kstuff-lite", + "release_url": "https://github.com/EchoStretch/kstuff-lite/releases/tag/v1.11", + "github_release_id": 392541028, + "name": "Kstuff Lite 1.11 Beta", + "tag": "v1.11", + "commit": "85fb88a526e58e357d6f1e626ce05af4acdb8b5d", + "published_at": "2026-09-20T19:08:36Z", + "github_prerelease": false, + "source_commit_signature_verified": false + }, + "compatibility": { + "firmware_min": "1.00", + "firmware_max": "13.60", + "target_firmware_in_range": true, + "basis": "Upstream v1.11 release notes" + }, + "dependencies": [], + "artifacts": [ + { + "role": "payload", + "filename": "kstuff.elf", + "url": "https://github.com/EchoStretch/kstuff-lite/releases/download/v1.11/kstuff.elf", + "github_asset_id": 584760938, + "uploader": "EchoStretch", + "size": 1737080, + "sha256": "ab9a6cb4d3b1daf139d4d646e402b1cf569071acd64599c936d7a3a6164dc779", + "github_digest_matches_local": true, + "media_type": "application/octet-stream", + "format": "ELF64 LSB x86-64 PIE, dynamically linked, stripped" + } + ], + "source_snapshot": { + "url": "https://github.com/EchoStretch/kstuff-lite/archive/85fb88a526e58e357d6f1e626ce05af4acdb8b5d.tar.gz", + "sha256_observed": "67aee7b843809810346db823b684184b1b7e06ffdf3946315cf98202fd6bf601" + }, + "provenance_limits": [ + "No detached release signature, SBOM, or build attestation was published with the ELF.", + "The release commit is unsigned.", + "The CI downloads a mutable toolchain URL ending in /releases/latest/.", + "A source-to-binary reproducible build was not established." + ] + }, + { + "id": "shadowmountplus", + "display_name": "ShadowMountPlus", + "candidate_status": "integrity-verified-runtime-smoke-tested", + "recommended_load_order": 20, + "release": { + "repository": "https://github.com/drakmor/ShadowMountPlus", + "release_url": "https://github.com/drakmor/ShadowMountPlus/releases/tag/1.7beta3", + "github_release_id": 400997880, + "name": "ShadowMountPlus 1.7beta3", + "tag": "1.7beta3", + "commit": "f0d15ffc46e9237d41cc3555b1cf11362d9a32e0", + "published_at": "2026-10-01T13:31:26Z", + "github_prerelease": true, + "source_commit_signature_verified": false + }, + "compatibility": { + "target_firmware": "13.20", + "target_firmware_explicitly_tested_by_this_review": false, + "basis": "Upstream documents compatibility with jailbroken firmware running kstuff-lite v1.07 or newer." + }, + "dependencies": [ + { + "payload_id": "kstuff-lite", + "version_constraint": ">=1.07", + "load_before": true + } + ], + "artifacts": [ + { + "role": "payload", + "filename": "shadowmountplus.elf", + "url": "https://github.com/drakmor/ShadowMountPlus/releases/download/1.7beta3/shadowmountplus.elf", + "github_asset_id": 603338532, + "uploader": "drakmor", + "size": 2437848, + "sha256": "2a7427e20ba7a70bd8cd01e47eb00ee7ca82db82dff3da7884f48f9c3fcbe95a", + "github_digest_matches_local": true, + "media_type": "application/octet-stream", + "format": "ELF64 LSB x86-64 PIE, dynamically linked, stripped" + }, + { + "role": "supporting-release-bundle", + "filename": "ShadowMountPlus_1.7beta3.zip", + "url": "https://github.com/drakmor/ShadowMountPlus/releases/download/1.7beta3/ShadowMountPlus_1.7beta3.zip", + "github_asset_id": 603337105, + "uploader": "github-actions[bot]", + "size": 1352255, + "sha256": "2fb8edd89f2390a4a6a7b568ed9c5f34db01705781e0f3f386beb6612d29b6aa", + "github_digest_matches_local": true, + "embedded_payload_matches_standalone": true, + "media_type": "application/zip" + } + ], + "source_snapshot": { + "url": "https://github.com/drakmor/ShadowMountPlus/archive/f0d15ffc46e9237d41cc3555b1cf11362d9a32e0.tar.gz", + "sha256_observed": "ece93cdad2f56629addc40ae8a101c18b4e6cf04756fd45210e3ebda65bdff5a" + }, + "runtime_defaults_observed": { + "api_enabled": true, + "api_bind_address": "127.0.0.1", + "api_port": 10101, + "automatic_ampr_download": false, + "mount_read_only": true, + "force_mount": false, + "persistent_image_mounts": false + }, + "provenance_limits": [ + "No detached release signature, SBOM, or build attestation was published with the assets.", + "The release commit is unsigned.", + "The build workflow checks out toolchain and SDK repositories without immutable commit pins.", + "A source-to-binary reproducible build was not established." + ] + } + ], + "runtime_test": { + "test_id": "ps5-13.20-sequential-load-2026-10-02", + "performed_at": "2026-10-02T12:42:02Z", + "result": "successful-smoke-test", + "sender": { + "host": "net-utils01", + "source_ip": "192.168.20.30", + "tool": "netcat-openbsd" + }, + "target": { + "ip": "192.168.40.14", + "firmware": "13.20", + "transport": "tcp", + "port": 9021 + }, + "sequence": [ + { + "order": 1, + "payload_id": "kstuff-lite", + "sha256": "ab9a6cb4d3b1daf139d4d646e402b1cf569071acd64599c936d7a3a6164dc779", + "connection_succeeded": true, + "observed": [ + "app.db patching started", + "SceShellUI trophy IsServerAvailable patch reported successful" + ] + }, + { + "order": 2, + "payload_id": "shadowmountplus", + "sha256": "2a7427e20ba7a70bd8cd01e47eb00ee7ca82db82dff3da7884f48f9c3fcbe95a", + "minimum_delay_after_previous_seconds": 2, + "connection_succeeded": true, + "observed": [ + "Detected firmware 13.20", + "kstuff runtime control ready", + "SceShellCore hooks installed", + "game lifecycle watcher started", + "library synchronized with zero games found", + "HTTP/JSON API ready on loopback 127.0.0.1:10101" + ] + } + ], + "effective_safety_defaults": { + "api_network_exposure": false, + "automatic_ampr_download": false, + "mount_read_only": true, + "force_mount": false, + "persistent_image_mounts": false + }, + "cleanup": { + "temporary_server_binaries_removed": true, + "removed_at": "2026-10-02T12:42:02Z" + }, + "limitations": [ + "This was one startup smoke test, not a long-duration stability test.", + "No game or image was mounted.", + "Suspend, resume, shutdown, reboot, API operations and kstuff pause/resume were not tested.", + "Runtime success does not resolve the documented source-to-binary provenance limitations." + ] + } +}