mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
88 lines
4.9 KiB
Markdown
88 lines
4.9 KiB
Markdown
# DDexec / EverythingExec
|
|
|
|
{{#include ../../../banners/hacktricks-training.md}}
|
|
|
|
## Contesto
|
|
|
|
In Linux, per eseguire un programma, deve esistere come file, deve essere accessibile in qualche modo attraverso la gerarchia del file system (questo è proprio come funziona `execve()`). Questo file può risiedere su disco o in ram (tmpfs, memfd) ma hai bisogno di un percorso. Questo ha reso molto facile controllare cosa viene eseguito su un sistema Linux, rende facile rilevare minacce e strumenti dell'attaccante o prevenire che provino a eseguire qualsiasi cosa di loro (_e. g._ non consentire agli utenti non privilegiati di posizionare file eseguibili ovunque).
|
|
|
|
Ma questa tecnica è qui per cambiare tutto questo. Se non puoi avviare il processo che desideri... **allora dirotta uno già esistente**.
|
|
|
|
Questa tecnica ti consente di **bypassare tecniche di protezione comuni come read-only, noexec, whitelisting dei nomi dei file, whitelisting degli hash...**
|
|
|
|
## Dipendenze
|
|
|
|
Lo script finale dipende dai seguenti strumenti per funzionare, devono essere accessibili nel sistema che stai attaccando (per impostazione predefinita li troverai ovunque):
|
|
```
|
|
dd
|
|
bash | zsh | ash (busybox)
|
|
head
|
|
tail
|
|
cut
|
|
grep
|
|
od
|
|
readlink
|
|
wc
|
|
tr
|
|
base64
|
|
```
|
|
## La tecnica
|
|
|
|
Se sei in grado di modificare arbitrariamente la memoria di un processo, allora puoi prenderne il controllo. Questo può essere utilizzato per dirottare un processo già esistente e sostituirlo con un altro programma. Possiamo ottenere questo sia utilizzando la syscall `ptrace()` (che richiede di avere la possibilità di eseguire syscall o di avere gdb disponibile sul sistema) o, più interessantemente, scrivendo in `/proc/$pid/mem`.
|
|
|
|
Il file `/proc/$pid/mem` è una mappatura uno a uno dell'intero spazio degli indirizzi di un processo (_e. g._ da `0x0000000000000000` a `0x7ffffffffffff000` in x86-64). Questo significa che leggere o scrivere in questo file a un offset `x` è lo stesso che leggere o modificare i contenuti all'indirizzo virtuale `x`.
|
|
|
|
Ora, abbiamo quattro problemi di base da affrontare:
|
|
|
|
- In generale, solo root e il proprietario del programma del file possono modificarlo.
|
|
- ASLR.
|
|
- Se proviamo a leggere o scrivere in un indirizzo non mappato nello spazio degli indirizzi del programma, otterremo un errore I/O.
|
|
|
|
Questi problemi hanno soluzioni che, sebbene non siano perfette, sono buone:
|
|
|
|
- La maggior parte degli interpreti di shell consente la creazione di descrittori di file che saranno poi ereditati dai processi figli. Possiamo creare un fd che punta al file `mem` della shell con permessi di scrittura... quindi i processi figli che utilizzano quel fd saranno in grado di modificare la memoria della shell.
|
|
- ASLR non è nemmeno un problema, possiamo controllare il file `maps` della shell o qualsiasi altro dal procfs per ottenere informazioni sullo spazio degli indirizzi del processo.
|
|
- Quindi dobbiamo `lseek()` sul file. Dalla shell questo non può essere fatto a meno di utilizzare il famigerato `dd`.
|
|
|
|
### In maggior dettaglio
|
|
|
|
I passaggi sono relativamente facili e non richiedono alcun tipo di competenza per comprenderli:
|
|
|
|
- Analizza il binario che vogliamo eseguire e il loader per scoprire quali mappature necessitano. Poi crea un "shell"code che eseguirà, in linea di massima, gli stessi passaggi che il kernel esegue ad ogni chiamata a `execve()`:
|
|
- Crea le suddette mappature.
|
|
- Leggi i binari in esse.
|
|
- Imposta i permessi.
|
|
- Infine, inizializza lo stack con gli argomenti per il programma e posiziona il vettore ausiliario (necessario per il loader).
|
|
- Salta nel loader e lascia che faccia il resto (carica le librerie necessarie per il programma).
|
|
- Ottieni dal file `syscall` l'indirizzo a cui il processo tornerà dopo la syscall che sta eseguendo.
|
|
- Sovrascrivi quel luogo, che sarà eseguibile, con il nostro shellcode (attraverso `mem` possiamo modificare pagine non scrivibili).
|
|
- Passa il programma che vogliamo eseguire allo stdin del processo (sarà `read()` da detto "shell"code).
|
|
- A questo punto spetta al loader caricare le librerie necessarie per il nostro programma e saltare in esso.
|
|
|
|
**Controlla lo strumento in** [**https://github.com/arget13/DDexec**](https://github.com/arget13/DDexec)
|
|
|
|
## EverythingExec
|
|
|
|
Ci sono diverse alternative a `dd`, una delle quali, `tail`, è attualmente il programma predefinito utilizzato per `lseek()` attraverso il file `mem` (che era l'unico scopo per utilizzare `dd`). Queste alternative sono:
|
|
```bash
|
|
tail
|
|
hexdump
|
|
cmp
|
|
xxd
|
|
```
|
|
Impostando la variabile `SEEKER` puoi cambiare il seeker utilizzato, _e. g._:
|
|
```bash
|
|
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`:
|
|
```bash
|
|
SEEKER=xxd SEEKER_ARGS='-s $offset' zsh ddexec.sh ls -l <<< $(base64 -w0 /bin/ls)
|
|
```
|
|
Blocca questo, EDRs.
|
|
|
|
## Riferimenti
|
|
|
|
- [https://github.com/arget13/DDexec](https://github.com/arget13/DDexec)
|
|
|
|
{{#include ../../../banners/hacktricks-training.md}}
|