IT/시스템 보안

[RELRO] RELRO의 개념, RELRO의 우회

kykyky 2024. 5. 15. 16:41

RELRO란

ELF는 data segment에 있는 GOT를 활용하여 반복되는 라이브러리 함수의 호출 비용을 줄이며,

이 GOT에 값을 채우는 방식 중 Lazy Binding은   

함수가 처음 호출될 때 함수의 주소를 구하고, 이를 GOT에 적는 방식이다.

그런데 이 방식의 바이너리는 실행 중에 GOT 테이블을 업데이트할 수 있어야 하기에, GOT에 쓰기 권한이 부여가 되므로 취약하다.


한편, ELF의 data segment에는 프로세스의 초기화 및 종료에 실행할 함수들의 주소가 저장된 .init_array, .fini_array가 있는데,

여기가 조작이 가능하다면 이또한 취약하다.

이러한 문제들을 해결하고자,

데이터 세그먼트 중, 쓰기 권한이 불필요한 영역의 쓰기 권한을 제거함으로써, 해당 영역을 보호하는 RELRO(RELocation Read-Only)가 개발되었다.

 

Partial RELRO와 Full RELRO의 비교

  Partial RELRO Full RELRO
쓰기 권한 .init_array X
.fini_array X
.got X
.got.plt O
.bss O
.init_array X
.fini_array X
.got X
.bss O
binding 조금 Now binding, 대부분 Lazy binding Now binding 
gcc PIE를 해제하면 Partial RELRO를 적용 Full RELRO가 기본값

 

  Lazy binding Now binding
binding 시점 라이브러리 함수들의 주소가 실행 중에 바인딩 라이브러리 함수들이 메모리에 로딩되어 바이너리 실행이 시작되는 때 바인딩
변수들의 위치  .got.plt
ㅡ 실행 중에 값이 써져야 함
->  쓰기 권한 O
.got
ㅡ 실행될 때는 이미 바인딩이 완료됨
->  쓰기 권한 X

 

 

Partial RELRO 쓰기 권한 확인

 

objdump를 통해, 각 symbol의 주소를 확인해 보자.

 

 

 

그 다음, 프로그램을 실행하여 메모리 위치에 따른 권한을 확인해 보자. (이 프로그램은 특벌히 메모리와 그에 따른 권한을 나타내도록 만들어서 이렇게 되는 것이다.)

 

이제, 주어진 심볼 주소와 주소-권한 표를 보고, 몇몇 섹션의 쓰기 권한을 확인해 보자.

 

.init_array, .fini_array, .got의 주소 =  0x403??? -> 쓰기 권한 X
.got.plt, .data, .bss의 주소 =  0x404??? -> 쓰기 권한 O

 

Full RELRO 쓰기 권한 확인

objdump를 통해, 각 symbol의 offset을 확인해 보자.

Q. 왜 여기서는 Partial RELRO와 다르게 "주소"가 아니라 "offset"이 나타나는 것인가?

A. Partial RELRO는 PIE를 해제한 것이기 때문에, code가 ASLR되지 않는데,
Full RELRO는 기본으로 적용된 PIE를 해제하지 않고 그대로 적용한 것이기 때문에, code도 ASLR돼 있으니, "주소"가 아니라 "offset"이 나타나는 것이다.

 

 

그 다음, 프로그램을 실행하여 메모리 위치에 따른 권한을 확인해 보자. (이 프로그램은 특벌히 메모리와 그에 따른 권한을 나타내도록 만들어서 이렇게 되는 것이다.)

 

이제, 주어진 심볼 offset과 주소-권한 표를 보고, 몇몇 섹션의 쓰기 권한을 확인해 보자.

 

.init_array의 주소 = ./frelro가 매핑된 주소 + .init_array의 오프셋

= 0x558715049000 + 0x3da8

= 55871504CDA8 -> 쓰기 권한 X

 

동일한 방식으로 

.fini_array의 주소 = 0x55871504CDB0 -> 쓰기 권한 X
.got의 주소 = 0x55871504CFA8 -> 쓰기 권한 X
.data의 주소 = 0x55871504D000 -> 쓰기 권한 O
.bss의 주소 = 0x55871504D010 -> 쓰기 권한 O

 

 

RELRO 우회

 

GOT Overwrite (Partial RELRO의 경우)

 

: .got.plt 영역에 대한 쓰기 권한 O -> GOT overwrite 공격 가능

 

Hook overwrite (Full RELRO의 경우)

: 덮어쓸 수 있는 함수 포인터인 libc의 hook(eg. malloc hook, free hook)을 조작