Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Einreichen
ToolsExploitsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

FeedsKontaktDatenschutz© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
Tools/GitHubGitHub/renio-wow/cve-2026-51416
Statische AnalyseSchwachstellenanalyseCode-AnalyseWebsicherheit
GitHubrenio-wow/cve-2026-51416

CVE-2026-51416

Analysiert eine spezifische CVE im WeChat-OAuth-Handler, identifiziert unbegrenzte HTTP-Antwortlesevorgänge, die zu einem Denial of Service führen, mit Anleitung zur Behebung.

Repository anzeigen
14vor 5 MonatenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

1. Zusammenfassung

  • Schwachstellentyp: Denial of Service / Unbegrenztes Lesen von HTTP-Antworten ([CWE-400])
  • Markierte Stelle: backend/internal/handler/auth_wechat_oauth.go:1149
  • Beschreibung der Schwachstelle: Der WeChat-OAuth-Token-Austauschprozess verwendet io.ReadAll(resp.Body), um den vollständigen Upstream-HTTP-Antworttext in den Speicher zu lesen, ohne vor dem Puffern eine maximale Größenbeschränkung durchzusetzen.

2. Analyse

Schritt 1: Untersuchung der markierten Senke bei backend/internal/handler/auth_wechat_oauth.go:1124

Die markierte Funktion und mehr als 50 Zeilen umgebenden Kontexts wurden überprüft. Die Senke ist der Token-Austausch-Helfer exchangeWeChatOAuthCode(). Diese Funktion erstellt eine GET-Anfrage an WeChat, sendet sie mit einem einfachen http.Client und liest dann den gesamten Antworttext mit 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)
    }
    ...
}

Belege:

  • backend/internal/handler/auth_wechat_oauth.go:1142 erstellt client := &http.Client{Timeout: 30 * time.Second}.
  • backend/internal/handler/auth_wechat_oauth.go:1149 führt body, err := io.ReadAll(resp.Body) aus.
  • Vor dem Puffern des Antworttexts ist kein io.LimitReader, keine ContentLength-Prüfung und kein Aufruf einer Hilfsfunktion vorhanden.

Analyse: Der einzige Schutz hier ist eine Zeitbegrenzung (Timeout: 30 * time.Second), keine Speicherbegrenzung. Ein entfernter Peer kann dennoch große Speicherzuweisungen auslösen, bevor EOF erreicht wird. Die Erreichbarkeit dieser Senke über Produktionsrouten wurde anschließend nachverfolgt.

Schritt 2: Nachverfolgung des Hauptanfragepfads von der öffentlichen OAuth-Callback-Route

Die Authentifizierungsrouten-Registrierung und der WeChat-OAuth-Handler wurden überprüft. Die Route ist in der öffentlichen Gruppe /auth registriert, nicht in einer JWT-geschützten Gruppe. Der Callback-Handler empfängt die vom Benutzer bereitgestellten Abfrageparameter code und state, bevor er den markierten Ablauf aufruft.

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

Belege:

  • backend/internal/server/routes/auth.go:27-28 platziert diese Routen in der öffentlichen Router-Gruppe /auth.
  • backend/internal/server/routes/auth.go:73 registriert auth.GET("/oauth/wechat/start", h.Auth.WeChatOAuthStart).
  • backend/internal/server/routes/auth.go:80 registriert auth.GET("/oauth/wechat/callback", h.Auth.WeChatOAuthCallback).
  • backend/internal/handler/auth_wechat_oauth.go:160-162 liest code und state aus der HTTP-Anfrage.
  • backend/internal/handler/auth_wechat_oauth.go:206 ruft fetchWeChatOAuthIdentity(c.Request.Context(), cfg, code) auf.
  • backend/internal/handler/auth_wechat_oauth.go:105-147 zeigt den normalen Vorverarbeitungsschritt, der ein State-Cookie setzt und den Browser in den OAuth-Ablauf umleitet.

Analyse: Dies ist produktiver Live-Code, der über einen öffentlichen GET-Callback erreichbar ist. Das State-Cookie bietet OAuth-CSRF-Schutz, begrenzt jedoch nicht die Größe der HTTP-Antwort, die nach dem Token-Austausch nachgelagert ankommt. Die interne Aufrufkette und alle Produktionsaufrufer der Senke wurden anschließend verfolgt.

Schritt 3: Nachverfolgung aller Produktionsaufrufer von exchangeWeChatOAuthCode()

Die interne Aufrufkette zwischen dem Handler und den Hilfsfunktionen wurde nachverfolgt. Der Haupt-Callback erreicht die Senke über einen Helfer (fetchWeChatOAuthIdentity), während der Zahlungs-Callback dieselbe Senke direkt erreicht.

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
}

Belege:

  • backend/internal/handler/auth_wechat_oauth.go:1112-1117 zeigt, dass fetchWeChatOAuthIdentity() exchangeWeChatOAuthCode() und dann fetchWeChatUserInfo() aufruft.
  • backend/internal/handler/auth_wechat_oauth.go:206 ist die Stelle, an der der Haupt-OAuth-Callback fetchWeChatOAuthIdentity() aufruft.
  • backend/internal/handler/auth_wechat_oauth.go:438 ist die Stelle, an der der Zahlungs-OAuth-Callback exchangeWeChatOAuthCode() direkt aufruft.

Analyse: Die markierte Senke ist kein toter Code. Eine projektweite Aufrufersuche ergibt zwei Produktionseinstiegspfade in denselben Helfer: den Standard-WeChat-Login/Bind-Callback und den WeChat-Zahlungs-Callback. Es wurde anschließend geprüft, ob auf diesem Antwortpfad Sanitizer, Validatoren oder Größenbegrenzungen auf Framework-Ebene vorhanden sind.

Schritt 4: Prüfung auf Größenbegrenzungen und vorhandene Sicherheitsmuster im Codebestand

Der Codebestand wurde nach Mustern zur Begrenzung der Antworttextgröße durchsucht, und der gemeinsam genutzte Helfer, der bereits an anderer Stelle für begrenzte Upstream-Lesevorgänge verwendet wird, wurde überprüft. Dieser Helfer verwendet io.LimitReader(..., maxBytes+1) und meldet explizit einen Fehler, wenn die Begrenzung überschritten wird, aber der WeChat-OAuth-Code verwendet ihn nicht.

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
Tool herunterladen