엄범



SSP : Stack Smashing Protector ( link )

  1. 로컬 변수 위치 재배치
  2. 로컬 변수 전에 포인터 배치
  3. 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

  1. ``c fork()``하는 경우 canary도 parent의 것을 그대로 복사해 가져오기 때문에 항상 동일한 값을 가진다.
  2. 프로세스 내 모든 함수에서 canary로 사용하는 값은 같다. 따라서 어느 함수에서든 canary를 알아내기만 하면 된다.
  3. 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