Encontre o Sink de Tool-Exec: RCE Através de um Agente LLM
O desafio
Este agente LLM deixa o modelo chamar ferramentas retornando JSON. Uma ferramenta executa o código que o modelo coloca na resposta, sem nenhum sandbox - então uma saída de modelo envenenada vira execução remota de código. Leia os dois arquivos e digite a chamada que executa esse código.
O que você vai aprender
- Reconhecer exec()/eval() sobre a saída de um LLM como um sink de execução remota de código
- Rastrear os dados da resposta do modelo, do parsing JSON até o despachante de ferramentas
- Entender como a injeção de prompt escala para execução de código
- Diferenciar executar código (exec) de fazer parsing seguro de dados (ast.literal_eval)
- Explicar por que a saída do modelo deve ser tratada como entrada não confiável
Habilidades testadas
Pré-requisitos
- Leitura básica de Python
- Como funciona, em alto nível, uma chamada de ferramenta/função de um LLM
- O que é injeção de prompt
Como funciona
Agentes que chamam ferramentas deixam um modelo agir: ele retorna uma solicitação estruturada (um nome de ferramenta e argumentos) e o runtime a executa. O problema de segurança é que a saída do modelo não é um dado confiável. Um atacante pode direcioná-la por meio de injeção de prompt - uma instrução maliciosa escondida em uma mensagem do usuário, em uma página web ou em um documento recuperado - então qualquer ferramenta que execute a saída bruta do modelo é um sink de injeção.
Em agent.py, run_tool lê o nome da ferramenta a partir do JSON do modelo e, para a ferramenta python, chama exec(args['code']). Qualquer string que o modelo coloque em args['code'] é executada como Python no host, sem nenhum sandbox e com privilégios totais do processo. Um prompt envenenado pode fazer o modelo emitir {"tool": "python", "args": {"code": "__import__('os').system('...')"}} e o agente executa isso - isso é execução remota de código que se origina de texto, não de uma porta de rede.
O contraste está em tools.py. parse_number usa ast.literal_eval, que converte uma string em um número, lista ou dicionário e recusa qualquer coisa executável. Essa é a primitiva certa quando você precisa de dados a partir de texto. O trabalho do revisor é seguir a resposta do modelo até a chamada que a executa - e a chamada que a executa é exec.
Erros comuns
- Apontar para json.loads. Fazer o parsing da resposta é normal; o bug é executar um dos seus campos. Nomeie a chamada que executa o código.
- Escolher ast.literal_eval. Esse é o auxiliar seguro em tools.py - ele faz o parsing de dados e nunca executa.
- Supor que o prompt de sistema te protege. Um modelo pode ser convencido a ignorar qualquer instrução; o runtime não deve confiar na sua saída.
- Achar que "é só uma ferramenta de calculadora". A ferramenta python executa código arbitrário, não aritmética - o nome do recurso esconde o sink.
Como se proteger
Nunca passe a saída do modelo para exec() ou eval(). Trate toda chamada de ferramenta vinda do modelo como controlada por um atacante e restrinja o que as ferramentas podem fazer.
- Substitua uma ferramenta de código bruto por uma lista de permissão fixa de ferramentas tipadas e parametrizadas (sem código livre).
- Se a execução de código for realmente necessária, rode-a em um sandbox forte (container separado, sem rede, privilégios reduzidos, limites de recursos).
- Valide e verifique o schema dos argumentos da ferramenta antes do despacho; rejeite qualquer coisa inesperada.
- Use
ast.literal_evaloujson.loadsquando você só precisar transformar texto em dados.
Solução completa
Estatísticas da comunidade
Hacks de hoje relacionados
Colaboradores creditados
Estes hackers relataram problemas, melhoraram o conteúdo e ajudaram a fortalecer esta página.