System Hacking - PIE & RELRO
PIE와 RELRO의 기본적인 이해
PIE (Position-Independent Executable)
ASLR을 떠올려보자. ASLR 보호 기법이 적용되면 스택, 힙, 라이브러리 영역의 메모리 주소가 변하지만 코드영역과 데이터영역은 고정 주소였다.
그래서 ROP로 임의의 익스플로잇 전략을 짤 때, 코드가젯의 주소는 변하지 않았으므로 미리 고정된 가젯의 주소를 알고 코드를 짜기도 했다.
PIE는 엄밀히는 보호기법은 아니지만, ASLR이 코드영역에도 적용될 수 있게하는 결과를 내놓는다. 즉, 보호기법으로써 해석하는 PIE는 ASLR을 코드영역까지 확장하는 Extension과 같은 느낌이다. 그래서 PIE가 적용되어있지만 ASLR이 적용되어 있지 않은 바이너리는 그 효력을 잃는다.
PIC
ELF는 실행 파일(Executable)과 공유 오브젝트(Shared Object, so)로 두가지 존재한다. so는 기본적으로 Relocation이 가능하도록 설계되었는데, 재배치가 가능하다는 것은 메모리의 어느 주소에 적재되어도 코드의 의미가 훼손되지 않음을 의미한다. 이런 성질을 만족하는 코드를 PIC(Position-Independent Code)라 부른다.
PIC는 데이터를 상대 참조(Relative Addressing)함으로서 위 성질을 만족할 수 있다.
PIE bypass : Partial Overwrite
ROP에서 라이브러리의 베이스 주소를 구하는것 처럼, 코드베이스를 구할수 있다면 PIE는 쉽게 파홰된다. 그러나 코드베이스를 구하기 어려운상황이 있다면, 다른 방법을 사용해야한다.
PIE가 적용 되어 있을지라도 바이너리에서 임의 함수들의 호출관계를 파악하는건 쉽게 확인할 수 있다.
또, ASLR의 특성 상, 코드영역의 주소도 하위 12비트 값은 항상 같다. 따라서, 사용하려는 코드 가젯의 주소가 반환 주소와 하위 1바이트(8bit)만 다르다면, 이 값만 바꿔서 원하는 코드를 실행 시킬 수 있다.
이렇게, 반환 주소의 일부분반 수정하는 전략을 Partial Overwrite이라 부른다.
RELRO (RELocation Read-Only)
Resolve를 통해서 GOT엔트리의 함수 주소를 갱신하는것과 같이, Lazy Binding을 하기 위해서 GOT에 쓰기 권한이 필요하다. 그런데, GOT에 쓰기 권한이 있으면 GOT overwrite에 취약하다.
GOT뿐만 아니라, .init_array, .fini_array도 Data Segment에 저장되어있는데, 이 영역들은 프로세스의 시작과 종료에 실행할 함수의 주소를 저장하고 있다. 만약 이 영역들에 쓰기 권한이 있다면, GOT overwrite와 비슷한 원리로, 다른 함수의 주소로 덮어서 공격할 수 있을것이다.
이러한 문제를 해결하기 위한 보호 기법이 RELRO이다. RELRO는 불필요하게 쓰기 권한이 부여된 Data Segment 영역에서 쓰기 권한을 제거한다. 이를 적용하는 범위에 따라서 Partial RELRO와 Full RELRO로 나뉜다.
Partial RELRO
.got.plt, .data, .bss : rw-
.init_array, .fini_array : r--
.got와.got.pltPartial RELRO가 적용된 바이너리는 got에 대한 섹션이
.got와.got.plt두개가 존재한다.now binding되는 변수는.got에 위치하고 쓰기 권한이 없다.
Lazy Binding되는 변수는.got.plt에 위치하고 이 영역에는 쓰기 권한이 부여된다.how plt & got works를 공부하면서 알아본 바로는,
.gotsection에__libc_start_main()주소가 저장되어있고,.got.pltsection에는.dynamicsection 주소,.link_map주소,_dl_runtime_resolve_xsavec()주소와 실제 함수의 주소가 담기는 GOT테이블이 위치한다.
Full RELRO
.data, .bss : rw-
.got : r--
.got.plt not exits
got영역에 쓰기 권한이 없으므로 GOT Overwrite 활용이 어렵다. GOT엔트리와 비슷하게, 어떤 흐름상 반드시 참조되면서 쓰기 권한이 있는 함수 포인터가 있으면 GOT Overwrite와 동일한로 원리로 공격 가능할 것이다.
Partial RELRO bypass : GOT overwrite
이전에 공부한 GOT overwrite 기법으로 Partial RELRO를 우회할 수 있다.
Full RELRO bypass : Hook Overwrite
libc의 malloc hook, free hook과 같은 함수 포인터를 조작하는 공격으로 우회할 수 있음.