← 목록으로

ROP (Return-Oriented Programming) 완전 정복

[Pwn] Pwnable · 작성: 2026-07-19 19:31:03 · 조회 5

ROP는 NX 때문에 새 코드를 심을 수 없을 때, 바이너리나 라이브러리에 이미 존재하는 코드 조각들을 이어 붙여서 원하는 동작을 조립하는 기법이다. ret2libc가 "이미 있는 함수 하나를 호출"하는 수준이라면, ROP는 그걸 훨씬 일반화해서 "이미 있는 코드 조각들로 사실상 원하는 프로그램을 조립"하는 수준까지 간다.

가젯(Gadget)이란

ret(리턴) 명령어로 끝나는 짧은 명령어 시퀀스를 가젯이라고 부른다.

pop rdi
ret

이 두 줄짜리 코드가 있으면: 스택 맨 위에서 값을 하나 꺼내 RDI 레지스터에 넣고(pop rdi), 그 다음 다시 스택 맨 위에 있는 값으로 점프한다(ret). 리턴 주소를 이 가젯 주소로 덮어두면, 스택에 원하는 값 → 다음 가젯 주소를 순서대로 쌓아서 마치 프로그램을 짜듯 명령어를 이어 붙일 수 있다. 이게 ROP 체인의 원리다.

ROP 체인이 실행되는 흐름

스택:  [pop_rdi 주소] [binsh 주소] [system 주소]
  1. 함수가 ret하면서 스택 맨 위의 pop_rdi 주소로 점프
  2. pop rdi; ret 실행 → RDI에 binsh 주소가 들어가고, 다시 스택 맨 위(이제 system 주소)로 점프
  3. system(RDI)system("/bin/sh")가 호출된 것과 동일한 효과

가젯을 여러 개 이어 붙이면 레지스터 여러 개를 세팅하고, 함수를 순서대로 여러 번 호출하는 것도 가능하다 — 이론적으로는 튜링 완전(Turing-complete)한 계산도 ROP만으로 할 수 있다는 게 알려져 있다.

가젯 찾기

ROPgadget --binary ./vuln | grep "pop rdi"
# 또는
ropper --file ./vuln --search "pop rdi"

바이너리 자체에 필요한 가젯이 부족하면 libc처럼 항상 로드되는 큰 라이브러리에서 찾는다. libc는 코드 양이 많아서 대부분의 원하는 가젯을 찾을 수 있다.

execve로 확장: ret2syscall

system()이 없거나 막혀 있을 때는, libc 함수 대신 시스템 콜을 직접 호출하는 syscall 가젯을 이용해서 execve("/bin/sh", NULL, NULL)을 직접 만드는 방법도 있다. RAX에 시스템콜 번호(execve는 59), RDI/RSI/RDX에 각각 인자를 채우고 syscall 가젯으로 점프시킨다.

pwntools의 ROP 자동화

from pwn import *

elf = context.binary = ELF('./vuln')
rop = ROP(elf)
rop.system(next(elf.search(b'/bin/sh')))

payload = b'A' * offset + rop.chain()

ROP 클래스는 필요한 가젯을 자동으로 찾아서 체인을 만들어준다. 처음엔 손으로 한 번씩 짜보면서 원리를 익히고, 익숙해지면 이렇게 자동화 도구로 넘어가는 순서를 권한다.

Pwnable 카테고리의 글 (7/14)

  1. 메모리 구조 기초: 스택, 힙, 레지스터부터 이해하기
  2. 스택 버퍼 오버플로우: 가장 기본적인 메모리 손상 공격
  3. Format String 취약점: printf가 위험해지는 순간
  4. Stack Canary: 원리와 우회 방법
  5. NX/DEP 우회와 Return-to-libc
  6. ASLR과 정보 유출(Leak)
  7. ROP (Return-Oriented Programming) 완전 정복
  8. 힙 익스플로잇 기초: Use-After-Free와 Double Free
  9. pwntools 실전 활용법
  10. UDF(User-Defined Function) 기반 DB 권한 상승: 원리부터 실전까지
  11. Pass-the-Hash / Pass-the-Ticket: 원리와 실전
  12. eBPF 기반 지속성(Persistence) 기법
  13. Full RELRO 환경에서의 GOT Overwrite와 우회
  14. ret2dlresolve: 심볼 정보 없이 임의 함수 호출하기
← ASLR과 정보 유출(Leak) 힙 익스플로잇 기초: Use-After-Free와 Double Free →