ROP(Return Oriented Programming)
ROP는 ASLR과 같은 메모리 보호기법을 우회하기 위한 공격기법으로 return이 포함된 코드 조각들인 가젯들을 이용해 system(“/bin/bash”)
를 실행하는 프로그램을 해커가 임의로 만들어서 root의 권한을 얻어내는 해킹 기법이다.
ROP 이해를 위한 예제를 준비했다.
ROP 체인으로 setresuid(0,0,0)
와 system("/bin/sh")
를 연속으로 실행하는 예제를 이해해보자.
대표적으로 자주 사용하는 pop rdi; ret
가젯과 pop rsi; pop rdx; ret
가젯을 활용한 예제다.
BOF로 스택에 가젯과 인자들을 덮어썼다는 전제로 만든 메모리 구조다.
가젯이 실행될 때마다 스택이 어떻게 바뀌는지 확인해보자.
함수가 종료되는 에필로그 과정에 돌입하면 [사진]과 같은 상태가 된다.
RET에는 pop rdi; ret
가젯 주소가 있고 해당 가젯을 실행한다.
pop rdi; ret
은 스택을 pop하고 rdi 레지스터에 저장한다.
- 스택에서 pop되는 값은
pop rdi; ret
가젯 상위에 위치한 0이다.
다음으로 pop rsi ; pop rdx ; ret
가젯을 실행하는데, 스택에서 2번 pop하고 rsi, rdx
레지스터에 저장한다.
레지스터에 저장되는 값은 pop rsi ; pop rdx ; ret
상위에 위치한 값이므로 모두 0이다.
- 즉,
rdi, rsi, rdx
에 모두 0이 저장됐다.
rdi, rsi, rdx
레지스터에 저장된 0은 setresuid()
를 실행할 때 사용할 3개의 인자다.
setresuid(0,0,0)
를 실행하고 uid를 root로 바꾼다.
다음으로 pop rdi ; ret
가젯을 실행한다. 스택에서 pop한 /bin/sh
를 rdi에 저장한다.
rdi 레지스터에 넣은 /bin/sh
는 system()
의 인자로 사용한다.
마지막으로 system()
를 호출하여 system(”/bin/sh”)
를 실행한다.
지금까지의 과정을 정리하면 다음과 같은 C 코드가 실행된 상황과 동일하다.
setresuid(0,0,0);
system("/bin/sh");
결과적으로 root 셸을 획득하게 된다.
이처럼 asm 가젯을 활용해서 원하는 명령어가 실행되도록 조작하는 공격 기법을 ROP라고 한다. ROP를 응용하면 메모리에 저장된 중요 정보를 획득하거나 임의 명령을 실행하는 등 공격자가 원하는 작업을 수행할 수 있다.