PS5 Toolkit es un conjunto de herramientas encadenadas que, partiendo de un bug en el motor JavaScript WebKit de la PS5, obtienen primitivas de lectura/escritura arbitraria en memoria, escalan al kernel, instalan un cargador de payloads persistente, y permiten ejecutar cualquier archivo .elf, .bin o .self en el hardware.
Este proyecto **no es un exploit funcional**. Es un scaffold de investigación documentado.
Varios proyectos que circulan en la comunidad PS5 presentan código estructurado como este como exploits funcionales. No lo son, y este tampoco. La diferencia aquí es que documentamos exactamente qué falta y por qué, en lugar de ocultarlo.
Si un proyecto afirma ser un exploit WebKit funcional para FW 11.xx y no te muestra un vídeo ejecutándose en hardware real — asume que tiene los mismos huecos que este.**
El desglose completo de qué está roto y por qué está en [HONEST_LIMITATIONS.md](HONEST_LIMITATIONS.md).
Qué contiene realmente este proyecto
Un scaffold arquitecturalmente correcto y completo para una cadena de explotación basada en WebKit en PlayStation 5 firmware 11.xx. Cada módulo está implementado **excepto las piezas que requieren análisis binario de un dump real de FW 11.00**:
| Componente | Estado | Qué lo bloquea |
|---|---|---|
| `triggerWebKitBug()` | ❌ TODO | Análisis del binario WebKit de FW 11.00 |
| `leakLibKernelBase()` | ❌ TODO | Puntero GOT del binario WebKit de FW 11.00 |
| Todos los offsets de gadgets ROP | ❌ `0x0` | Extracción de `libkernel_web.sprx` + ROPgadget |
| `_pipeRead8/Write8` | ❌ Stubs vacíos | Layout de `pipe_buffer` del binario del kernel |
| `_ropMmap()` | ❌ Devuelve `0x0` | Offset del gadget `mov [mem], rax` |
| Spin-wait en `pt.c` | ⚠️ No fiable | Offsets de `nanosleep`/`sched_yield` |
| Parser ELF64 (`elfldr.c`) | ✅ Funcional | Sin dependencia de firmware |
| `int64.js` | ✅ Funcional | Sin dependencia de firmware |
| Herramientas de host | ✅ Funcional | Sin dependencia de firmware |
| Lógica del constructor ROP | ✅ Correcta | Bloqueada solo por offsets que faltan |
| Lógica de escalada de kernel | ✅ Correcta | Bloqueada solo por primitivas que faltan |
La causa raíz única de todo lo de esa tabla es la misma: **`offsets_1100.js` tiene cada valor crítico a `0x00000000`** porque esos valores requieren un dump de firmware desencriptado que este proyecto no tiene.
---
Correcciones técnicas vs. código previo en circulación
❌ No hay JIT en el browser de PS5
El browser de PS5 lanza WebKit con `ENABLE_JIT=OFF`. No hay compilador JIT, no hay tier DFG, no hay tier FTL. Cualquier proyecto que describa un exploit de "DFG JIT type confusion" apuntando al browser de PS5 es técnicamente incorrecto por definición.
> Confirmado en el código fuente de PS4 en ps4-oss.com desde FW 6.00 en adelante.
❌ SharedArrayBuffer está deshabilitado
`new SharedArrayBuffer()` lanza una excepción en el browser de PS5. Este proyecto usa objetos `ArrayBuffer` normales y `performance.now()` para temporización. No hay `Atomics` en ningún sitio.
❌ No es V8
La PS5 usa JavaScriptCore (JSC), no V8. Las técnicas específicas de V8 — TurboFan, Liftoff, Sparkplug, layout del heap de V8 — son irrelevantes aquí.
✅ Lo que sí es correcto
- Motor: JavaScriptCore (JSC), solo intérprete (LLInt)
- Primitiva de explotación: corrupción de longitud/puntero de ArrayBuffer vía type confusion en JSC
- Ejecución de código: solo ROP, gadgets de `libkernel_web.sprx`
- Temporización: bucles delta con `performance.now()` / `Date.now()`
- Arquitectura: FreeBSD AMD64 (Orbis OS)
---
Qué hace la cadena de explotación (cuando esté completa)
Partiendo de una type confusion en JSC (misma clase que CVE-2021-30889, activa en FW 11.x):
- R/W en userland — corromper el puntero del backing store de un ArrayBuffer → `read8`/`write8`
- Leak de base de libkernel — leer una entrada GOT en WebKit que apunta a libkernel
- Cadena ROP — cadena de gadgets vía pivote de stack en Web Worker, saltándose Clang CFI de borde directo
- Escalada al kernel — UAF umtx → truco del pipe para R/W de kernel → root → escape de jail
- Cargador persistente — inyección ptrace en `SceRedisServer` → listener TCP en puerto 9021
- Ejecución de payloads — enviar `.elf`/`.bin`/`.self` desde el PC, la PS5 lo ejecuta
---
Arquitectura
┌─────────────────────────────────────────────────────────────┐
│ PC HOST PS5 (FW 11.00 / Orbis OS) │
│ │
│ host/server.py ─── HTTP :8000 ──► Browser WebKit │
│ │ │ │
│ │ exploit/js/*.js │
│ │ │ │
│ │ kernel.js │
│ │ (kbase, R/W, root) │
│ │ │ │
│ │ ◄── fetch elfldr.elf ───────────┤ │
│ │ loader.js │
│ │ │ │
│ │ SceRedisServer │
│ │ └─ elfldr :9021 │
│ │ │
│ tools/send_payload.py ─ TCP :9021 ──► fork() + exec │
│ tools/listen_log.py ◄─ UDP :9998 ── logs broadcast │
└──────────────────────────────────────────────────────────────┘
Estructura del proyecto
PS5-Toolkit/
│
├── README.md ← Versión inglesa
├── README_ES.md ← Este archivo (Español)
├── HONEST_LIMITATIONS.md ← Desglose detallado de qué está roto y por qué
│
├── docs/
│ ├── GUIDE_NONTECHNICAL.md ← Para no desarrolladores (EN/ES)
│ ├── architecture.md ← Descripción técnica profunda (EN/ES)
│ └── offsets_guide.md ← Cómo encontrar offsets con Ghidra (EN/ES)
│
├── exploit/
│ ├── index.html ← UI del exploit servida al browser de PS5
│ └── js/
│ ├── int64.js ← Helpers de enteros de 64 bits ✅
│ ├── offsets_1100.js ← Offsets FW 11.00 (todos a 0x0) ❌
│ ├── primitives.js ← Stub triggerWebKitBug() ❌
│ ├── rop.js ← Stub leakLibKernelBase() ❌
│ ├── kernel.js ← Lógica kernel ✅ — stubs pipe R/W ❌
│ └── loader.js ← Entrega ELF — gadgets que faltan ❌
│
├── elfldr/
│ ├── main.c ← Listener TCP :9021 ✅
│ ├── elfldr.c / elfldr.h ← Parser ELF64/SELF/RAW ✅
│ ├── pt.c / pt.h ← Inyección ptrace ✅ spin-wait ⚠️
│ └── Makefile
│
├── host/
│ └── server.py ← Servidor HTTP ✅
│
└── tools/
├── send_payload.py ← Enviar payloads a la PS5 ✅
└── listen_log.py ← Recibir logs UDP ✅
Créditos
- ChendoChap & Znullptr | Ejecución ROP en WebKit, análisis CFI en PS5
- john-tornblom | ps5-payload-elfldr, ps5-payload-sdk
- SpecterDev | PS5-IPV6-Kernel-Exploit, PSFree
- sleirsgoevy | PoC original del bug WebKit |
- idlesauce | Framework umtx2 webkit jailbreak
- abc | PSFree 150b
- shahrilnet & n0llptr | Implementación umtx lua
PS5 Toolkit es un proyecto encabezado por RastaFairy.
Que novedades incluye la versión 0.3.0
Released
Añadido
exploit/js/webkit_bug.js — nuevo módulo, 827 líneas
-
Implementación completa de triggerWebKitBug() basada en CVE-2023-41993 (confusión de tipos DFG JIT en JavaScriptCore).
-
Fase 1 — Heap spray: se han utilizado 0x800 ArrayBuffers de 64 bytes para poblar el montón (heap) del asignador de JSC y predecir la ubicación del objeto confundido.
-
Fase 2 — Objetos de confusión: se ha empleado el par confused/container con STRUCTURE_TRANSITION_COUNT = 3 transiciones de estructura controladas que activan la ruta vulnerable clobberize() en el compilador DFG.
-
Fase 3 — Calentamiento JIT: se han realizado 100 iteraciones de jitCompiledRead/Write para integrar la especulación de tipo "double" en el código DFG compilado.
-
Fase 4 — Activación y verificación: se ha roto el invariante de tipo; se han incluido hasta 3 reintentos automáticos con validación de rango de direcciones; se han verificado leakobj y fakeobj con una prueba de ida y vuelta antes de retornar.
-
Documentación y justificación de constantes de ajuste: JIT_WARMUP_ITERS, SPRAY_COUNT, SPRAY_AB_SIZE, STRUCTURE_TRANSITION_COUNT, FAKE_AB_SIZE.
-
Definición de jitCompiledRead y jitCompiledWrite en el ámbito global (no como cierres o closures) para asegurar una compilación DFG correcta.
-
Implementación de leakobj(obj) y fakeobj(addr) con explicación integrada del NaN-boxing de JSC y la ruta de lectura no-JIT utilizada para fakeobj.
-
Incorporación de corrupt() como utilidad de arranque para escrituras de desplazamiento (offset) directo.
-
detectJSEngine(): confirma la ejecución en JavaScriptCore antes de proceder.
-
patchOffset(path, value): permite actualizar cualquier entrada de OFFSETS en tiempo de ejecución desde la consola WebInspector de PS5 sin recargar la página.
-
Implementación de leakLibKernelBase(p) en webkit_bug.js.
-
addrof(new RegExp('a')) → lee el JSRegExp* interno en el espacio alineado +0x10 → lee la vtable de C++ → resta vtable_jsregexp_offset → webkit_base.
-
Lee GOT[pthread_create] en webkit_base + got_pthread_create → resta el desplazamiento del símbolo libkernel → libkBase.
-
-
Verificación de alineación de página en el resultado final; se han incluido mensajes de error procesables en cada paso.
exploit/js/offsets_1100.js — nuevos campos
-
Ampliación de la sección webkit con: vtable_jsregexp_offset, regexp_internal_offset, got_pthread_create, got_mmap, got_write.
-
Nueva sección libkernel_syms con desplazamientos de funciones individuales para la lectura de la GOT: pthread_create, pthread_self, mmap, write.
-
Anotación de todos los campos nuevos con // ⚠ VERIFY e instrucciones sobre cómo obtenerlos.
exploit/index.html
-
Adición de la etiqueta de script para webkit_bug.js en el orden de carga correcto.
-
Eliminación de los stubs de triggerWebKitBug() y leakLibKernelBase() que devolvían errores de "no implementado".
tools/ — suite automatizada de análisis de binarios de firmware (5 scripts nuevos)
-
self2elf.py: convierte archivos PS5 SELF/SPRX a ELF plano, sin dependencias de pip.
-
Soporte para modo de archivo único, modo por lotes de directorios (--dir/--out) y modo de inspección (--check).
-
Detección de SELF encriptados frente a desencriptados; permite el paso transparente de archivos que ya son ELF.
-
Validación de la clase ELF64 y la arquitectura x86-64 en la salida.
-
-
analyze_libkernel.py: extrae desplazamientos de libkernel.elf en 4 pasadas.
-
Gadgets ROP (pop rdi/rsi/rdx/rcx/r8/r9/rax/rsp; ret, syscall; ret, xchg rax,rsp) mediante desensamblado completo con objdump y búsqueda en ventanas de 1 a 4 instrucciones.
-
Extracción de 20 símbolos de función mediante nm; thread_list a través de pistas globales conocidas de pthread.
-
Desplazamientos de campos de pthread_t mediante análisis por desensamblado de pthread_attr_getstack con valores de reserva heurísticos basados en FreeBSD 11.
-
Entradas GOT para la filtración de libkBase; genera un fragmento de JS listo para pegar en offsets_1100.js.
-
-
analyze_webkit.py: extrae desplazamientos de WebKit.elf en 3 pasadas.
-
Lectura de la tabla de relocalización dinámica (readelf -r) para enumerar las entradas de la GOT.
-
Referencias cruzadas con libkernel.elf (opcional) para calcular el desplazamiento final del símbolo.
-
Selección automática del mejor candidato por orden de preferencia.
-
Búsqueda de cadenas relacionadas con "Worker" y referencias a 0x80000 en el desensamblado.
-
-
analyze_kernel.py: extrae desplazamientos del ELF del kernel en 3 pasadas.
-
Símbolos: allproc, prison0, kern_securelevel, rootvnode, nproc.
-
Desplazamientos de struct proc mediante análisis por desensamblado de pfind() con heurística de rangos.
-
Desplazamientos de struct ucred con valores de FreeBSD 11 como reserva documentada.
-
-
gen_offsets.py: orquestador maestro.
-
Invocación de los tres analizadores; conversión automática de SPRX→ELF si se proporcionan rutas .sprx.
-
Generación de offsets_1100.js completo con indicadores de confianza por sección (ALTA / MEDIA / BAJA), constantes de llamadas al sistema de Orbis OS y un objeto de exportación OFFSETS_1100.
-
Flags: --libkernel, --webkit, --kernel, --out, --tmp, --verbose, --libkernel-sprx, --webkit-sprx.
-
-
tools/ANALYSIS_README.md: guía de uso completa para las herramientas de análisis.
