Skip to content
KitploitKITPLOIT
FerramentasBlog
Log in
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

FeedsContatoPrivacidade© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2026-51416 — Analisa um CVE específico no manipulador OAuth do WeChat, identificando leituras ilimitadas de respostas HTTP que levam à negação de serviço, com orientação de remediação. | Kitploit
Ferramentas/GitHubGitHub/renio-wow/cve-2026-51416
Análise EstáticaAnálise de VulnerabilidadesAnálise de CódigoSegurança Web
GitHubrenio-wow/cve-2026-51416

CVE-2026-51416

Analisa um CVE específico no manipulador OAuth do WeChat, identificando leituras ilimitadas de respostas HTTP que levam à negação de serviço, com orientação de remediação.

Ver Repositório
14há 5 mesesAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

1. Resumo

  • Tipo de Vulnerabilidade: Negação de Serviço / Leitura Ilimitada de Resposta HTTP ([CWE-400])
  • Local Sinalizado: backend/internal/handler/auth_wechat_oauth.go:1149
  • Descrição da Vulnerabilidade: O processo de troca de token OAuth do WeChat usa io.ReadAll(resp.Body) para ler todo o corpo da resposta HTTP upstream na memória sem impor nenhum limite máximo de tamanho antes do buffer.

2. Análise

Etapa 1: Examinar o sink sinalizado em backend/internal/handler/auth_wechat_oauth.go:1124

A função sinalizada e mais de 50 linhas de contexto circundante foram revisadas. O sink é o helper de troca de token exchangeWeChatOAuthCode(). Esta função constrói uma requisição GET para o WeChat, a envia usando um http.Client simples e então lê todo o corpo da resposta com 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)
    }
    ...
}

Evidências:

  • backend/internal/handler/auth_wechat_oauth.go:1142 cria client := &http.Client{Timeout: 30 * time.Second}.
  • backend/internal/handler/auth_wechat_oauth.go:1149 executa body, err := io.ReadAll(resp.Body).
  • Nenhum io.LimitReader, nenhuma verificação de ContentLength e nenhuma chamada de função helper está presente antes do buffer do corpo da resposta.

Análise: A única proteção aqui é um limite de tempo (Timeout: 30 * time.Second), não um limite de memória. Um peer remoto ainda pode acionar grandes alocações de memória antes que o EOF seja alcançado. A acessibilidade deste sink a partir de rotas de produção foi então rastreada.

Etapa 2: Rastrear o caminho principal da requisição a partir da rota pública de callback OAuth

O registro da rota de autenticação e o handler OAuth do WeChat foram revisados. A rota está registrada no grupo público /auth, não em um grupo protegido por JWT. O handler de callback recebe os parâmetros de consulta code e state fornecidos pelo usuário antes de invocar o fluxo sinalizado.

// 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)
}

Evidências:

  • backend/internal/server/routes/auth.go:27-28 coloca essas rotas no grupo público de roteadores /auth.
  • backend/internal/server/routes/auth.go:73 registra auth.GET("/oauth/wechat/start", h.Auth.WeChatOAuthStart).
  • backend/internal/server/routes/auth.go:80 registra auth.GET("/oauth/wechat/callback", h.Auth.WeChatOAuthCallback).
  • backend/internal/handler/auth_wechat_oauth.go:160-162 lê code e state da requisição HTTP.
  • backend/internal/handler/auth_wechat_oauth.go:206 chama fetchWeChatOAuthIdentity(c.Request.Context(), cfg, code).
  • backend/internal/handler/auth_wechat_oauth.go:105-147 mostra a etapa de pré-processamento normal que define um cookie de estado e redireciona o navegador para o fluxo OAuth.

Análise: Este é código de produção ativo, acessível a partir de um callback GET público. O cookie de estado fornece proteção OAuth-CSRF, mas não limita o tamanho da resposta HTTP que chega a jusante após a troca de token. A cadeia de chamadas interna e todos os chamadores de produção do sink foram então acompanhados.

Etapa 3: Rastrear todos os chamadores de produção em exchangeWeChatOAuthCode()

A cadeia de chamadas interna entre o handler e as funções helper foi rastreada. O callback principal alcança o sink através de um helper (fetchWeChatOAuthIdentity), enquanto o callback de pagamento alcança o mesmo sink diretamente.

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
}

Evidências:

  • backend/internal/handler/auth_wechat_oauth.go:1112-1117 mostra fetchWeChatOAuthIdentity() chamando exchangeWeChatOAuthCode() e depois fetchWeChatUserInfo().
  • backend/internal/handler/auth_wechat_oauth.go:206 é onde o callback OAuth principal chama fetchWeChatOAuthIdentity().
  • backend/internal/handler/auth_wechat_oauth.go:438 é onde o callback OAuth de pagamento chama exchangeWeChatOAuthCode() diretamente.

Análise: O sink sinalizado não é código morto. Uma busca de chamadores em todo o projeto resolve dois caminhos de entrada de produção para o mesmo helper: o callback padrão de login/vínculo do WeChat e o callback de pagamento do WeChat. Quaisquer sanitizadores, validadores ou proteções de tamanho em nível de framework presentes neste caminho de resposta foram então verificados.

Etapa 4: Verificar limites de tamanho e padrões de segurança existentes no código

O código foi pesquisado por padrões de limitação de tamanho do corpo da resposta, e o helper compartilhado já usado em outros lugares para leituras upstream limitadas foi revisado. Esse helper usa io.LimitReader(..., maxBytes+1) e gera erro explicitamente quando o limite é excedido, mas o código OAuth do WeChat não o usa.

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
raw, _ := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
...
raw, _ := io.ReadAll(io.LimitReader(resp.Body, 5<<20))
Baixar ferramenta