Skip to content
KitploitKITPLOIT
ИнструментыЭксплойтыБлог
Log in
Отправить
ИнструментыЭксплойтыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

ЛентыКонтактыКонфиденциальность© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2026-51416 — Анализирует конкретную CVE в обработчике OAuth WeChat, выявляя неограниченное чтение HTTP-ответов, приводящее к отказу в обслуживании, с рекомендациями по устранению. | Kitploit
Инструменты/GitHubGitHub/renio-wow/cve-2026-51416
Статический анализАнализ уязвимостейАнализ КодаВеб-безопасность
GitHubrenio-wow/cve-2026-51416

CVE-2026-51416

Анализирует конкретную CVE в обработчике OAuth WeChat, выявляя неограниченное чтение HTTP-ответов, приводящее к отказу в обслуживании, с рекомендациями по устранению.

Репозиторий
145 месяцев назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

1. Сводка

  • Тип уязвимости: Отказ в обслуживании / Неограниченное чтение HTTP-ответа ([CWE-400])
  • Место обнаружения: backend/internal/handler/auth_wechat_oauth.go:1149
  • Описание уязвимости: В процессе обмена OAuth-токена WeChat используется io.ReadAll(resp.Body) для чтения полного тела HTTP-ответа вышестоящего сервиса в память без установления какого-либо максимального ограничения размера перед буферизацией.

2. Анализ

Шаг 1: Изучение отмеченного места сбоя в backend/internal/handler/auth_wechat_oauth.go:1124

Были проверены отмеченная функция и более 50 строк окружающего контекста. Местом сбоя является вспомогательная функция обмена токена exchangeWeChatOAuthCode(). Эта функция формирует GET-запрос к WeChat, отправляет его с помощью обычного http.Client, а затем считывает всё тело ответа с помощью io.ReadAll(resp.Body).

func exchangeWeChatOAuthCode(ctx context.Context, cfg wechatOAuthConfig, code string) (*wechatOAuthTokenResponse, error) {
    endpoint, err := url.Parse(wechatOAuthAccessTokenURL)
    ...
    req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
    ...
    client := &http.Client{Timeout: 30 * time.Second}
    resp, err := client.Do(req)
    ...
    defer func() { _ = resp.Body.Close() }()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return nil, fmt.Errorf("read wechat access token response: %w", err)
    }
    if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
        return nil, fmt.Errorf("wechat access token status=%d", resp.StatusCode)
    }
    ...
}

Доказательства:

  • backend/internal/handler/auth_wechat_oauth.go:1142 создаёт client := &http.Client{Timeout: 30 * time.Second}.
  • backend/internal/handler/auth_wechat_oauth.go:1149 выполняет body, err := io.ReadAll(resp.Body).
  • Никакого io.LimitReader, проверки ContentLength или вызова вспомогательной функции перед буферизацией тела ответа нет.

Анализ: Единственной защитой здесь является ограничение по времени (Timeout: 30 * time.Second), а не ограничение памяти. Удалённый узел всё ещё может вызвать большие выделения памяти до достижения EOF. Затем была прослежена достижимость этого места сбоя из производственных маршрутов.

Шаг 2: Прослеживание основного пути запроса от публичного маршрута обратного вызова OAuth

Были проверены регистрация маршрутов аутентификации и обработчик WeChat OAuth. Маршрут зарегистрирован в публичной группе /auth, а не в группе, защищённой JWT. Обработчик обратного вызова получает предоставленные пользователем параметры запроса code и state перед вызовом отмеченного потока.

// routes
auth := v1.Group("/auth")
auth.Use(servermiddleware.BackendModeAuthGuard(settingService))
...
auth.GET("/oauth/wechat/start", h.Auth.WeChatOAuthStart)
auth.GET("/oauth/wechat/callback", h.Auth.WeChatOAuthCallback)
// callback handler
func (h *AuthHandler) WeChatOAuthCallback(c *gin.Context) {
    ...
    code := strings.TrimSpace(c.Query("code"))
    state := strings.TrimSpace(c.Query("state"))
    if code == "" || state == "" {
        redirectOAuthError(c, frontendCallback, "missing_params", "missing code/state", "")
        return
    }
    ...
    tokenResp, userInfo, err := fetchWeChatOAuthIdentity(c.Request.Context(), cfg, code)
    if err != nil {
        redirectOAuthError(c, frontendCallback, "provider_error", "wechat_identity_fetch_failed", singleLine(err.Error()))
        return
    }
    ...
}
// start handler
func (h *AuthHandler) WeChatOAuthStart(c *gin.Context) {
    ...
    state, err := oauth.GenerateState()
    ...
    wechatSetCookie(c, wechatOAuthStateCookieName, encodeCookieValue(state), wechatOAuthCookieMaxAgeSec, secureCookie)
    ...
    c.Redirect(http.StatusFound, authURL)
}

Доказательства:

  • backend/internal/server/routes/auth.go:27-28 размещает эти маршруты в публичной группе маршрутизатора /auth.
  • backend/internal/server/routes/auth.go:73 регистрирует auth.GET("/oauth/wechat/start", h.Auth.WeChatOAuthStart).
  • backend/internal/server/routes/auth.go:80 регистрирует auth.GET("/oauth/wechat/callback", h.Auth.WeChatOAuthCallback).
  • backend/internal/handler/auth_wechat_oauth.go:160-162 считывает code и state из HTTP-запроса.
  • backend/internal/handler/auth_wechat_oauth.go:206 вызывает fetchWeChatOAuthIdentity(c.Request.Context(), cfg, code).
  • backend/internal/handler/auth_wechat_oauth.go:105-147 показывает обычный этап предварительной обработки, который устанавливает cookie состояния и перенаправляет браузер в поток OAuth.

Анализ: Это рабочий производственный код, доступный через публичный GET-обратный вызов. Cookie состояния обеспечивает защиту от OAuth-CSRF, но не ограничивает размер HTTP-ответа, который поступает ниже по потоку после обмена токена. Затем были прослежены внутренняя цепочка вызовов и все производственные вызывающие объекты места сбоя.

Шаг 3: Прослеживание всех производственных вызывающих объектов в exchangeWeChatOAuthCode()

Была прослежена внутренняя цепочка вызовов между обработчиком и вспомогательными функциями. Основной обратный вызов достигает места сбоя через вспомогательную функцию (fetchWeChatOAuthIdentity), в то время как платёжный обратный вызов достигает того же места сбоя напрямую.

func fetchWeChatOAuthIdentity(ctx context.Context, cfg wechatOAuthConfig, code string) (*wechatOAuthTokenResponse, *wechatOAuthUserInfoResponse, error) {
    tokenResp, err := exchangeWeChatOAuthCode(ctx, cfg, code)
    if err != nil {
        return nil, nil, err
    }
    userInfo, err := fetchWeChatUserInfo(ctx, tokenResp)
    ...
}
cfg, err := h.getWeChatOAuthConfig(c.Request.Context(), "mp", c)
...
cfg.redirectURI = h.resolveWeChatPaymentOAuthCallbackURL(c.Request.Context(), c)
tokenResp, err := exchangeWeChatOAuthCode(c.Request.Context(), cfg, code)
if err != nil {
    redirectOAuthError(c, frontendCallback, "token_exchange_failed", "failed to exchange oauth code", err.Error())
    return
}

Доказательства:

  • backend/internal/handler/auth_wechat_oauth.go:1112-1117 показывает, что fetchWeChatOAuthIdentity() вызывает exchangeWeChatOAuthCode(), а затем fetchWeChatUserInfo().
  • backend/internal/handler/auth_wechat_oauth.go:206 — это место, где основной обратный вызов OAuth вызывает fetchWeChatOAuthIdentity().
  • backend/internal/handler/auth_wechat_oauth.go:438 — это место, где платёжный обратный вызов OAuth вызывает exchangeWeChatOAuthCode() напрямую.

Анализ: Отмеченное место сбоя не является мёртвым кодом. Поиск вызывающих объектов по всему проекту выявляет два производственных пути входа в одну и ту же вспомогательную функцию: стандартный обратный вызов входа/привязки WeChat и платёжный обратный вызов WeChat. Затем были проверены любые санитайзеры, валидаторы или защитные механизмы размера на уровне фреймворка, присутствующие на этом пути ответа.

Шаг 4: Проверка ограничений размера и существующих шаблонов безопасности в кодовой базе

Была выполнена проверка кодовой базы на предмет шаблонов ограничения размера тела ответа, а также проверена общая вспомогательная функция, уже используемая в других местах для ограниченного чтения вышестоящих данных. Эта вспомогательная функция использует io.LimitReader(..., maxBytes+1) и явно сообщает об ошибке при превышении лимита, но код WeChat OAuth её не использует.

func readUpstreamResponseBodyLimited(reader io.Reader, maxBytes int64) ([]byte, error) {
    ...
    body, err := io.ReadAll(io.LimitReader(reader, maxBytes+1))
    if err != nil {
        return nil, err
    }
    if int64(len(body)) > maxBytes {
        return nil, fmt.Errorf("%w: limit=%d", ErrUpstreamResponseBodyTooLarge, maxBytes)
    }
    return body, nil
}
// DefaultUpstreamResponseReadMaxBytes is the default read cap for upstream non-streaming response bodies.
const DefaultUpstreamResponseReadMaxBytes int64 = 128 * 1024 * 1024
Скачать инструмент