
SSRF через smtplib raw TCP-сокеты в обход HTTP-блоклиста в AutoGPT SendEmailBlock
CVE-2026-33234 | Умеренный 5.0 | GHSA-4jwj-6mg5-wrwf Автор: Pavan Nallamothu
Я сопоставлял каждый управляемый пользователем ввод, который касался сети в AutoGPT Platform. HTTP-уровень был надёжно заблокирован. Частные диапазоны IP (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), loopback, конечные точки метаданных облака — всё в блок-листе. Я подтвердил HTTP-шлюз с нескольких сторон. Ничего не проходило.
Затем я открыл схему конфигурации SendEmailBlock.
Поле SMTP-сервера было вводом свободного текста. Не учётные данные администратора. Не заблокированная конфигурация, задаваемая один раз при развёртывании. Поле, которое любой аутентифицированный пользователь мог заполнить чем угодно. Я проследил путь кода и обнаружил, что smtplib.SMTP() открывает сырой TCP-сокет. Это соединение никогда не проходит через HTTP-путь, где находится блок-лист IP. В платформе существовало два исходящих пути. Защищён был только один.
Я указал SMTP-сервер на localhost:22.
SSH-баннер вернулся в сообщении об ошибке. smtplib подключается к чему угодно, пытается прочитать SMTP-приветствие 220, а когда получает что-то другое, оборачивает сырые байты в SMTPConnectError. Это исключение распространяется через исполнительный фреймворк AutoGPT и чисто отображается в выводе блока. Я видел строку версии SSH цели, не касаясь HTTP-уровня.
Вот что делало это интересным. smtplib — это не просто почтовый клиент. Это захватчик TCP-баннеров со структурированным отчётом об ошибках. Укажите порт 6379 — и вы получите сигнатуру протокола Redis. Укажите закрытый порт — и ConnectionRefusedError сообщит вам, что хост жив, но порт закрыт. Укажите 169.254.169.254:80 — и вы подтвердите, что конечная точка метаданных облака доступна. Каждая попытка соединения возвращает разную, информативную ошибку. Неслепой SSRF через функцию, которая должна была отправлять электронную почту.
Дизайн SMTPConfig усугубляет проблему. В безопасной архитектуре адрес SMTP-сервера был бы управляемыми администратором учётными данными — заданными один раз, заблокированными, никогда не доступными пользователям. Вместо этого это ввод на каждое выполнение. Каждый аутентифицированный пользователь контролирует, куда платформа открывает TCP-соединения.
# Конфигурация SendEmailBlock - установка SMTP-сервера на внутренние цели
# Сканирование SSH
smtp_server = "10.0.0.5"
smtp_port = 22
# Ошибка раскрывает: "SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.6"
# Сканирование Redis
smtp_server = "10.0.0.5"
smtp_port = 6379
# Ошибка раскрывает: "-ERR unknown command ..."
# Сканирование закрытого порта
smtp_server = "10.0.0.5"
smtp_port = 9999
# Ошибка раскрывает: "ConnectionRefusedError" (порт закрыт, хост жив)
# Запрос к метаданным облака
smtp_server = "169.254.169.254"
smtp_port = 80
# Подтверждает доступность конечной точки метаданных
Я проверил всю цепочку через API выполнения блока:
# Эквивалентный прямой тест против API выполнения блока
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"
}
}'
# Ответ содержит SMTPConnectError с SSH-баннером
graph LR
A[Attacker sets SMTP server to internal IP] --> B[SendEmailBlock calls smtplib.SMTP]
B --> C[Raw TCP connect to target:port]
C --> D{Service responds?}
D -->|Yes| E[Banner read as SMTP greeting]
E --> F[SMTPConnectError with banner data]
F --> G[Error propagates to block output]
D -->|No| H[ConnectionRefused = port closed]
G --> I[Attacker reads service version]Поверхность атаки, которую это открывает, значительна. SSH-баннеры раскрывают точные версии (OpenSSH_8.9p1 Ubuntu-3ubuntu0.6). Redis утекает свою сигнатуру протокола. MySQL отправляет строку версии. Каждый баннер — это поиск CVE, ожидающий своего часа. Атакующий составляет карту внутренней сети, идентифицирует каждый работающий сервис и его точную версию, затем нацеливается на самый слабый. Всё из текстового поля с надписью "SMTP Server".
Три отсутствующие проверки создали это: отсутствие валидации IP на SMTP-пути, отсутствие ограничения портов, отсутствие санитизации исключений. Платформа защитила каждую исходящую дверь, кроме той, что с надписью "исходящая почта".
Я сообщил об этой проблеме в Significant Gravitas. Они сразу поняли архитектурный пробел.
Исправлено в: autogpt-platform-backend 0.6.52 (добавлена валидация SMTP-сервера для применения блок-листа, применены ограничения портов)