[메모리 보호 기법] SSP +Canary (prologue) / DEP
SSP : Stack Smashing Protector ( link )
- 로컬 변수 위치 재배치
- 로컬 변수 전에 포인터 배치
- stack canary 삽입
disable
컴파일 옵션에 다음을 지정한다.
```bash
-fno-stack-protector
```
stack boundary (정렬) 설정 컴파일 옵션
```bash
-mpreferred-stack-boundary=x
```
`` x``의 기본 값은 4이고, 일반적으로 2를 준다. stack boundary는 `` 2^x``로 설정된다.
e.g.,
기본 값은 4이므로 기본 stack boundary는 `` 2^4=16`` Byte.
`` x == 2``이면 stack boundary는 `` 2^2=4`` Byte.
Canary
Prologue 직후 `` fs`` 등 segment register를 기점으로 어떤 데이터를 가져와 stack에 저장해놓게 되는데, 이 데이터가 canary가 된다.
Canary는 8byte 이상의 ``c char`` 배열이 존재하거나 string처리 함수를 호출하는 함수에만 적용되는 것이 기본 설정(`` -fstack-protector``)이고, 설정을 변경하면 모든 함수에 적용할 수 있다.
Epilogue 직전 `` fs``를 통해 접근한 원본 데이터와 stack에 저장해놓은 데이터를 `` xor`` 연산을 통해 비교하게 되는데, 결과가 0이 아니면 `` call __stack_chk_fail``하게 되어 `` SIGABRT``가 발생하게 된다.
Hex-Ray를 통해 확인해보면, segment register에 접근하는 부분이 ``c *MK_FP(seg_reg, offset)``으로 나타난다.
* `` call __stack_chk_fail``하는 부분은 나타내 주지 않으므로 참고.
* ``c *MK_FP()``는 make far pointer. segment register를 지정해서 접근할 때 사용한다.
exploit
- ``c fork()``하는 경우 canary도 parent의 것을 그대로 복사해 가져오기 때문에 항상 동일한 값을 가진다.
- 프로세스 내 모든 함수에서 canary로 사용하는 값은 같다. 따라서 어느 함수에서든 canary를 알아내기만 하면 된다.
- canary의 하위 1 byte는 ``c 0x00``으로 고정이다.
보통 이어지는 변수 출력으로 leak하는 것이 편하고, 불가능한 경우 brute force로 충분히 깰 수 있다.
하위 1 byte 부터 각 byte를 순서대로 알아내는 것이 효율적이다.
참고 : main(argv)를 쓸 때와 쓰지 않을 때의 prologue
```c
int main(int argc, char* argv[]) {
char buf[1024];
return 0;
}
gcc -o re1 re1.c -fstack-protector
0x000000000000066a <+0>: push rbp
0x000000000000066b <+1>: mov rbp,rsp
0x000000000000066e <+4>: sub rsp,0x420
// main(argv)를 적어주면 다음 두 라인이 추가된다. 안적으면 없음.
0x0000000000000675 <+11>: mov DWORD PTR [rbp-0x414],edi
0x000000000000067b <+17>: mov QWORD PTR [rbp-0x420],rsi
0x0000000000000682 <+24>: mov rax,QWORD PTR fs:0x28 // canary
0x000000000000068b <+33>: mov QWORD PTR [rbp-0x8],rax
0x000000000000068f <+37>: xor eax,eax
0x0000000000000691 <+39>: mov eax,0x0
0x0000000000000696 <+44>: mov rdx,QWORD PTR [rbp-0x8] // canary
0x000000000000069a <+48>: xor rdx,QWORD PTR fs:0x28 // canary
0x00000000000006a3 <+57>: je 0x6aa <main+64> // canary
0x00000000000006a5 <+59>: call 0x540 <__stack_chk_fail@plt> // canary
0x00000000000006aa <+64>: leave
0x00000000000006ab <+65>: ret
```
DEP : Data Execution Prevention
stack과 heap에 `` x`` permission을 빼서 stack과 heap에 삽입된 code가 실행되는 것을 막는 방법.
* NX권한(Not Executable)을 설정한다고 말하기도 한다.
Note ) NX check는 어떤 checksec을 써도 제대로 동작한다고 보장하기 어렵다. 그냥 nxtest 사용하는게 속편함.
disable
```bash
-z execstack // compile option
```
If an application attempts to run code from a protected page, the application receives an exception with the status code `` STATUS_ACCESS_VIOLATION``.
* 설정 된 Protection Constant에 따라 다른 Exception이 발생한다.
Bypass
windows
```c
LPVOID WINAPI VirtualAlloc(
_In_opt_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD flAllocationType,
_In_ DWORD flProtect
);
BOOL WINAPI VirtualProtect(
_In_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD flNewProtect,
_Out_ PDWORD lpflOldProtect
);
```
페이지에 `` PAGE_EXECUTE_READWRITE( 0x40 )`` 을 준다.
Linux
'Security > System Exploit' 카테고리의 다른 글
[메모리 보호 기법] RELRO (0) | 2017.07.15 |
---|---|
[메모리 보호기법] ASLR, FORTIFY_SOURCE (1) | 2017.07.13 |
BOF, Buffer OverFlow ( local exploit ) (0) | 2016.11.10 |
FSB, Format String Attack/Bug (0) | 2016.10.23 |
System [ Exploit ] (0) | 2016.09.03 |