Software/소프트웨어보안

Stack Overflow에 대한 대응과 안전한 프로그램 개발

와븨 2022. 11. 26. 17:52

스택 Overflow에 대한 대응

일반적인 방어 방법

방어 기술은 fix를 대체하기 어려움

- 계층적인 방어(Layered Defense) 기법 : 악성코드 실행, 취약한 코드의 악용

- 코드의 변경이 가능한지에 대한 고려

 

Overflow defense

공격에 대한 성공 확률 낮춤

- Tamper detection: 누가 건드렸는지 확인

- 운영체제와 하드웨어에서의 Memory protection: 실행할 수 없는 곳에서는 실행이 안되도록 함

- Diversification methods: 메모리의 위치를 랜덤하게 해라. (특히 return address, ebp)

 

Canaries on the stack

각 스택 프레임이 갖고 있는 취약한 포인터 값들에 대한 보호

Idea

- 프레임을 보호계층으로 감싸기 "canary" - unhealthy condition을 알아내서 먼저 알려줌

- Canary는 return address 아래 위치

- 공격자가 리턴 주소를 위변조 하고자 할 때

- 프로그램 실행 중 Canary의 갱신 여부를 확인

 

Stack without canaries

 

Stack with canaries

 

GCC's Stack Smashing Protector

#include <stdio.h>
#include <string.h>

int fun1(char *arg){
    char buffer[1024];
    strcpy(buffer,arg);
}

void main(int argc, char *argv[]){
    fun1(argv[1]);
}

위의 코드를 어셈블리로 표현하면 다음과 같다.

 

SSP 없는 코드

fun1

- pushl, movl을 통해 새로운 스택을 만든다.

- 스택이 가리키는 위치가 1048만큼 증가한다.

- ebp에서 8만큼 떨어진 값을 eax에 넣는다.

- eax의 값을 esp에서 4만큼 떨어진 값에 넣는다.

- eax값을 esp로 이동하고 strcpy를 호출한다.

 

SSP 있는 코드

- 스택을 생성한 후, 스택이 가리키는 위치를 1064만큼 올린다.

- ebp에서 8만큼 떨어진 값을 eax에 넣고, ebp에서 -1052만큼 떨어진 값에 eax를 넣는다.

- gs:20은 일종의 난수이다. EAX에 canary 값을 세팅한다.

- 리턴 주소 근처에 canary 값을 저장한 후, strcpy를 호출한다.

- edx에 canary 값을 저장하고, canary 값이 바뀌었는지 확인한다. 변하지 않았다면 L3로 점프해 정상 종료하고, 변했다면 abort 한다.

 

Detecting Stack Overflow

$ gcc -m32 overflow.c -o overflow.out
$ ./overflow.out xxxx
$ ./overflow.out 'perl -e 'print "x"x1025''
***stack smashing detected ***: ./overflow.out terminated Aborted (core dumped)

 

경쟁 조건

경쟁 : 공격자는 canary 매커니즘을 분석하여 이의 취약점을 발견하고 공격을 수행

- 상수형 canary를 찾아냄

  • 만일 canary가 0x0af237ab6이면 리턴 주소 근처에 해당 값을 넣어서 우회함

- 난수형 canary

  • 난수 값의 변화를 확인하거나 SEED 값을 찾아냄
  • 컴퓨터는 보통 SEED 값을 사용해 난수값을 생성하는데, 보통 SEED는 날짜,시간 값을 쓴다.

- 암호 기술 기반의 난수 생성

  • 값이 저장된 위치 찾기
  • 이를 복사하기 위한 코드 작성

 

Temper detection 효과

지역 변수는 보호하지 않음

- 지역 변수의 재배치를 방어기법으로 사용

파라미터에 대한 overwriting 공격

- 연속적으로 쓰기가 발생한 경우의 변경을 확인

- 리턴 주소에 쓰기를 해도 리턴하지 않음 -> 종료, abort

Heap 보호 기능 개발

- glibc와 Windows XP SP2부터 heap canaries를 갖고 있음

리턴을 기반으로 하는 프로그래밍

- state-of-the-art: 존재하는 실행 코드의 활용

- Canaries 우회, NX까지 우회

 

Operating system 분리

고립(Isolation) : 다른 프로세스들이 다른 자원을 사용하도록

공유(Sharing) : 프로세스간 자원이 공유되어야 함, 일부 고립 허용

- 공유 대상: All or nothing, 접근 통제를 위한 중재, 사용량 제한을 통한 중재

Concern: 보호의 단위

운영체제는 다중 사용자 환경을 기반으로 분리 매커니즘을 중요하게 생각함

 

NX(실행불가-Non-executable) Memory

CPU가 메모리 페이지에 대해 R, RW, X 보호 기능을 갖게 함

- x86 series CPU들은 페이지 레벨 XD/NX을 갖게 함

non-executable regions의 정의를 통해

- code와 데이터가 나누어져 있는 상황을 고려

- 쉘 코드의 실행이 데이터영역에서 이루어지지 않도록 할 수 있음

 

ASLR (Address Space Layout Randomization)

개념

- 같은 프로그램의 여러 버전을 만들어서 다양화

- 고정된 구조를 가질 것이라고 가장한 공격의 발생을 막을 수 있음

Randomization을 통해

- 데이터 혹은 코드의 위치를 찾기 어렵게 함

효과

- 좋지만, 주된 취약점을 제거하지는 못함

- 오히려 ASLR구현 내용이 악용 대상이 되기도 함

- 적은 주소 공간을 가지고 random화 할 경우 (e.g. 256 addresses), 공격자가 brute force(무차별 대입 공격) 기법으로 취약한 위치를 찾을 수 있음

 

안전한 프로그램 개발

방어적 프로그래밍 - 경계 점검

오버 플로우에 대한 방어적 프로그래밍 방법은 경계의 검사임

- 쓰기 전 데이터 길이 검사 (Check data lengths before writing)

- 입력의 길이를 제한 (Constrain size of inputs)