1. Return-Oriented Programming
- 기본적인 ret2libc 공격에서는 단순히 system()함수와 exit() 함수를 연결하여 2개의 함수만 chain 형태로 호출 하는 방식
- 공격자가 system() 함수를 필요로 하지만, 대상 라이브러리에 해당 함수가 존재하지 않는 경우에는 system() 대신 fork() -> execve()와 같이 다른 libc 함수 조합을 활용하는 우회가 가능하다.
- 코드 조각(code gadget)단위로 무제한 연결할 수 있는 기법을 제한하였다. => 이러한 코드 조각들은 일반적으로 명령어들의 끝이 ret으로 끝나는 짧은 코드들이다.
2. Return to functions
/*stack2.c*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void a_fun(void){
system("/bin/sh");
}
void b_fun(void){
printf("I am in b_fun()\n");
}
void c_fun(void){
printf("I am in c_fun()\n");
}
int vul_func(char *str){
char buff[10];
strcpy(buff,str);
return 1;
}
int main (int argc, char **argv)
{
char str[100];
vul_func(argv[1]);
printf("returned properly\n");
return 1;
}

- 컴파일을 한다.
- gcc -m32 -fno-stack-protector -z execstack -no-pie -o stack2_32 stack2.c
- pie와 ASLR , stack canary모두 꺼줘야한다.

- 지역변수 자리에 20byte를 할당함 => 패딩을 제공하고 있음.
- 실제 배열은 0x12 => 즉 18byte위치해있다.
- Buff (18B) + Previous FP(4B) = 22B 후 RET

- 사진을 보면 22B후 eee를 입력 => return address에 0x00656565가 들어간것을 확인할 수 있다.

- 마찬가지로 'aaab'가 리틀 엔디안으로 들어가 return address와 eip가 바뀐것을 확인할 수 있다.

- buf크기를 넘지 않으면 프로그램이 정상 종료된다.

- (geb) p를 사용하여 exit, getpid, system의 상세 주소를 알게 되었다.
- exit address => 0xf7dc35b0 , getpid address => 0xf7e6a630 , system => 0xf7dd48e0

- objdump -d 출력에서 왼쪽에 보이는 숫자는 실행 파일 내부에서 함수가 배치된 위치를 의미한다.
- 실행 파일 내부에서 함수가 몇번 째 바이트에 있는지를 나타낸다.
- 08049186 <a_fun>
- 080491b1 <b_fun>
- 080491dc <c_fun>
- 08049207 <vul_func>
- 현재 exit를 쓸 수 없어서 공격을 완벽하게 감추는 것에 한계가 있다. => 어떻게 만들 수 있을 까?
2. Return Oriented Programming (ROP)
- 공격자가 system () 함수를 수행하고 싶다고 가정하자
- 이때 문제 발생 => libc에 system()이 존재하지 않는다면 ?
int system(const char *command) {
pid = fork();
if (pid == 0) execve(...);
}
- ROP은 쉘코드 주입 X , system 함수 호출 필요 X, 기존 코드 변조 X
- 그러나 여전히 스택의 내용은 변조 또는 조작되어야한다.
- 접근 방식
- 전체 함수를 사용하는 대신 , libc 등에서 추출한 짧은 명령어 시퀸스를 이용한다.
- 이러한 명령어 시퀸스는 일반적으로 2~5개로 구성
- 모든 시퀸스는 ret 명령어로 종료된다
- 이러한 짧은 명령어 시퀸스를 연결하여 가젯을 구성한다
- 각 가젯은 다음과 같은 특정 작업을 수행한다. => load, store, xor, branch 등
- 이후 공격자는 이러한 가젯들을 조합함으로써 자신이 원하는 동작을 강제한다.
- 명령어 시퀸스 : ret 명령어로 끝나는 일련의 명령어 집합을 의미한다.
- 가젯 : 여러 개의 명령어 시퀸스로 구성된 논리적 단위
3. 의도되지 않은 순차 명령어들
b8 04 00 00 00 c3
- mov eax 0x4라는 의미를 가지고 있음
- c3은 리턴
- 이때 공격자가 중간 주소로 점프한다고 가정해보자 (CPU가 세번쨰 바이트에서 명령어 해석을 시작)
[00] 00 00 c3
- add [eax], al
- add bl, al
- ret
- 이 코드는 프로그래머가 전혀 의도하지 않은 명령이지만, 공격자는 이를 ROP 가젯으로 악용할 수 있다.
- 이런 현상이 가능한 이유는 x86 명령어는 길이가 1바이트부터 15바이트까지 모두 가능하다. => 중간에서 시작하면 새로운 조합이 생성됨
- 또한 메모리 정렬을 강제하지 않기 때문에 임의 주소에서 명령을 읽기 시작할 수 있다.
3. CISC와 RISC에서의 ROP 가젯 생성 가능성 차이
- CISC 구조에서는 명령어 길이가 가변적으로 구성되기 때문에, 공격자가 이를 ROP 명령어 해석에 활용할 수 있어 ROP 공격에 유리한 환경이 형성된다.