
PoC di esecuzione in userland da utilizzare come tecnica vettore di attacco
L'exec in userland sostituisce l'immagine del processo esistente all'interno dello spazio di indirizzi corrente con una nuova. Riproduce il comportamento della chiamata di sistema execve, ma le strutture di processo che descrivono l'immagine del processo rimangono invariate. In altre parole, il nome del processo riportato dalle utility di sistema manterrà il vecchio nome del processo.
Questa tecnica può essere utilizzata per ottenere stealth dopo aver ottenuto l'esecuzione di codice arbitrario. Può anche essere usata per eseguire binari memorizzati in partizioni noexec.
La prima exec in userland è stata creata da grugq. Questo repository è fortemente ispirato alla libreria Mettle di Rapid7, che include una descrizione completa nel blog della tecnica.
Inizialmente, gran parte del codice di questo repository imitava la libreria Mettle, ma da allora è stato esteso per includere ulteriore complessità al fine di aggirare la verifica SELinux.
SELinux include la verifica execmem, che garantisce:
PROT_WRITE in PROT_EXEC usando mprotect è vietato).mprotectPer aggirare mprotect, è necessario creare un file temporaneo. Ciò può essere ottenuto usando memfd_create combinato con munmap e mmap, evitando così del tutto la chiamata di sistema mprotect.
L'esempio elf_debugger.c dimostra che qualsiasi ELF contiene una regione PT_LOAD che è sia eseguibile che scrivibile. Questa regione è necessaria per caricare le informazioni del programma durante l'esecuzione. Per affrontare questo problema, è stata creata l'implementazione bypass_wx.c. Questo design:
SIGSEGV.PROT_EXEC a PROT_WRITE.| OS | Architettura | Risultato |
|---|---|---|
| Ubuntu 24.04 | x86_64 | Successo |
| Archlinux 6.12.4 | x86_64 | Successo |
| CentOS | x86_64 | Successo |
| Raspberry Pi OS | arm64 | Successo |
| S23 Android 14 | arm64 | Successo |
Questa sezione descrive come compilare per macchine Android e x86. Assicurarsi che libelf sia installato prima di procedere.
mkdir build && cd build
cmake ..
make
desktop % strace ./uexec hello others args here 2>&1 | grep exec
execve("./uexec", ["./uexec", "hello", "others", "args", "here"], 0x7ffc34ec02f0 /* 54 vars */) = 0
desktop % strace bash -c ./hello 2>&1 | grep exec
execve("/usr/bin/bash", ["bash", "-c", "./hello"], 0x7ffebecc3130 /* 54 vars */) = 0
newfstatat(AT_FDCWD, "/desktop/userland-exec/build", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
newfstatat(AT_FDCWD, "/desktop/userland-exec", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
execve("./hello", ["./hello"], 0x5fb22658e2a0 /* 54 vars */) = 0
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Debug ..
make
mkdir build && cd build
cmake -DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-30 ..
make
desktop % adb push uexec hello /data/local/tmp
uexec: 1 file pushed, 0 skipped. 113.9 MB/s (22912 bytes in 0.000s)
hello: 1 file pushed, 0 skipped. 184.9 MB/s (6936 bytes in 0.000s)
2 files pushed, 0 skipped. 0.3 MB/s (29848 bytes in 0.090s)
desktop % adb shell
dm3q:/ $ cd /data/local/tmp
dm3q:/data/local/tmp $ chmod +x uexec
dm3q:/data/local/tmp $ ./hello
Hello World
dm3q:/data/local/tmp $ ./uexec hello
Hello World
dm3q:/data/local/tmp $
Su CentOS, la libreria libc può mostrare un comportamento insolito. Per risolvere questo problema, è stato fornito un semplice programma "Hello, World" scritto in assembly, hello_nolibc.s. Questo esempio insieme al cmake dimostra come compilare ed eseguire un programma senza collegarsi a libc.
Se il tuo CMAKE è superiore alla 4.0 puoi aggiungere nella compilazione -DCMAKE_POLICY_VERSION_MINIMUM=3.5.
Questo repository utilizza la Licenza GPL-3.0.