Skip to content
KitploitKITPLOIT
OutilsExploitsBlog
Log in
Soumettre
OutilsExploitsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

FluxContactConfidentialité© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
Outils/GitHubGitHub/renio-wow/cve-2026-51416
Analyse StatiqueAnalyse des VulnérabilitésAnalyse de CodeSécurité Web
GitHubrenio-wow/cve-2026-51416

CVE-2026-51416

Analyse une CVE spécifique dans le gestionnaire OAuth de WeChat, identifiant des lectures de réponses HTTP non bornées menant à un déni de service, avec des conseils de remédiation.

Voir le dépôt
14il y a 5 moisPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

1. Résumé

  • Type de vulnérabilité : Déni de service / Lecture de réponse HTTP sans restriction ([CWE-400])
  • Emplacement signalé : backend/internal/handler/auth_wechat_oauth.go:1149
  • Description de la vulnérabilité : Le processus d'échange de jeton OAuth WeChat utilise io.ReadAll(resp.Body) pour lire l'intégralité du corps de la réponse HTTP en amont en mémoire sans imposer de limite de taille maximale avant la mise en mémoire tampon.

2. Analyse

Étape 1 : Examiner le point sensible signalé à backend/internal/handler/auth_wechat_oauth.go:1124

La fonction signalée et plus de 50 lignes de contexte environnant ont été examinées. Le point sensible est la fonction d'aide à l'échange de jeton exchangeWeChatOAuthCode(). Cette fonction construit une requête GET vers WeChat, l'envoie à l'aide d'un http.Client simple, puis lit l'intégralité du corps de la réponse avec 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)
    }
    ...
}

Preuves :

  • backend/internal/handler/auth_wechat_oauth.go:1142 crée client := &http.Client{Timeout: 30 * time.Second}.
  • backend/internal/handler/auth_wechat_oauth.go:1149 exécute body, err := io.ReadAll(resp.Body).
  • Aucun io.LimitReader, aucune vérification de ContentLength et aucun appel de fonction d'aide n'est présent avant la mise en mémoire tampon du corps de la réponse.

Analyse : La seule protection ici est une limite de temps (Timeout: 30 * time.Second), pas une limite de mémoire. Un pair distant peut toujours déclencher d'importantes allocations mémoire avant que EOF ne soit atteint. L'accessibilité de ce point sensible depuis les routes de production a ensuite été retracée.

Étape 2 : Retracer le chemin de requête principal depuis la route publique de rappel OAuth

L'enregistrement des routes d'authentification et le gestionnaire OAuth WeChat ont été examinés. La route est enregistrée sous le groupe public /auth, et non sous un groupe protégé par JWT. Le gestionnaire de rappel reçoit les paramètres de requête code et state fournis par l'utilisateur avant d'invoquer le flux signalé.

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

Preuves :

  • backend/internal/server/routes/auth.go:27-28 place ces routes dans le groupe de routeurs public /auth.
  • backend/internal/server/routes/auth.go:73 enregistre auth.GET("/oauth/wechat/start", h.Auth.WeChatOAuthStart).
  • backend/internal/server/routes/auth.go:80 enregistre auth.GET("/oauth/wechat/callback", h.Auth.WeChatOAuthCallback).
  • backend/internal/handler/auth_wechat_oauth.go:160-162 lit code et state depuis la requête HTTP.
  • backend/internal/handler/auth_wechat_oauth.go:206 appelle fetchWeChatOAuthIdentity(c.Request.Context(), cfg, code).
  • backend/internal/handler/auth_wechat_oauth.go:105-147 montre l'étape de pré-traitement normale qui définit un cookie d'état et redirige le navigateur dans le flux OAuth.

Analyse : Il s'agit de code de production actif accessible depuis un rappel GET public. Le cookie d'état fournit une protection OAuth-CSRF, mais il ne limite pas la taille de la réponse HTTP qui arrive en aval après l'échange de jeton. La chaîne d'appels interne et tous les appelants de production du point sensible ont ensuite été suivis.

Étape 3 : Retracer tous les appelants de production vers exchangeWeChatOAuthCode()

La chaîne d'appels interne entre le gestionnaire et les fonctions d'aide a été retracée. Le rappel principal atteint le point sensible via une fonction d'aide (fetchWeChatOAuthIdentity), tandis que le rappel de paiement atteint le même point sensible directement.

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
}

Preuves :

  • backend/internal/handler/auth_wechat_oauth.go:1112-1117 montre fetchWeChatOAuthIdentity() appelant exchangeWeChatOAuthCode(), puis fetchWeChatUserInfo().
  • backend/internal/handler/auth_wechat_oauth.go:206 est l'endroit où le rappel OAuth principal appelle fetchWeChatOAuthIdentity().
  • backend/internal/handler/auth_wechat_oauth.go:438 est l'endroit où le rappel OAuth de paiement appelle exchangeWeChatOAuthCode() directement.

Analyse : Le point sensible signalé n'est pas du code mort. Une recherche d'appelants à l'échelle du projet révèle deux chemins d'entrée de production vers la même fonction d'aide : le rappel standard de connexion/liaison WeChat et le rappel de paiement WeChat. Les éventuels sanitiseurs, validateurs ou gardes de taille au niveau du framework présents sur ce chemin de réponse ont ensuite été vérifiés.

Étape 4 : Vérifier les limites de taille et les modèles de sécurité existants dans la base de code

La base de code a été recherchée pour les modèles de limitation de taille du corps de réponse, et la fonction d'aide partagée déjà utilisée ailleurs pour les lectures en amont bornées a été examinée. Cette fonction d'aide utilise io.LimitReader(..., maxBytes+1) et génère une erreur explicite lorsque la limite est dépassée, mais le code OAuth WeChat ne l'utilise pas.

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
}
Télécharger l’outil