Skip to content
KitploitKITPLOIT
StrumentiExploitsBlog
Log in
Invia
StrumentiExploitsBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

FeedContattoPrivacy© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2026-51416 — Analizza una specifica CVE nel gestore OAuth di WeChat, identificando letture illimitate delle risposte HTTP che portano a denial of service, con indicazioni di rimedio. | Kitploit
Strumenti/GitHubGitHub/renio-wow/cve-2026-51416
Analisi StaticaAnalisi delle VulnerabilitàAnalisi del CodiceSicurezza Web
GitHubrenio-wow/cve-2026-51416

CVE-2026-51416

Analizza una specifica CVE nel gestore OAuth di WeChat, identificando letture illimitate delle risposte HTTP che portano a denial of service, con indicazioni di rimedio.

Vedi Repository
145 mesi faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

1. Riepilogo

  • Tipo di vulnerabilità: Denial of Service / Lettura illimitata della risposta HTTP ([CWE-400])
  • Posizione segnalata: backend/internal/handler/auth_wechat_oauth.go:1149
  • Descrizione della vulnerabilità: Il processo di scambio del token OAuth di WeChat utilizza io.ReadAll(resp.Body) per leggere l'intero corpo della risposta HTTP upstream in memoria senza imporre alcun limite massimo di dimensione prima del buffering.

2. Analisi

Passo 1: Esaminare il sink segnalato in backend/internal/handler/auth_wechat_oauth.go:1124

La funzione segnalata e oltre 50 righe di contesto circostante sono state esaminate. Il sink è l'helper di scambio token exchangeWeChatOAuthCode(). Questa funzione costruisce una richiesta GET verso WeChat, la invia utilizzando un semplice http.Client, e poi legge l'intero corpo della risposta con 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)
    }
    ...
}

Evidenza:

  • backend/internal/handler/auth_wechat_oauth.go:1142 crea client := &http.Client{Timeout: 30 * time.Second}.
  • backend/internal/handler/auth_wechat_oauth.go:1149 esegue body, err := io.ReadAll(resp.Body).
  • Nessun io.LimitReader, nessun controllo ContentLength e nessuna chiamata a funzione helper è presente prima del buffering del corpo della risposta.

Analisi: L'unica protezione qui è un limite di tempo (Timeout: 30 * time.Second), non un limite di memoria. Un peer remoto può comunque innescare grandi allocazioni di memoria prima che venga raggiunto EOF. È stata poi tracciata la raggiungibilità di questo sink dalle route di produzione.

Passo 2: Tracciare il percorso di richiesta principale dalla route pubblica di callback OAuth

Sono stati esaminati la registrazione delle route di autenticazione e l'handler OAuth di WeChat. La route è registrata nel gruppo pubblico /auth, non in un gruppo protetto da JWT. L'handler di callback riceve i parametri di query code e state forniti dall'utente prima di invocare il flusso segnalato.

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

Evidenza:

  • backend/internal/server/routes/auth.go:27-28 colloca queste route nel gruppo pubblico di router /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 legge code e state dalla richiesta HTTP.
  • backend/internal/handler/auth_wechat_oauth.go:206 chiama fetchWeChatOAuthIdentity(c.Request.Context(), cfg, code).
  • backend/internal/handler/auth_wechat_oauth.go:105-147 mostra il normale passaggio di pre-elaborazione che imposta un cookie di stato e reindirizza il browser nel flusso OAuth.

Analisi: Questo è codice di produzione attivo raggiungibile da un callback GET pubblico. Il cookie di stato fornisce protezione OAuth-CSRF, ma non limita la dimensione della risposta HTTP che arriva a valle dopo lo scambio del token. Sono stati poi seguiti la catena di chiamate interna e tutti i chiamanti di produzione del sink.

Passo 3: Tracciare tutti i chiamanti di produzione in exchangeWeChatOAuthCode()

È stata tracciata la catena di chiamate interna tra l'handler e le funzioni helper. Il callback principale raggiunge il sink tramite un helper (fetchWeChatOAuthIdentity), mentre il callback di pagamento raggiunge lo stesso sink direttamente.

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
}

Evidenza:

  • backend/internal/handler/auth_wechat_oauth.go:1112-1117 mostra fetchWeChatOAuthIdentity() che chiama exchangeWeChatOAuthCode(), poi fetchWeChatUserInfo().
  • backend/internal/handler/auth_wechat_oauth.go:206 è il punto in cui il callback OAuth principale chiama fetchWeChatOAuthIdentity().
  • backend/internal/handler/auth_wechat_oauth.go:438 è il punto in cui il callback OAuth di pagamento chiama exchangeWeChatOAuthCode() direttamente.

Analisi: Il sink segnalato non è codice morto. Una ricerca dei chiamanti a livello di progetto risolve due percorsi di ingresso di produzione nello stesso helper: il callback standard di login/collegamento WeChat e il callback di pagamento WeChat. Sono stati poi verificati eventuali sanitizer, validatori o guardie di dimensione a livello di framework presenti su questo percorso di risposta.

Passo 4: Verificare i limiti di dimensione e i pattern di sicurezza esistenti nel codebase

Il codebase è stato cercato per pattern di limitazione della dimensione del corpo della risposta, ed è stato esaminato l'helper condiviso già utilizzato altrove per letture upstream limitate. Tale helper utilizza io.LimitReader(..., maxBytes+1) e genera un errore esplicitamente quando il limite viene superato, ma il codice OAuth di WeChat non lo utilizza.

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
Scarica lo strumento