[Protection Tech.] RELRO
System/System Hacking

[Protection Tech.] RELRO

728x90

RELRO (RELocation Read-Only)

ELF 바이너리(프로세스)의 다이나믹 섹션에 읽기 권한만을 부여해 데이터 섹션의 보안을 강화하는 보호기술

* Lazy Binding

바이너리가 실행되는 도중 함수가 처음 호출될 때 주소를 찾는 방식

ELF 바이너리에서 동적 라이브러리의 함수를 호출할 때 호출된 함수를 찾기 위해 PLT와 GOT를 사용하는데 이 때 GOT가 사용되는 방식과 같다. PLT, GOT 정리▷▶doongdangdoongdangdong.tistory.com/117?category=869864 

Lazy Binding을 하기 위해서는 프로그램이 실행되는 도중 GOT에 라이브러리 함수의 주소를 덮어써야 한다. 즉, GOT에 쓰기 권한이 있어야한다. 

 

==> RELRO가 설정되어 있는 바이너리에서는 GOT와 같은 다이나믹 섹션이 읽기 권한만 가지게 된다. 


Partial RELRO / Full RELRO

  No RELRO Partial RELRO Full RELRO
컴파일 방식 gcc -Wl,-z,norelro (++) gcc -Wl,-z,relro (++) gcc -WI,-z,relro,-z,now (++)
D.S에 BIND_NOW 포함 여부 X X O
D.S에 JMPREL 포함 여부 O O X
D.S에 PLTREL 포함 여부 O O X
D.S에 PLTRELSZ 포함 여부 O O X
RELRO에 포함된 섹션 X INIT_ARRAY,
FINI_ARRAY
INIT_ARRAY,
FINI_ARRAY,
PLT GOT
프로그램 헤더에 RELRO X(없음) O(있음) O(있음)
Lazy Binding O O X
Now Binding X X O
GOT의 쓰기 권한 O O X

(++): -o 바이너리명 소스코드.c / D.S: Dynamic Section / 컴파일할 때 위에 적힌 옵션들끼리 띄어쓰기하면 안된다.

#include <stdio.h>
#include <string.h>
 
void main(){
 
        char address[16];
        size_t *pointer;
        int count = 1;
 
        while(count != 100)
        {
                printf("----- %d -----\n",count);
                memset(address,0,16);
                printf("Input Pointer address : ");
                fgets(address,16,stdin);
 
                pointer = strtol(address,0,16);
                printf("Pointer address : %p\n",pointer);
 
                printf("Input Pointer text : ");
                fgets(pointer,16,stdin);
                printf("Pointer text : %s\n",pointer);
                count++;
        }
        scanf("%s",address);
}

△ RELRO.c

RELRO.c 소스코드를 각각 NoRELRO, PartialRELRO, FullRELRO가 적용되도록 컴파일했다.

program header & dynamic section 변화

Partial RELRO Full RELRO
'Program Header'
- Read Only 권한의 RELRO 영역이 생성된다.
- INIT_ARRAY, FINI_ARRAY 섹션이 포함된다.
>> GOT를 덮어 쓸 수 있다.
"Program Header"
- Read Only 권한의 RELRO 영역이 생성된다.
- INIT_ARRAY, FINI_ARRAY, PLTGOT 섹션이 포함된다.
"Dynamic Section"
- PLTRELSZ, PLTREL, JMPREL 섹션 제거
- BIND_NOW, FLAGS_1 섹션 추가
>> GOT를 덮어 쓸 수 없다.

$ readelf - ld 바이너리 >> program header와 dynamic section의 정보를 확인할 수 있다.

No RELRO
Partial RELRO
Full RELRO

overwrite test

No RELRO >> .got 영역을 덮어 쓸 수 있다.

No-RELRO: GOT 덮어써진다

__isoc99_scanf 함수의 주소값은 .got.plt 영역에 저장되어 있다. 이 때 .got.plt 영역(0x600c20 - 0x600c70)은 "W"(쓰기) 권한이 있는 영역에 포함되기 때문에 GOT 값을 덮어쓸 수 있다.

 

Partial RELRO >> .got.plt 영역을 덮어 쓸 수 있다.

Partial RELRO - GOT Address가 덮어써졌다

.got.plt 영역은 0x601000으로, "W"권한이 설정되어 있는 영역에 포함된다. 반면, .init_array, .fini_arrray, .jcr, .dynamic, .got 헤더가 포함된 0x600000 ~ 0x601000 영역은 r--p로, 쓰기권한은 설정되어 있지않다.

 

Full RELRO >> GOT 영역을 덮어 쓸 수 없다.

Full Relro에서는 디버거에서 __isoc99_scanf의 심볼 정보를 찾을 수 없다. 

디스어셈블 코드 - main()

0x4007fd (main+263): 0x4005f8 영역을 호출한다.

0x4005f8: 0x600ff8(rip + 0x2009f6)영역에 저장된 주소로 이동한다.

rip+0x2009f6: 0x00007ffff7a784e0이 저장되어 있다.

0x00007ffff7a784e0: __isoc99_scanf 함수의 시작주소이다.

No Relro, Partial RELRO와 다르게 ".rela.plt", ".got.plt" 헤더가 존재하지 않는다.

function calls

  Partial RELRO Full RELRO
main 함수에서 ".plt" 영역의 메모리 주소 호출 ".plt.got" 영역의 메모리 주소 호출
.plt 에서 jmp QWORD PTR [-------]
[-------]는 ".got.plt" 영역으로, 이 영역에 저장된 주소로 점프
jmp QWORD PTR [-------]
[-------]는 ".got" 영역으로, 이 영역에 저장된 주소로 점프
.got.plt / .got .got.plt
동적 라이브러리의 주소가 아닌 ".plt" 영역 저장
(호출되기 전 함수들의 .got.plt에는 stub 코드가 저장되어 있다.)
.got
아무런 값도 저장되어 있지 않음
(아직 함수 호출 전이기 때문이다.)

함수 호출 시작 ".got.plt" 영역에 동적라이브러리의 함수의 시작 주소 값이 저장 ".got" 영역에 동적라이브러리의 함수 시작 주소 값이 저장
  Partial RELRO 가 적용된 바이너리는 ".got.plt" 영역이 writable하기 때문에 ".got.plt" 영역에 저장된 값을 변경할 수 있다. Full RELRO가 적용된 바이너리는 ".got" 영역이 read-only로 설정되어 있기 때문에 ".got"영역에 저장된 값을 변경할 수 없다.

Detecting RELRO

➰ Bianry

"readelf" 명령어를 이용해 해당 파일의 프로그램 헤더와 dynamic section 정보를 가져와 RELRO 설정여부를 확인할 수 있다.

No-Relro
Partial RELRO
Full RELRO

➰ Process

바이너리의 확인 방식과 비슷하다. 

"/proc/<PID>/exe" 파일에서 바이너리에서 확인했던 방식대로 찾으면 되고, 추가적으로 'Program Headers' 정보가 있는지 확인하면 된다.


www.lazenca.net/display/TEC/04.RELRO

SMALL

'System > System Hacking' 카테고리의 다른 글

FSB (Format String Bug)  (0) 2021.02.10
[Protection Tech.] Canaries(카나리), SSP  (0) 2021.01.27
[Protection Tech.] ASLR  (0) 2021.01.15
PLT, GOT  (0) 2021.01.14
[Protection Tech.] NX bit  (2) 2021.01.03