Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
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.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
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. | Kitploit
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
vor 4 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)
root@kitploit:~
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.

root@kitploit:~
// 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)
root@kitploit:~
// 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
    }
    ...
}
root@kitploit:~
// 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.

root@kitploit:~
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)
    ...
}
root@kitploit:~
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.

root@kitploit:~
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
}
root@kitploit:~
// DefaultUpstreamResponseReadMaxBytes is the default read cap for upstream non-streaming response bodies.
const DefaultUpstreamResponseReadMaxBytes int64 = 128 * 1024 * 1024
root@kitploit:~
raw, _ := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
...
raw, _ := io.ReadAll(io.LimitReader(resp.Body, 5<<20))

Belege:

  • backend/internal/service/upstream_response_limit.go:26-40 definiert readUpstreamResponseBodyLimited() mit io.LimitReader(reader, maxBytes+1).
  • backend/internal/service/upstream_response_limit.go:49-61 definiert ReadUpstreamResponseBody() als gemeinsamen Wrapper für begrenzte Lesevorgänge.
  • backend/internal/config/config.go:55-58 definiert DefaultUpstreamResponseReadMaxBytes.
  • backend/internal/service/crs_sync_service.go:1166 verwendet io.ReadAll(io.LimitReader(resp.Body, 1<<20)), um eine Upstream-Antwort zu lesen.
  • backend/internal/service/crs_sync_service.go:1201 verwendet io.ReadAll(io.LimitReader(resp.Body, 5<<20)) für eine andere Upstream-Antwort.
  • Im Gegensatz dazu verwendet backend/internal/handler/auth_wechat_oauth.go:1149 weiterhin ein rohes io.ReadAll(resp.Body).

Analyse: Das Projekt hat bereits erkannt, dass die Größe von Upstream-Antworttexten begrenzt werden muss, und sowohl Ad-hoc- als auch gemeinsam genutzte Begrenzungsimplementierungen sind im Einsatz. Der markierte WeChat-OAuth-Pfad umgeht diese Schutzmaßnahmen vollständig. Der entfernte Endpunkt wurde anschließend geprüft, um festzustellen, ob er fest ist und ob dies die Schlussfolgerung ändert.

Schritt 5: Überprüfung der Vertrauensgrenzen und des angrenzenden Codekontexts

Die Konstantendefinitionen und der angrenzende Code zum Abrufen von Benutzerinformationen wurden überprüft. Der OAuth-Token-Endpunkt ist fest auf WeChat codiert und nicht benutzerbereitgestellt, aber der Inhalt des Antworttexts sind dennoch entfernte Netzwerkdaten, die ohne Größenbegrenzung gelesen werden. Ein zweites unbegrenztes Upstream-Lesen existiert in derselben Datei für die Benutzerinformationsanfrage.

root@kitploit:~
var (
    wechatOAuthAccessTokenURL = "https://api.weixin.qq.com/sns/oauth2/access_token"
    wechatOAuthUserInfoURL    = "https://api.weixin.qq.com/sns/userinfo"
)
root@kitploit:~
body, err := io.ReadAll(resp.Body)
if err != nil {
    return nil, fmt.Errorf("read wechat userinfo response: %w", err)
}
root@kitploit:~
for _, suffix := range []string{
    "/auth/oauth/linuxdo/callback",
    "/auth/oauth/wechat/callback",
    "/auth/oauth/wechat/payment/callback",
    ...
} {
    if strings.HasSuffix(path, suffix) {
        return true
    }
}

Belege:

  • backend/internal/handler/auth_wechat_oauth.go:52-54 codiert Upstream-Endpunkte fest auf WeChat-URLs.
  • backend/internal/handler/auth_wechat_oauth.go:1197 führt ein zweites unbegrenztes io.ReadAll(resp.Body) innerhalb von fetchWeChatUserInfo() aus.
  • backend/internal/server/middleware/backend_mode_guard.go:38-55 erlaubt /auth/oauth/wechat/callback und /auth/oauth/wechat/payment/callback ausdrücklich, auch wenn der Backend-Modus aktiviert ist.

Analyse: Der feste WeChat-Hostname reduziert die Kontrolle eines Angreifers über die Endpunktauswahl, fügt jedoch keine Begrenzung der Antwortgröße hinzu. Die Schwachstelle bleibt bestehen, da die Anwendung beliebige entfernte Antwortbytes ohne Obergrenze in den Speicher puffert. Dies ist Produktions-Handler-Code, kein Test-, Demo- oder toter Code.

Entscheidungspfad

  • F1: Führt der Code ein unbegrenztes Lesen von entfernt bereitgestellten Daten durch? → Ja. exchangeWeChatOAuthCode() sendet eine ausgehende HTTP-Anfrage und ruft dann io.ReadAll(resp.Body) bei backend/internal/handler/auth_wechat_oauth.go:1142-1149 ohne Größenbegrenzung auf.
  • F2: Ist die Senke über einen echten Produktionsanfragepfad erreichbar? → Ja. backend/internal/server/routes/auth.go:73 und backend/internal/server/routes/auth.go:80 registrieren die öffentlichen WeChat-Start-/Callback-Routen, und backend/internal/handler/auth_wechat_oauth.go:206 leitet den Callback-Ablauf durch fetchWeChatOAuthIdentity().
  • F3: Gibt es Sanitizer, Validatoren oder Framework-/Hilfsfunktionen, die vor dem Lesen eine maximale Antworttextgröße durchsetzen? → Nein. Der gemeinsame Begrenzungshelfer existiert bei backend/internal/service/upstream_response_limit.go:26-40, und andere Dienste verwenden io.LimitReader bei backend/internal/service/crs_sync_service.go:1166 und backend/internal/service/crs_sync_service.go:1201, aber die markierte Funktion verwendet keinen davon.
  • F4: Ist der Code tot, nur für Tests oder anderweitig von der Produktion ausgeschlossen? → Nein. Der Code befindet sich in der Produktions-Handlerdatei backend/internal/handler/auth_wechat_oauth.go, ist bei backend/internal/server/routes/auth.go:73-82 registriert, und die Backend-Modus-Middleware erlaubt die Callback-Pfade weiterhin bei backend/internal/server/middleware/backend_mode_guard.go:38-55.
  • → Echtes Positiv

3. Fazit

Echte Schwachstelle

Wichtigste Belege:

  • backend/internal/handler/auth_wechat_oauth.go:1149 verwendet body, err := io.ReadAll(resp.Body), um die vollständige Upstream-Token-Antwort zu lesen, nachdem nur ein Timeout festgelegt wurde — keine Größenbegrenzung.
  • backend/internal/server/routes/auth.go:73-82 legt /oauth/wechat/callback und /oauth/wechat/payment/callback offen, und beide Routen erreichen den markierten Helfer über backend/internal/handler/auth_wechat_oauth.go:206 und backend/internal/handler/auth_wechat_oauth.go:438.
  • backend/internal/service/upstream_response_limit.go:26-40 und backend/internal/service/crs_sync_service.go:1166 zeigen, dass der Codebestand bereits io.LimitReader für begrenzte Upstream-Lesevorgänge verwendet — der WeChat-OAuth-Code tut dies schlicht nicht.

4. Behebung

  • Fügen Sie vor dem Puffern der WeChat-Token-Antwort eine explizite maximale Antworttextgröße hinzu — beispielsweise durch Umwickeln von resp.Body mit io.LimitReader(..., maxBytes+1) und Ablehnen von Texten, die die Begrenzung überschreiten.
  • Wenden Sie dieselbe Korrektur auf das angrenzende Benutzerinformations-Lesen bei backend/internal/handler/auth_wechat_oauth.go:1197 an, das dasselbe unbegrenzte Muster aufweist.
  • Bevorzugen Sie die Wiederverwendung des vorhandenen Musters für begrenzte Lesevorgänge aus backend/internal/service/upstream_response_limit.go:26-40, damit der OAuth-Ablauf konsistent mit der Art und Weise ist, wie der Rest des Codebestands Upstream-Antworten behandelt.
  • Überprüfen Sie nach der Korrektur beide Produktionsaufrufpfade erneut: den Haupt-OAuth-Callback (backend/internal/handler/auth_wechat_oauth.go:206) und den Zahlungs-Callback (backend/internal/handler/auth_wechat_oauth.go:438).
Tool herunterladen