
PoC de un solo archivo para Rails CVE-2026-66066: lectura arbitraria de archivos, recuperación de secretos, escaneo multihilo y RCE condicional mediante variaciones de imágenes firmadas.
Un proof of concept de un solo archivo y sin dependencias, más un laboratorio Docker aislado en loopback
para la vulnerabilidad de lectura arbitraria de archivos en Rails Active Storage/libvips. También
demuestra la escalación condicional del aviso desde una secret_key_base recuperada
hasta una variación de imagen falsificada y ejecución de comandos.
Referencias principales: Aviso de Rails, Análisis forense de Rails, el informe técnico de Ethiack y el lanzamiento 8.1.3.1.
https://github.com/user-attachments/assets/fdcb5651-c1d1-4bc4-b322-8f1205b09635
kr2s.py contiene el cliente completo en un solo archivo:
h5py ni numpy;La herramienta no instala paquetes, no inicia un listener de callback, no requiere curl
en el objetivo ni depende de make. La fase RCE usa la ruta de representación integrada de Active
Storage y no requiere un gadget de Marshal.
Inicia el laboratorio vulnerable:
cd lab
RAILS_VERSION=8.1.3 docker compose up --build
El puerto de Compose está vinculado a 127.0.0.1 y el contenedor se ejecuta como un
usuario sin privilegios con todas las capacidades de Linux eliminadas.
En otra terminal:
# Intrusivo: sube un blob y luego confirma que /etc/hostname es legible.
python3 kr2s.py check http://127.0.0.1:3000
# Recuperar un prefijo de tamaño fijo. La salida binaria va a stdout salvo que se use -o.
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
# Recuperar secretos seleccionados del entorno. Los valores se redactan por defecto.
python3 kr2s.py secrets http://127.0.0.1:3000
# Mostrar los valores completos de entorno coincidentes para análisis autorizado.
python3 kr2s.py secrets http://127.0.0.1:3000 --show-full
# Preflight pasivo de un objetivo o de un archivo con un objetivo por línea.
python3 kr2s.py scan http://127.0.0.1:3000
python3 kr2s.py scan targets.txt --threads 10 --json scan.json
# Confirmar intrusivamente la lectura de archivos en cada objetivo de la lista.
python3 kr2s.py scan targets.txt --active
# Probar cargadores seleccionados de libvips.
python3 kr2s.py probe http://127.0.0.1:3000
# Escalación condicional. Esto ejecuta el comando suministrado.
python3 kr2s.py rce http://127.0.0.1:3000 "id; uname -a"
Ejecuta python3 kr2s.py COMMAND --help para ver todas las opciones. Controles comunes
en aplicaciones reales incluyen --harvest-url, --show-path, --proxy, --insecure y
--skb.
secrets --show-full imprime los valores completos de las variables de entorno coincidentes.
Sin esa opción, la herramienta imprime solo los primeros 12 caracteres y una elipsis.
Los archivos solicitados con --also-read, incluidos los archivos de credenciales predeterminados
de Rails, se imprimen hasta 600 caracteres cuando son legibles.
El scan pasivo solo informa si la página expone una representación de Active Storage
recolectable; no puede identificar el nivel de parche de Rails instalado.
scan --active sube un blob malicioso e intenta la lectura canario. Un resultado activo
fallido se etiqueta como BLOCKED_OR_INCONCLUSIVE, no como SAFE, porque los WAF,
la autenticación, las variaciones no compatibles y el parche de Rails pueden parecer idénticos
desde fuera de la aplicación.
Detén el laboratorio con:
cd lab
docker compose down
image/png.matload de libvips; los bytes del archivo objetivo
se convierten en píxeles de imagen y se devuelven en un PNG generado.El archivo híbrido satisface a dos analizadores a la vez: su texto comienza con
MATLAB 5.0, mientras que la palabra de versión en el desplazamiento 124 selecciona la ruta
MATLAB 7.3 respaldada por HDF5. El parche de Rails bloquea las operaciones de libvips marcadas
como no confiables antes de que un archivo controlado por el atacante pueda llegar a matload.
rce primero lee SECRET_KEY_BASE de /proc/self/environ, salvo que se proporcione --skb.
Deriva la clave del verificador de Active Storage y firma una variación JSON que contiene una
operación instance_eval. En la ruta vips afectada, la operación llega a Vips::Image.public_send.
El PoC la envía a través de la ruta de representación integrada, ejecuta el comando suministrado
mediante /bin/sh y captura ambos flujos de salida.
Esta segunda fase es condicional a recuperar el secreto de firma y alcanzar el comportamiento vulnerable de transformación de vips descrito en el análisis de Ethiack sobre CVE-2025-24293. El parche de CVE-2026-66066 cierra el punto de entrada de lectura de archivos; no es una solución general para secretos de firma filtrados previamente. Rota los secretos ante una posible exposición, como recomienda el aviso de Rails.
La salida del comando se escribe en un archivo aleatorio /tmp/.kr2s_*, se recupera mediante
la misma primitiva de lectura de archivos y luego se elimina con una segunda carga útil firmada.
Las lecturas devuelven la región de tamaño fijo solicitada. Si el origen es más corto, su prefijo
va seguido de bytes cero. Usa --offset para regiones posteriores.
La variación predeterminada del laboratorio solo convierte a PNG, por lo que la recuperación es
exacta byte a byte. Las aplicaciones reales pueden redimensionar las variaciones. El modo de clave
recolectada usa una columna de un píxel para evitar el remuestreo horizontal, pero una variación con
una altura menor aún puede cambiar la geometría. En ese caso, el cliente falla explícitamente;
reduce --size o recolecta una representación que no se redimensione.
Cada comando es intrusivo: crea blobs persistentes de Active Storage y puede crear variantes
procesadas. rce además ejecuta el comando suministrado.