메모리 보호 기법 - PIE
PIE (Position-Independent Excutale)
2 분 소요
PIE (Position-Independent Excutale)
- ASLR 보호 기법은 바이너리가 실행될 때마다 스택, 힙, 공유 라이브러리 등이 무작위 주소에 매핑되는 보호 기법이지만 코드 영역의 주소는 무작위 주소에 매핑하지 않는다.
- PIE는 ASLR이 코드 영역에도 적용되게 하는 기술이다.
- 이 기술은 보안성 향상을 위해 도입된 것이 아니라 엄밀하게 보호 기법은 아니지만 ASLR과 맞물려 공격을 더욱 어렵게 만들었기에 여러 글이나 발표에서 보호 기법이라고 소개되기도 한다.
PIC
- 리눅스에서 ELF는 실행 파일(Excutable)과 공유 오브젝트(Shared Object, SO)로 두 가지가 존재한다.
- 실행 파일은 일반적인 바이너리 실행 파일을 의미하고, 공유 오브젝트는 libc.so.6 같은 라이브러리 파이 해당한다.
- 공유 오브젝트는 기본적으로 재배치(Relocation)이 가능하도록 설계되어 있다.
- 재배치가 가능하다는 것은 메모리의 어느 주소에 적재되어도 코드의 의미가 훼손되지 않음을 의미하는데, 컴퓨터 과학에서는 이러한 성질을 만족하는 코드를 Position-Independent Code(PIC)라고 부른다.
- gcc는 PIC 컴파일을 지원하고, 이 PIC를 지원해야 ASLR 같이 무작위 주소에 매핑되어도 실행 가능한 것이다.
PIE
- PIE는 무작위 주소에 매핑되도 실행 가능한 실행 파일을 뜻한다.
- ASLR이 도입되기 전에는 실행 파일을 무작위 주소에 매핑할 필요가 없었기 때문에, 리눅스의 실행 파일 형식은 재배치를 고려하지 않고 설계되었다.
- 이후에 ASLR이 도입되었을 때는 이미 널리 사용하던 실행 파일 형식의 호환성 문제가 있어 공유 오브젝트를 실행 파일 형식으로 사용하기로 했다.
PIE on ASLR
- PIE는 재배치가 가능하므로, ASLR이 적용된 시스템에서는 실행 파일도 무작위 주소에 적재된다.
- 반대로 ASLR이 적용되지 않은 시스템에서는 PIE가 적용된 바이너리라도 무작위 주소에 적재되지 않는다.
- 현대의 gcc는 PIE를 기본적으로 적용하므로, 모든 옵션을 제거하면 PIE가 적용된 바이너리로 컴파일 된다. (기본값)
- PIE가 적용되면 코드 영역의 주소가 매 실행마다 바뀜
PIE 우회
코드 베이스 구하기
- ASLR환경에서 PIE가 적용된 바이너리는 실행될 때마다 다른 주소에 적재된다.
- 그래서 코드 영역의 가젯을 사용하거나, 데이터 영역에 접근하려면 바이너리가 적재된 주소를 알아야 한다.
- 이 주소를 PIE 베이스, 또는 코드 베이스라고 부른다.
- 코드 베이스를 구하려면 라이브러리의 베이스 주소를 구할 때 처럼 코드 영역의 임의 주소를 읽고, 그 주소에서 오프셋을 빼야 한다.
Partial Overwrite
- 코드 베이스를 구하기 어렵다면 반환 주소의 일부 바이트만을 덮는 공격을 고려해볼 수 있다.
- 이러한 공격 방법을 Partial Overwrite라고 부른다.
- 일반적으로 함수의 반환 주소는 호출 함수(Caller)의 내부를 가리킨다. 특정 함수의 호출 관계는 정적 분석 또는 동적 분석으로 쉽게 확인할 수 있으므로, 공격자는 반환 주소를 예측할 수 있다.
- ASLR 특성 상, 코드 영역의 주소도 하위 12비트 값은 항상 똑같다. 따라서 코드 가젯의 주소가 반환 주소와 하위 한 바이트만 다르다면, 이 값만 덮어서 원하는 코드를 실행시킬 수 있다.
- 그러나 만약 두 바이트 이상이 다른 주소로 실행 흐름을 옮기고자 한다면, ASLR로 뒤섞이는 주소를 맞춰야 하므로 브루트 포싱이 필요하며, 공격이 확률에 따라 성공하게 된다.
- PIE는 자체적으로 보호 기법은 아니지만 ASLR과 맞물려서 시스템을 한 층 더 안전하게 보호하는 효과가 있다
- 이를 우회하려면 코드 베이스 주소를 구하거나, Partial Overwrite을 시도해볼 수 있다.
댓글남기기