Return Oriented Programming
- 리턴 가젯 사용하여 실행 흐름 구현
- RTL, Return to dl-resolve, GOT overwrite 등..
ROP 페이로드는 리턴 가젯으로 구성 Ret 단위로 여러 코드 연쇄적 실행 -> ROP chain이라고 한다.
// Name: rop.c
// Compile: gcc -o rop rop.c -fno-PIE -no-pie
#include <stdio.h>
#include <unistd.h>
int main() {
char buf[0x30];
setvbuf(stdin, 0, _IONBF, 0);
setvbuf(stdout, 0, _IONBF, 0);
// Leak canary
puts("[1] Leak Canary");
write(1, "Buf: ", 5);
read(0, buf, 0x100);
printf("Buf: %s\n", buf);
// Do ROP
puts("[2] Input ROP payload");
write(1, "Buf: ", 5);
read(0, buf, 0x100);
return 0;
}
위 코드 다시 보자. buf를 0x100 만큼 읽고 프린트하면 당연히 canary leak이 된다. 그리고 여기서 ROP 페이로드를 짜는 부분이 중요한데 그건 후술하자.
system 호출이 없기 때문에 우리가 가젯을 찾아서 가지고 와야 한다.
익스플로잇 설계
-
카나리 릭
-
- sytem 함수의 주소 계산
- 이 함수는 libc.so.6에 정의되어 있다. read도 이 라이브러리에 있는데, 코드에 있다는 건 어느 주소이든 간에 libc.so.6이 통째로 매핑되어 있다는 뜻이다.
직접 호출하지는 않아서 GOT 등록은 아니지만, 이 GOT 값을 읽고 오프셋을 빼면 Libc.so.6 매핑 시작 주소를 알 수 있다. 여기서 system 오프셋을 더하면 함수 호출이 가능하다.
libc 파일이 있으면 readelf 명령어로 오프셋 구하기가 가능하다.
-
- “/bin/sh”
- pwndbg에서 일단
search로 찾아본다.