FreeBSD ptrace RFI and vm_map PROT_EXEC bypass (PS5 case study)
Reading time: 8 minutes
tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :
HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d'abonnement !
- Rejoignez le đŹ groupe Discord ou le groupe telegram ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépÎts github.
Aperçu
Cette page documente une technique pratique d'injection de processus/ELF usermode Unix/BSD sur PlayStation 5 (PS5), basée sur FreeBSD. La méthode se généralise aux dérivés FreeBSD lorsque vous disposez déjà de primitives de lecture/écriture du kernel (R/W). Vue d'ensemble :
- Patchez les credentials du processus courant (ucred) pour accorder l'autorité de debugger, permettant ptrace/mdbg sur des processus utilisateur arbitraires.
- Trouvez les processus cibles en parcourant la liste kernel allproc.
- Contournez les restrictions PROT_EXEC en basculant vm_map_entry.protection |= PROT_EXEC dans le vm_map de la cible via des écritures de données kernel.
- Utilisez ptrace pour effectuer Remote Function Invocation (RFI) : suspendre un thread, régler les registres pour appeler des fonctions arbitraires dans la cible, reprendre, récupérer les valeurs de retour et restaurer l'état.
- Mappez et exécutez des payloads ELF arbitraires dans la cible en utilisant un ELF loader in-process, puis créez un thread dédié qui exécute votre payload et déclenche un breakpoint pour détacher proprement.
Mitigations hyperviseur PS5 à noter (contextualisées pour cette technique) :
- XOM (execute-only .text) empĂȘche la lecture/Ă©criture du .text kernel.
- Réinitialiser CR0.WP ou désactiver CR4.SMEP provoque un vmexit hyperviseur (crash). Seules les écritures kernel affectant uniquement les données sont viables.
- Le mmap en userland est restreint Ă PROT_READ|PROT_WRITE par dĂ©faut. L'attribution de PROT_EXEC doit ĂȘtre faite en Ă©ditant les entrĂ©es vm_map dans la mĂ©moire kernel.
Cette technique est post-exploitation : elle suppose l'existence de primitives R/W kernel issues d'une chaßne d'exploit. Des payloads publics démontrent cela jusqu'au firmware 10.01 au moment de la rédaction.
Primitives kernel 'data-only'
Découverte des processus via allproc
FreeBSD maintient une liste doublement chaßnée de processus dans .data du kernel à allproc. Avec une primitive de lecture kernel, itérez-la pour localiser les noms de processus et les PIDs:
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);
}
Notes:
- KERNEL_ADDRESS_ALLPROC dépend du firmware.
- p_comm est un nom de taille fixe ; envisagez des recherches pid->proc si nécessaire.
Ălever les credentials pour le dĂ©bogage (ucred)
Sur PS5, struct ucred contient un champ Authority ID accessible via proc->p_ucred. Ăcrire l'Authority ID du debugger accorde ptrace/mdbg sur d'autres processus:
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);
}
}
- L'offset 0x58 est spĂ©cifique Ă la famille de firmware PS5 et doit ĂȘtre vĂ©rifiĂ© par version.
- AprÚs cette écriture, l'injecteur peut attacher et instrumenter les processus utilisateur via ptrace/mdbg.
Contournement des mappings RW-only utilisateur : vm_map PROT_EXEC flip
Le Userland mmap peut ĂȘtre contraint Ă PROT_READ|PROT_WRITE. FreeBSD suit l'espace d'adressage d'un processus dans un vm_map de nĆuds vm_map_entry (BST plus liste). Chaque entrĂ©e porte les champs protection et max_protection :
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;
};
Avec kernel R/W you can locate the targetâs vm_map and set entry->protection |= PROT_EXEC (and, if needed, entry->max_protection). Remarques pratiques d'implĂ©mentation :
- Parcourez les entrées soit linéairement via next, soit en utilisant le balanced-tree (left/right) pour une recherche en O(log n) par plage d'adresses.
- Choisissez une région RW connue que vous contrÎlez (scratch buffer ou mapped file) et ajoutez PROT_EXEC pour pouvoir y placer du code ou des loader thunks.
- Le code PS5 SDK fournit des helpers pour la recherche rapide de map-entry et le basculement des protections.
Cela contourne la politique mmap de l'userland en modifiant directement les métadonnées appartenant au kernel.
Remote Function Invocation (RFI) with ptrace
FreeBSD ne dispose pas des Ă©quivalents Windows VirtualAllocEx/CreateRemoteThread. Ă la place, forcez la cible Ă appeler des fonctions sur elleâmĂȘme sous contrĂŽle ptrace :
- Attachez-vous à la cible et sélectionnez un thread ; PTRACE_ATTACH ou des flows mdbg spécifiques à PS5 peuvent s'appliquer.
- Sauvegardez le contexte du thread : registers, PC, SP, flags.
- Ăcrivez les argument registers selon l'ABI (x86_64 SysV ou arm64 AAPCS64), rĂ©glez PC sur la fonction cible, et placez optionnellement des arguments/stack supplĂ©mentaires si nĂ©cessaire.
- ExĂ©cutez en single-step ou continuez jusqu'Ă un arrĂȘt contrĂŽlĂ© (par ex. breakpoint logiciel ou signal), puis relisez les valeurs de retour depuis les regs.
- Restaurez le contexte original et continuez.
Use cases:
- Appeler un ELF loader en-processus (par ex. elfldr_load) avec un pointeur vers votre image ELF dans la mémoire cible.
- Invoquer des routines helper pour récupérer les entrypoints retournés et les pointeurs payload-args.
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);
Le loader mappe les segments, résout les imports, applique les relocations et retourne l'entry (souvent un CRT bootstrap) ainsi qu'un pointeur opaque payload_args que votre stager passe au main() du payload.
Threaded stager et détachement propre
Un stager minimal à l'intérieur de la cible crée un nouveau pthread qui exécute le main de l'ELF puis déclenche int3 pour signaler à l'injector de se détacher :
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;
}
- Les pointeurs SCEFunctions/payload_args sont fournis par le loader/SDK glue.
- AprĂšs le breakpoint et le detach, le payload continue dans son propre thread.
Pipeline de bout en bout (implémentation de référence PS5)
Une implémentation fonctionnelle s'accompagne d'un petit serveur injecteur TCP plus d'un script client :
- Le serveur NineS écoute sur TCP 9033 et reçoit un header contenant le nom du processus cible suivi de l'image ELF:
typedef struct __injector_data_t{
char proc_name[MAX_PROC_NAME];
Elf64_Ehdr elf_header;
} injector_data_t;
- Utilisation du client Python:
python3 ./send_injection_elf.py SceShellUI hello_world.elf <PS5_IP>
Exemple de payload Hello-world (enregistre dans klog) :
#include <stdio.h>
#include <unistd.h>
#include <ps5/klog.h>
int main(){
klog_printf("Hello from PID %d\n", getpid());
return 0;
}
Considérations pratiques
- Offsets et constantes (allproc, ucred authority offset, vm_map layout, ptrace/mdbg details) sont spĂ©cifiques au firmware et doivent ĂȘtre mis Ă jour Ă chaque release.
- Les protections de l'hyperviseur forcent des data-only kernel writes ; n'essayez pas de patcher CR0.WP ou CR4.SMEP.
- JIT memory est une alternative : certains processus exposent des PS5 JIT APIs pour allouer des pages exécutables. L'inversion de la protection vm_map supprime la nécessité de s'appuyer sur des astuces JIT/mirroring.
- Assurez-vous que la sauvegarde/restauration des registres est robuste ; en cas d'échec, vous pouvez provoquer un deadlock ou un crash de la cible.
Outils publics
- 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
Références
- 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
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :
HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d'abonnement !
- Rejoignez le đŹ groupe Discord ou le groupe telegram ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépÎts github.
HackTricks