[DreamHack] PIE, RELRO, Out of Bounds Keywords && Quiz
Position Independent Executable (PIE)
상대 참조(Relative Addressing): 어떤 값을 기준으로 다른 주소를 지정하는 방식
Position Independent Code (PIC): 어떤 주소에 매핑되어도 실행 가능한 코드. 절대 주소를 사용하지 않으며 일반적으로 rip를 기준으로 한 상대 주소를 사용함.
Position Independent Executable (PIE): 어떤 주소에 매핑되어도 실행 가능한 실행 파일. PIE의 코드는 모두 PIC이다. 자체적으로 보호 기법은 아니지만 ASLR이 적용된 환경에서는 시스템을 더욱 안전하게 만드는 효과가 있음. 최신 gcc는 기본적으로 PIE 컴파일을 함.
Partial Overwrite: 어떤 값을 일부분만 덮는 공격 방법. PIE를 우회하기 위해 사용될 수 있음.
quiz : PIE
Q1. 다음은 file 명령어로 바이너리를 확인한 모습이다. PIE가 적용된 바이너리는 무엇인가? 답을 선택하고 확인을 눌러주세요.
/bin/ls: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=2f15ad836be3339dec0e2e6a3c637e08e48aacbd, for GNU/Linux 3.2.0, stripped
/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=96b5dec8ab42c48cec65f2ba3a3e0b133869b42a, for GNU/Linux 3.2.0, stripped
A1. PIE (Position Independent Executable) 적용 여부는 바이너리의 설명에서 "shared object"라는 표현으로 확인할 수 있는데, 이건 해당 바이너리가 주소 재배치가 가능하도록 설계되었음을 의미함
- /bin/ls: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=2f15ad836be3339dec0e2e6a3c637e08e48aacbd, for GNU/Linux 3.2.0, stripped
이 설명에서 "shared object"가 포함되어 있어 PIE가 적용된 바이너리임을 알 수 있다.
Q2. ASLR을 꺼도 PIE가 적용된 프로세스는 무작위 주소에 매핑된다. O X
A2.X
PIE는 ASLR와 결합되어 프로세스를 무작위 주소에 매핑한다. 그러나 ASLR이 비활성화된 경우에는 PIE가 적용되었더라도, 프로세스가 고정된 주소에 매핑된다. 따라서 ASLR이 꺼진 상태에서는 무작위 매핑이 이루어지지 않는다.
Shared Object는 동적으로 로드되어 실행 파일이 사용하는 라이브러리로 설계되었지만, 리눅스에서 ld-linux와 같은 동적 링커(dynamic linker)를 사용하여 직접 실행할 수 있다.
RELRO 보호 기법
RELocation Read-Only(RELRO): 불필요한 데이터 영역에 쓰기 권한을 제거함.
Partial RELRO: init array, fini array 등 여러 섹션에 쓰기 권한을 제거함. Lazy binding을 사용하므로 라이브러리 함수들의 GOT 엔트리는 쓰기가 가능함. GOT Overwrite등의 공격으로 우회가 가능함.
Full RELRO: init array, fini array 뿐만 아니라 GOT에도 쓰기 권한을 제거함. Lazy binding을 사용하지 않으며 라이브러리 함수들의 주소는 바이너리가 로드되는 시점에 바인딩됨. libc의 malloc hook, free hook과 같은 함수 포인터를 조작하는 공격으로 우회할 수 있음.
quiz : RELRO
Q1. Full RELRO에서는 .got 영역을 조작하여 실행 흐름을 조작할 수 있다.
A1 : X
.bss, .data 영역에만 쓰기 권한이 남아있다.
Q2. No RELRO는 어떠한 RELRO 보호기법도 적용되지 않는 상태를 의미한다.
A2 : O
Q3. Partial RELRO에서는 .fini_array를 조작하여 실행 흐름을 조작할 수 있다.
A3 : X
.bss, .data, .got.plt 영역에만 쓰기 권한이 남아있다.
Q4. RELRO는 RELocation Read-Only의 줄임말이다.
A4 : O
out of bounds 취약점
배열의 범위를 벗어난 메모리에 접근할 수 있는 취약점. 개발자가 인덱스에 대한 검사를 제대로 하지 않으면 발생함. 임의 주소 읽기, 임의 주소 쓰기로 이어질 수 있음.
Quiz: Out of Bounds
Q1. OOB 취약점을 방어하기 위해 [A] 위치에 들어갈 올바른 검증 코드는? #include <stdio.h> int main() { int buf[0x10]; unsigned int index; scanf("%d", &index); [A] printf("%d\n", buf[index]); return 0; } 답을 선택하고 확인을 눌러주세요.
if (index < 0x10) {exit(-1);}
if (index > 0x10) {exit(-1);}
if (index <= 0x10) {exit(-1);}
if (index >= 0x10) {exit(-1);}
A1. if (index >= 0x10) {exit(-1);}
이유는 배열 buf의 크기가 0x10(16)이므로, 유효한 인덱스 범위는 0부터 15이다. 즉, index가 16 이상인 경우에는 배열의 범위를 초과하는 OOB 취약점이 터진다.
그러므로 인덱스가 0x10 이상일 때 프로그램을 종료해야 한다.