
Análisis técnico y exploit de prueba de concepto para CVE-2025-57489, una vulnerabilidad de escalada de privilegios en SuperDuper! v3.10 mediante un diseño inadecuado del binario setuid, que permite la ejecución arbitraria de comandos como root.
Del blog del desarrollador:
Cuando el candado de SuperDuper está desbloqueado para permitir la ejecución sin tener que introducir una contraseña de administrador, un programa de terceros podría utilizar nuestra autorización para ejecutar algo que no sea una copia de seguridad con privilegios de administrador.
Descripción del CVE:
Control de acceso incorrecto en el componente SDAgent de Shirt Pocket SuperDuper! v3.10 permite a los atacantes escalar privilegios a root debido al uso inadecuado de un binario setuid.
Este autor no es el descubridor de la vulnerabilidad, quien es identificado por el desarrollador de SuperDuper como «investigador de seguridad anónimo». No me atribuyo el mérito de haber descubierto esta vulnerabilidad; solo me interesé en hacer un análisis técnico de la misma.
Puntuación CVSS 3.1: 8.1: Alta (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H)
Para evitar esta vulnerabilidad, elimine la aplicación SuperDuper! o aplique la actualización 3.11.
Advertencia: Debe descargar la actualización directamente del sitio web del desarrollador para evitar la vulnerabilidad CVE-2025-61228.
Este análisis de exploit y prueba de concepto se proporcionan únicamente con fines educativos. Úselo bajo su propio riesgo.
El componente SDAgent de la aplicación SuperDuper! es un binario setuid. Debido a un mal diseño/implementación, SDAgent existe únicamente para ejecutar comandos de shell solicitados por otra aplicación, y SDAgent no parece realizar ninguna verificación de la aplicación solicitante, ni implementar salvaguardas sobre qué tipos de comandos de shell se pueden solicitar. Como resultado, los atacantes pueden hacer que las versiones afectadas de la herramienta SDAgent ejecuten cualquier comando de shell con privilegios de root. El parche del desarrollador solo aborda la falta de verificación del solicitante por parte de SDAgent; no aborda el diseño de la herramienta auxiliar «títere», lo que deja al agente potencialmente vulnerable a futuros ataques.
La descripción del desarrollador sobre este problema era vaga, pero el comentario «Cuando el candado en SuperDuper está desbloqueado» me apuntó en la dirección correcta rápidamente. Comenzando con una versión anterior (aún vulnerable) de SuperDuper, hice clic en el icono del candado y me autentiqué. En Activity Monitor, noté que aparecía un nuevo proceso relacionado con SuperDuper: SDAgent. Encontré este componente en el archivo bundle de SuperDuper y examiné sus atributos en Terminal. Después de alternar el candado entre apagado y encendido, noté que el archivo SDAgent es un binario setuid cada vez que el candado está desbloqueado. Dado ese atributo y el nombre del archivo, concluí que debe ser una «herramienta auxiliar privilegiada», aunque parecía un poco pequeño para ese propósito.
Setuid es una forma muy antigua de escalada de privilegios, y normalmente construirías toda tu funcionalidad de «necesita root» dentro de la herramienta «auxiliar» y simplemente le pedirías que haga lo suyo, o desarrollarías una vía de comunicación que permita a una aplicación cliente hacer solicitudes específicas a la herramienta auxiliar. Pero dado lo pequeño que es este archivo SDAgent (solo 137 KB), parece poco probable que contenga todo el código que requiere root para lo que esta aplicación afirma hacer. Con la curiosidad despertada, ejecuté la utilidad "strings" en SDAgent para hacerme una idea de lo que se supone que debe hacer. Esto resultó ser muy esclarecedor. Prácticamente no había salida (en comparación con lo que normalmente se ve en un binario de aplicación), y la salida básicamente indica que SDAgent tiene una sola función: ejecutar cualquier script de shell proporcionado por el solicitante, por ejemplo:
% strings /Applications/SuperDuper\!.app/Contents/MacOS/SDAgent
...
/bin/bash
bash
SDAgent could not fork process
****DONE****
Es un mal diseño crear una herramienta auxiliar que ejecute literalmente cualquier comando; «no seas un títere» es una regla importante a seguir al hacer una herramienta auxiliar.
Continué con la suposición de que SuperDuper debe abrir SDAgent, establecer un pipe de comunicación y luego enviar scripts de shell a SDAgent. Un breve vistazo al paquete de la aplicación SuperDuper mostró que iba por buen camino. Esta aplicación parece administrar toda su actividad de copia mediante scripts de shell.
Hice algunos intentos endebles de simplemente canalizar comandos al agente:
printf "whoami" | /Applications/SuperDuper\!.app/Contents/MacOS/SDAgent
zsh: done printf "whoami" |
zsh: segmentation fault /Applications/SuperDuper!.app/Contents/MacOS/SDAgent
SDAgent se bloqueó, ¡supongo que no será tan fácil! Sin desanimarme, comencé a hacer algunas suposiciones basadas en cómo funcionan normalmente las aplicaciones auxiliares setuid. Entre un par de utilidades de shell, normalmente crearías algunos pipes para stdin, stdout y stderr, y luego harías fork y exec. El proceso hijo heredaría una copia de cada pipe, por lo que cada lado tendría automáticamente pipes de comunicación abiertos hacia el otro. Con una aplicación que enlaza contra frameworks de alto nivel, fork() no es una opción. En cambio, tendrías que desarrollar alguna forma de comunicar a la aplicación hija cómo pretendes comunicarte con ella. La salida de "strings" dio una pista:
strings /Applications/SuperDuper\!.app/Contents/MacOS/SDAgent
...
STDIN_PIPE_READ_FD
%i %i %i
«STDIN_PIPE_READ_FD»: el desarrollador es muy transparente sobre lo que está sucediendo aquí. Podemos obtener un poco más de contexto sobre esta cadena desde otool:
otool -tV /Applications/SuperDuper\!.app/Contents/MacOS/SDAgent
/Applications/SuperDuper!.app/Contents/MacOS/SDAgent:
...
00000001000011a8 leaq 0xa56(%rip), %rdi ## literal pool for: "STDIN_PIPE_READ_FD"
00000001000011af callq 0x1000017f6 ## symbol stub for: _getenv
OK, así que probablemente sea una variable de entorno. Intentemos de nuevo el truco fácil del pipe, y voy a asumir que SDAgent simplemente recibirá mis comandos desde su descriptor de archivo stdin (0):
export STDIN_PIPE_READ_FD=0
printf "whoami" | /Applications/SuperDuper\!.app/Contents/MacOS/SDAgent
1557%
Después de repetirlo unas veces quedó claro que «1557» era el ID de proceso del SDAgent generado. No fue muy útil (y no era la salida «root» que esperaba), pero no se bloqueó esta vez, así que era alentador. Lo intenté de nuevo con algo que hiciera un cambio en el sistema de archivos:
printf "touch /Library/test" | /Applications/SuperDuper\!.app/Contents/MacOS/SDAgent
1593%
No, el archivo no se creó; es hora de arremangarse. Deshabilité SIP, inicié dtruss y le pedí a SuperDuper que ejecutara una tarea. Justo después de autenticarme para iniciar la tarea, veo la siguiente salida de dtruss (adjunta al proceso SDAgent):
read(0x0, "21 23 24 \0", 0x800) = 9 0
dup2(0x15, 0x1, 0x0) = 1 0
dup2(0x17, 0x2, 0x0) = 2 0
write(0x1, "1615\0", 0x4) = 4 0