
SSRF mediante sockets TCP sin procesar de smtplib que evaden la lista de bloqueo HTTP en AutoGPT SendEmailBlock
CVE-2026-33234 | Moderado 5.0 | GHSA-4jwj-6mg5-wrwf Autor: Pavan Nallamothu
Estaba mapeando cada entrada controlada por el usuario que tocaba la red en la Plataforma AutoGPT. La capa HTTP estaba bien asegurada. Rangos de IP privadas (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), loopback, endpoints de metadatos de la nube -- todo en lista negra. Confirmé la puerta HTTP desde múltiples ángulos. Nada lograba pasar.
Entonces abrí el esquema de configuración de SendEmailBlock.
El campo del servidor SMTP era una entrada de texto libre. No era una credencial de administrador. No era una configuración bloqueada establecida una vez en el despliegue. Era un campo que cualquier usuario autenticado podía rellenar con lo que quisiera. Rastreé la ruta del código y descubrí que smtplib.SMTP() abre un socket TCP crudo. Esa conexión nunca pasa por la ruta HTTP donde reside la lista negra de IPs. Existían dos rutas de salida en la plataforma. Solo una estaba protegida.
Apunté el servidor SMTP a localhost:22.
El banner SSH apareció en el mensaje de error. smtplib se conecta a lo que le des, intenta leer un saludo SMTP 220, y cuando recibe otra cosa, envuelve los bytes crudos en un SMTPConnectError. Esa excepción se propaga a través del marco de ejecución de AutoGPT y aparece limpiamente en la salida del bloque. Estaba viendo la cadena de versión SSH del objetivo sin tocar jamás la capa HTTP.
Esto es lo que lo hizo interesante. smtplib no es solo un cliente de correo. Es un capturador de banners TCP con informes de error estructurados. Apúntalo al puerto 6379 y obtienes la firma de protocolo de Redis. Apúntalo a un puerto cerrado y ConnectionRefusedError te dice que el host está vivo pero el puerto está caído. Apúntalo a 169.254.169.254:80 y confirmas que el endpoint de metadatos de la nube es alcanzable. Cada intento de conexión devuelve un error diferente e informativo. SSRF no ciego a través de una función que se suponía debía enviar correo.
El diseño de SMTPConfig agrava el problema. En una arquitectura segura, la dirección del servidor SMTP sería una credencial controlada por el administrador -- establecida una vez, bloqueada, nunca expuesta a los usuarios. En cambio, es una entrada por ejecución. Cada usuario autenticado controla dónde abre conexiones TCP la plataforma.
# Configuración de SendEmailBlock - establece el servidor SMTP a objetivos internos
# Escanear SSH
smtp_server = "10.0.0.5"
smtp_port = 22
# El error revela: "SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.6"
# Escanear Redis
smtp_server = "10.0.0.5"
smtp_port = 6379
# El error revela: "-ERR unknown command ..."
# Escanear puerto cerrado
smtp_server = "10.0.0.5"
smtp_port = 9999
# El error revela: "ConnectionRefusedError" (puerto cerrado, host vivo)
# Golpear metadatos de la nube
smtp_server = "169.254.169.254"
smtp_port = 80
# Confirma la accesibilidad del endpoint de metadatos
Verifiqué toda la cadena a través de la API de ejecución de bloques:
# Prueba directa equivalente contra la API de ejecución de bloques
curl -X POST https://autogpt-platform/api/blocks/execute \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"block_id": "send_email_block",
"inputs": {
"smtp_server": "10.0.0.5",
"smtp_port": 22,
"to": "[email protected]",
"subject": "test",
"body": "test"
}
}'
# La respuesta contiene SMTPConnectError con el banner SSH
graph LR
A[Atacante establece el servidor SMTP a IP interna] --> B[SendEmailBlock llama a smtplib.SMTP]
B --> C[Conexión TCP cruda a objetivo:puerto]
C --> D{¿Responde el servicio?}
D -->|Sí| E[Banner leído como saludo SMTP]
E --> F[SMTPConnectError con datos del banner]
F --> G[El error se propaga a la salida del bloque]
D -->|No| H[ConnectionRefused = puerto cerrado]
G --> I[El atacante lee la versión del servicio]La superficie de ataque que esto abre es significativa. Los banners SSH revelan versiones exactas (OpenSSH_8.9p1 Ubuntu-3ubuntu0.6). Redis filtra su firma de protocolo. MySQL envía su cadena de versión. Cada banner es una búsqueda de CVE a punto de ocurrir. Un atacante mapea la red interna, identifica cada servicio en ejecución y su versión exacta, y luego apunta al más débil. Todo desde un campo de texto etiquetado como "Servidor SMTP".
Tres comprobaciones faltantes crearon esto: sin validación de IP en la ruta SMTP, sin restricción de puertos, sin saneamiento de excepciones. La plataforma protegía cada puerta de salida excepto la etiquetada como "correo saliente".
Reporté el problema a Significant Gravitas. Entendieron la brecha arquitectónica de inmediato.
Corregido en: autogpt-platform-backend 0.6.52 (se añadió validación del servidor SMTP al cumplimiento de la lista negra, se aplicaron restricciones de puertos)