1. PIC (Position-Independent Code) 정의
- 리눅스에서 ELF에는 실행파일(Executable)과 공유 오브젝트(Shared Object, SO)가 존재하며, 공유 오브젝트는 libc.so와 같은 라이브러리 파일이 해당된다.
- 공유 오브젝트는 기본적으로 재배치가 가능하도록 설계되어 있는데, 이러한 성질을 만족하는 코드를 PIC라고 한다.
- gcc는 PIC 컴파일을 지원한다.
[참고] '재배치가 가능하다는 것'은 메모리의 어느 주소에 적재되어도, 코드의 의미가 훼손되지 않음을 의미한다. |
2. PIC 실습
2-1. 실습 코드
- PIC 적용된 바이너리와 적용되지 않은 바이너리 비교를 위해, 두 가지 방식으로 컴파일해준다.
// Name: pic.c
// Compile: gcc -o pic pic.c
// : gcc -o no_pic pic.c -fno-pic -no-pie
#include <stdio.h>
char *data = "Hello World!";
int main() {
printf("%s", data);
return 0;
}
2-2. PIC 실습 결과
- 두 파일에서 main함수를 비교해보면, [main + 14]에서 "%p"문자열을 printf에 전달하는 방식이 다른 것을 볼 수 있다.
- pic가 적용되지 않은 파일의 경우, 0x4005a1라는 절대 주소로 문자열을 참조하고 있다.
- pic가 적용된 파일은 문자열 주소를 [rip + 0xa2]로 참조하고 있다.
- 이를 통해 알 수 있는 점은 아래와 같다.
- pic가 적용되지 않은 파일 경우, 바이너리가 매핑되는 주소가 바뀌면 0x4005a1에 있던 데이터도 함께 이동하므로 코드를 제대로 실행하지 못한다.
- pic가 적용된 파일은 rip을 기준으로 데이터를 상대 참조하기 때문에, 바이너리가 무작위 주소에 매핑되어도 제대로 실행된다.
3. PIE (Position-Idependent Executable)
- ASLR이 코드 영역에도 적용되게 해주는 기술로, 무작위 주소에 매핑해도 실행 가능한 실행파일이다.
- ASLR이 생기기 전, 기존 실행파일은 재배치를 고려하지 않고 설계되었기 때문에, 개발자들은 원래 재배치가 가능했던 공유 오브젝트를 실행 파일로 사용하기로 한다.
- 현대의 gcc는 PIE를 기본적으로 적용하므로, 모든 옵션을 제거하면 PIE가 적용된 바이너리로 컴파일된다.
- PIE가 적용되면, main함수의 주소도 매 실행마다 바뀌게 된다.
4. PIE 우회
- 코드 베이스 구하기
- ASLR환경에서 PIE가 적용된 바이너리는 실행될 때마다 다른 주소에 적재하므로, 코드 영역의 가젯을 사용하거나 데이터 영역에 접근하려면 바이너리가 적재된 주소를 알아야 한다.
해당 주소를 "PIE 베이스" or " 코드 베이스"라고 한다. - 코드 베이스를 구하려면, 코드 영역의 임의 주소를 읽고 그 주소의 오프셋을 빼야 한다.
- ASLR환경에서 PIE가 적용된 바이너리는 실행될 때마다 다른 주소에 적재하므로, 코드 영역의 가젯을 사용하거나 데이터 영역에 접근하려면 바이너리가 적재된 주소를 알아야 한다.
- Partial Overwrite
- 코드 베이스가 구하기 어렵다면, 반환 주소의 일부 바이트만 덮는 공격을 고려해볼 수 있는데
이를 Partial Overwrite라고 한다. - Off by One이라는 취약점으로 인해, Partial Overwrite가 발생한다.
- 일반적으로 함수의 반환 주소는 호출 함수(Caller)의 내부를 가리키기 때문에,
특정 함수의 호출 관계는 정적&동적 분석으로 쉽게 확인할 수 있으므로 공격자는 반환 주소를 예측할 수 있다. - ASLR의 특성상, 코드 영역의 주소도 하위 12bit 값은 항상 같다.
따라서, 사용하려는 코드 가젯의 주소가 반환 주소와 하위 한 바이트만 다르면, 이 값만 덮어서 원하는 코드를 실행시킬 수 있다.
(단, 2byte이상 다른 주소로 실행 흐름을 옮기려면 ASLR로 섞이는 주소를 맞춰야 하므로 브로트 포싱을 해야함.)
- 코드 베이스가 구하기 어렵다면, 반환 주소의 일부 바이트만 덮는 공격을 고려해볼 수 있는데
5. 키워드 정리
상대참조 | 어떤 값을 기준으로 다른 주소를 지정하는 방식이다. |
PIC | 어떤 주소에 매핑되어도 실행 가능한 코드로, 절대 주소를 사용하지 않으며 일반적으로 rip을 기준으로 한 상대 주소를 사용한다. |
PIE | 어떤 주소에 매핑되어도 실행 가능한 실행 파일로, PIE의 코드는 모두 PIC이다. |
Partical Overwrite | 어떤 값을 일부분만 덮는 공격 방법으로, PIE를 우회하기 위해 사용된다. |
'Dreamhack > Lecture & Practice' 카테고리의 다른 글
[Lecture] OOB (Out of bounds) (0) | 2022.08.09 |
---|---|
[Practice] Hook Overwrite (0) | 2022.07.14 |
[Lecture] RELRO (RELocation Read-Only) (0) | 2022.07.11 |
[Practice] ROP - GOT Overwrite (0) | 2022.07.02 |
[Practice] Return to Library (0) | 2022.07.01 |