Sechack

[시스템 해킹] 5강 - 메모리 보호기법 본문

Lecture/pwnable

[시스템 해킹] 5강 - 메모리 보호기법

Sechack 2021. 12. 12. 23:47
반응형

지난 시간에는 Return to Shellcode기법을 실습해보았습니다. 하지만 일반적인 환경에서는 다양한 보호기법들로 인해서 Return to Shellcode와 같은 단순한 공격은 거의 먹히지 않습니다.

 

이번 시간에는 우리의 exploit을 방해하는 보호기법들이 무엇이 있는지 알아보도록 하겠습니다.

 

 

NX bit

 

NX bit는 code영역을 제외한 다른 메모리 영역에서 실행권한을 빼버리는 보호기법입니다.

조금만 생각해보면 스택, 힙과 같은 데이터 저장을 위해서 존재하는 메모리 공간에 굳이 실행권한이 존재할 이유가 없습니다. 따라서 실제 실행되는 opcode가 들어가있는 code영역을 제외하고 나머지 메모리 공간에서는 실행권한을 빼버리더라도 프로그램 실행에는 지장이 없습니다.

 

 

먼저 NX bit가 걸려있지 않은 바이너리의 메모리 레이아웃을 보면

 

 

스택 영역에 rwx권한이 있는것을 확인할 수 있습니다. rwx는 읽기, 쓰기, 실행 권한이 모두 있음을 나타냅니다.

 

 

그리고 NX bit가 걸려있는 바이너리의 메모리 레이아웃을 보면

 

 

스택 영역에 rw권한이 있는것을 볼 수 있습니다. 실행 권한을 뜻하는 x가 사라졌네요.

스택에 실행권한이 존재하지 않으면 Shellcode를 넣고 Shellcode로 프로그램 흐름을 변조하더라도 Shellcode가 실행되지 않습니다. 따라서 NX bit의 등장으로 일반적인 상황에서 Return to Shellcode기법을 사용하기는 힘들어졌습니다.

NX bit가 걸려있는 바이너리에서 Shellcode를 실행시키려면 mprotect와 같은 함수를 불러서 원하는 메모리 공간에 rwx권한을 준 후에 Shellcode를 실행시키는 여러번의 chaining과정이 필요합니다.

chaining에 대해서는 ROP기법을 배울때 자세히 알게될것입니다.

 

ASLR

 

ASLR은 힙, 스택, 라이브러리 영역의 base주소를 바이너리를 실행할때마다 Randomization시켜서 고정된 주소로 메모리에 직접 접근하는 행위를 할 수 없게끔 만듭니다.

따라서 우리는 앞서 실습했던 Return to Shellcode기법을 사용하는게 더욱 어려워집니다. NX bit에 이어 스택 베이스 주소까지 매번 바뀌니까 Shellcode가 들어간 스택 주소까지 알아낼 수 없게 됩니다.

 

ASLR의 한가지 약점은 전체 메모리 주소를 Randomization시키는게 아니라 각각 메모리 영역의 base주소만 Randomization시키는것이기 때문에 base주소만 알아낸다면 해당 메모리 영역에서 원하는 주소에 base + offset으로 맘대로 접근하는게 가능해집니다.

 

따라서 특정 영역에 해당하는 메모리 주소를 하나라도 가지고 있다면 offset을 빼서 base주소를 알아내는게 가능해지고 알아낸 메모리 영역 내에서 원하는 공간에 마음대로 접근할 수 있게 됩니다.

 

프로그램에 취약점이 존재해서 메모리에 존재하는 스택 주소나 라이브러리 주소를 그대로 화면에 출력할 수 있게 된다면 ASLR을 우회할 수 있게 됩니다. 그리고 이러한 행위를 memory leak이라고 부릅니다.

memory leak역시 ROP기법을 배울때 자세히 알게될것입니다.

반응형

 

 

SSP

 

SSP(Stack Smashing Protector)는 BOF가 터지더라도 exploit으로 연계되는것을 방어하기 위해서 sfp위에 랜덤한 값을 넣어서 함수 에필로그 과정에서 해당 값의 변조 여부를 체크하는 보호기법입니다.

랜덤한 값을 Canary라고 부르는데 sfp나 ret을 덮기 위해선 어쩔수 없이 Canary값을 덮어야 합니다. 하지만 Canary값이 변조될경우에는 __stack_chk_fail함수를 호출해서 공격이 수행되기 전에 프로그램을 종료시켜버리기 때문에 BOF공격을 1차적으로 방어할 수 있습니다.

 

 

위와같이 SSP가 걸려있는 바이너리의 함수 프롤로그와 에필로그 부분을 보면

 

 

프롤로그 부분에 fs:0x28을 참조해서 Canary값을 가져와서 rbp-0x8에 저장하는것을 볼 수 있습니다.

rbp-0x8은 sfp바로 이전 주소입니다. fs:0x28에 대해서는 Master Canary에 대해서 배울때 자세히 알게될것입니다.

 

 

그리고 에필로그 부분에서는 rbp-0x8의 값과 fs:0x28의 값을 비교해서 같을 경우에만 정상적으로 리턴하고 다를 경우에는 __stack__chk_fail함수를 호출해서 프로그램을 종료시키는것을 볼 수 있습니다.

 

SSP의 등장으로 Stack Buffer Overflow의 공격은 더욱 까다로워졌지만 역시 우회방법은 존재합니다.

앞서 말한 memory leak을 내서 카나리값을 알아내거나 마스터 카나리(fs:0x28)를 원하는 값으로 덮는다던가 fork로 자식 프로세스를 사용할때 1byte씩 brute force해서 카나리 값을 알아낼수도 있습니다.

 

 

 

RELRO

 

RELRO는 프로세스의 섹션을 보호하는 기술입니다. RELRO는 3가지의 모드가 있습니다.

 

Full relro는 data, bss를 제외한 모든 섹션에서 쓰기권한을 없앱니다. 따라서 GOT Overwrite가 불가능합니다.

GOT Overwrite에 대해서는 다음 강의에서 소개할 것입니다.

 

Pertial relro일 경우에는 GOT섹션에 쓰기권한이 존재합니다. 따라서 Lazy binding과정을 거쳐서 함수 주소를 가져오고GOT Overwrite를 진행할 수 있습니다. Lazy binding에 대해서도 다음 강의에서 소개할 것입니다.

GOT Overwrite여부가 exploit에 큰 영향을 주기도 합니다.

 

No relro는 ELF기본헤더와 code영역을 제외하고는 거의 모든 섹션에 쓰기권한이 있습니다.

.init, .fini와 같은 섹션들도 덮어쓸 수 있고 exploit에 유용하게 활용될수도 있습니다.

 

 

PIE

 

PIE는 binary base주소를 Randomization시킵니다. 동작 원리는 ASLR과 유사합니다.

ASLR이 binary에 적용되었다고 생각하면 편합니다. 따라서 PIE가 적용된 바이너리는 code, data, bss등등 섹션들의 주소를 알 수 없습니다.

binary base자체가 계속 바뀌니까 code영역의 가젯(코드 조각)에 의존적인 ROP공격을 어렵게 만드는 보호기법입니다.

우회방법은 마찬가지로 memory leak을 내는게 확실합니다.

 

 

이번 시간에는 다양한 메모리 보호기법들에 대해서 알아보았습니다. 다음 시간에는 ROP기법을 이해하는데 필요한 plt, got에 대해서 알아보도록 하겠습니다.

반응형
Comments