Pwnable/Dreamhack

[Dreamhack] Background: RELRO

와븨 2022. 11. 7. 00:12

Lazy binding을 하는 바이너리는 실행 중에 GOT 테이블을 업데이트할 수 있어야 하므로 GOT에 쓰기 권한이 부여된다. 그런데 이는 바이너리를 취약하게 만드는 원인이 된다.

또한, ELF의 데이터 세그먼트에는 프로세스의 초기화 및 종료와 관련된 .init_array, .fini_array가 있다. 이 영역들은 프로세스의 시작과 종료에 실행할 함수들의 주소를 저장하고 있는데, 여기에 공격자가 임의로 값을 쓸 수 있다면, 프로세스의 실행 흐름이 조작될 수 있다.

=> RELocation Read-Only(RELRO) 개발

 

RELRO

: 쓰기 권한이 불필요한 데이터 세그먼트에 쓰기 권한을 제거한다.

 

Partial RELRO 권한

prelro를 실행해보면 0x601000부터 0x602000까지의 주소에는 쓰기 권한이 있는 것을 확인할 수 있습니다. 오른쪽의 섹션 헤더를 참조해보면 해당 영역에는 .got.plt, .data, .bss가 할당되어 있다.

=> 이 섹션들에는 쓰기가 가능하다.

 

반면, .init_array와 .fini_array는 각각 0x600e10과 0x600e18에 할당되어 쓰기가 불가능하다.

 

+) .got와 .got.plt

artial RELRO가 적용된 바이너리는 got와 관련된 섹션이 .got .got.plt로 두 개가 존재합니다. 전역 변수 중에서 실행되는 시점에 바인딩(now binding)되는 변수는 .got에 위치한다. 바이너리가 실행될 때는 이미 바인딩이 완료되어있으므로 이 영역에 쓰기 권한을 부여하지 않는다.

반면, 실행 중에 바인딩(lazy binding)되는 변수는 .got.plt에 위치한다. 이 영역은 실행 중에 값이 써져야 하므로 쓰기 권한이 부여됩니다. Partial RELRO가 적용된 바이너리에서 대부분 함수들의 GOT 엔트리는 .got.plt에 저장된다.

 

FULL RELRO

frelro를 실행하여 메모리 맵을 확인하고, 이를 섹션 헤더 정보와 종합해보면 got에는 쓰기 권한이 제거되어 있으며 data와 bss에만 쓰기 권한이 있다. Full RELRO가 적용되면 라이브러리 함수들의 주소가 바이너리의 로딩 시점에 모두 바인딩된다. 따라서 GOT에는 쓰기 권한이 부여되지 않는다.

 

RELRO 기법 우회

malloc 함수의 코드를 살펴보면, 함수의 시작 부분에서 __malloc_hook이 존재하는지 검사하고, 존재하면 이를 호출한다. __malloc_hook은 libc.so에서 쓰기 가능한 영역에 위치한다. 따라서 공격자는 libc가 매핑된 주소를 알 때, 이 변수를 조작하고 malloc을 호출하여 실행 흐름을 조작할 수 있다. 이와 같은 공격 기법을 통틀어 Hook Overwrite라고 부른다.