외로운 Nova의 작업실

정보보안기사 필기 - 17(각종 시스템 보안 위협 및 대응책) 본문

Certification/정보보안기사

정보보안기사 필기 - 17(각종 시스템 보안 위협 및 대응책)

Nova_ 2022. 11. 23. 14:23

- 버퍼 오버플로우

버퍼 또는 데이터 저장 영역에 할당된 용량보다 더 많은 입력을 위치시켜 다른 정보를 변경하는 공격 기법입니다. 주로 strcpy 함수에서 일어나게됩니다.

 

- 스택 버퍼 오버플로우

보통 SetUID가 설정된 루트 권한의 프로그램을 공격대상으로하여 버퍼 오버플로우를 이용해 반환주소를 변경함으로써 임의의 공격코드를 루트 권한으로 실행하도록 하는 방법입니다. 1988년 모리스 인터넷 웜에서 gets() 함수의 검사되지 않은 버퍼오버플로우가 처음 발견되었습니다.

 

<셸코드>

버퍼 오버플로우의 공격의 핵심은 반환 코드에 셸의 주소를 넣어 셸로 제어를 넘기고 공격당한 프로그램의 권한으로 시스템의 다른 프로그램에 접근하는 것입니다. 이러한 코드를 셸코드라고 합니다.

 

<스택 버퍼 오버플로우 공격절차>

  1. 공격 셸 코드를 버퍼에 저장합니다.
  2. 루트 권한으로 설정되는 프로그램의 특정 함수의 스택 반환주소 버퍼를 오버플로우시켜 공격 쉘 코드가 저장되어있는 버퍼의 주소로 덮어씌웁니다.
  3. 특정 함수의 호출이 완료되면 조작된 반환 주소로 셸 코드의 주소가 반환되어 셸코드가 실행되고 루트 권한을 획득하게됩니다.

- 힙 오버플로우

일반적으로 힙은 최대주소 방향으로 커집니다. 스택과는 다르게 실행 제어를 쉽게 이동시킬 수 있는 반환 주소는 없지만 할당된 공간이 함수에 대한 포인터를 포함하고 있다면 공격자는 이 포인터의 주소를 버퍼의 주소로 바꿔 셸코드를 가리키게 할 수 있습니다.

 

- 버퍼 오버플로우 대응책

버퍼 오버플로우 방어법은 크게 두가지 번주로 분류될 수 있습니다. 컴파일 시간 방어와 실행시간 방어입니다.

<컴파일 시간 방어>

컴파일 시간 방어는 컴파일 할때 검사하여 버퍼 오버플로우를 방지하거나 발견하는 것을 목표로 합니다. 가장 기본적인 방법은 java와 같이 현대화된 고급 프로그래밍 언어를 사용하는 것입니다. C나 C++과 같이 메모리 접근에 높은 자유도를 가진 프로그래밍 언어를 사용하는 경우 버퍼의 크기를 초과하지 않도록 반드시 확인하는 로직을 포함하여 안전하게 프로그래밍 해야합니다.

 

<안전한 코딩 함수들>

  • 사용을 자제하는 함수 : strcat(), strcpy(), gets(), scanf(), sscanf(), vscanf(), vsscanf(), sprintf(), vsprintf(), gethostbyname(), realpath()
  • 사용을 권장하는 함수 : strncat(), strncpy(), fgets(), fscanf(), vfscanf(), snpribtf(), vsnprintf()

<스택 보호 매커니즘(Stack Guard)>

Stack Guard는 가장 잘 알려진 버퍼 오버플로우 보호 매커니즘 중에 하나입니다. 함수 호출시에 ret 앞에 canary 값을 주고 종료 시에 canary 값이 변조되었는지의 여부를 확인하여 버퍼 오버플로우 공격을 감지합니다. 하지만 이를 적용하기위해서는 기존의 프로그램들을 모두 새롭게 컴파일해야합니다.

 

<스택 쉴드>

함수 시작 시 복귀주소를 Global RET이라는 특수 스택에 저장해 두었다가 함수 종료시 저장된 값과 스택의 RET값을 비교해 다를 경우 오버플로우로 가정하여 프로그램 실행을 중단시키는 기술을 말합니다.

 

<실행 시간 방어>

대부분의 컴파일 시간기법은 기존의 프로그램을 다시 컴파일 해야하기때문에 기존의 취약한 프로그램에 보호를 제공하기 위해 운영체제의 업데이트로 배포할 수 있는 실행 시간 방어법이 인기를 끌고 있습니다. 실행 시간 방어법에는 실행가능 주소 공간 보호 기법과 주소 공간 임의화 기법이 있습니다. 

  • 실행 시간 주소 공간 보호 기법 : 실행 코드가 프로세스 메모리상의 특정 위치에서만 실행될 수 있게함으로써 쉘코드를 ret 위치에 넣어도 실행되지 않게 하는 방법입니다.
  • 주소 공간 임의화 기법 : 스택 버퍼가 위치하는 주소 공간을 메모리 내에서 임의적으로 배치함으로써 공격자가 ret 위치를 모르게 만드는 것입니다.

<ASLR과 NOP>

ASLR(주소 공간의 임의 추출, address space layout randomization) : 프로세서 주소 공간에 있는 스택을 임의의 다른 곳에 위치하도록 변경하여 ret주소를 예측하지 못하게 하는 기법입니다.

NOP sled : NOP은 아무기능도 수행하지 않는 명령어를 의미합니다. 기계어 핵사값은 0x90입니다. 이는 ret 부분에 셸코드의 주소를 넣었다고 해도 셸코드의 주소가 변경될 수 있으므로 셸코드 앞부분에 NOP 명령어를 삽입하여 NOP 부분만 가르키기만 하면 NOP을타고 최종적으로 쉘코드가 실행되도록 하는 기법이이 있습니다. 아래는 이해하기 쉬운 예시 그림입니다.

 

<실행 가능 주소 공간의 보호>

스택과 힙을 실행 불능으로 만듦으로써 스택과 힙에 있는 내용들을 모두 변수로 보게 만듭니다. 이를 설정하는 방법은 Solaris 2.7버전 이상에서는 /etc/system 파일에 다음 두 라인을 추가하여 설정할 수 있습니다.

  • set noexec_user_stack = 1
  • set noexec_user_stack_log = 1

하지만 이는 rtl이라는 스택에 있는 ret 주소를 실행가능한 libc 영역의 주소로 돌려 원하는 함수를 수행하게 만드는 기법에 의해 우회가 가능합니다. 메모리에 적재된 공유 라이브러리는 스택에 존재하는 것이 아니기때문입니다.

 

- 포멧 스트링 공격(FSA, format string attack)

printf(), fprintf(), sptirnf()와 같이 포맷스트링을 사용하는 함수를 사용하는 경우 외부로 부터 받아오는 매개변수를 포맷 문자열 그대로 사용하는 경우에 발생한다. 아래는 포멧 스트링 공격에 취약한 코드입니다.

#include<stdio.h>

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

위 코드에서 인자값으로 %x를 주게되면 스택의 최상단에 있는 내용을 가져와 메모리 내용을 참조할 수 있으며 이후 %n을 통해 ret부분에 악성코드가 위치한 주소로 변조하여 악성코드를 실행할 수 있습니다. 이러한 원리로 프로그램의 파괴, 프로세스 메모리 보기, 임의의 메모리 덮어쓰기와 같은 공격을 할 수 있습니다.

 

- 레이스 컨디션 공격

실행중인 프로세스가 임시파일을 만드는 경우 악의적인 프로그램을 통해 그 프로세스의 실행중에 끼어들어 임시파일을 심볼릭 링크하여 악의적인 행동을 하게하는 공격입니다. 즉 다시말해, 실행중인 프로세스가 test.txt 파일을 생성하고 처리한후에 프로세스를 종료한다면 해커는 test 파일을 test.lnk 파일로 변경하여 목적파일로 연결할 수 있습니다. 이때, 실행중인 프로세스의 소유자가 root 이고 SetUID를 가진다면 목적파일을 관리자 권한으로 실행시킬 수 있어 큰 위협이되게됩니다.

일반적인 프로세스
심볼링 링크로 공격당하는 프로세스

레이스 컨디션 공격을 하려면 생성되는 파일의 이름을 알고 있어야 합니다. 리눅스에서는 lsof(list open files)라는 명령어로 특정 파일에 접근하는 프로세스 목록을 확인할 수 있으며 특정 프로세스가 사용하는 파일 목록을 뽑아 볼 수도 있습니다. 보통 레이스 공격을통해 etc/passwd 파일을 수정하여 root 권한을 획득합니다.

 

<대응책>

  • 임시파일이 심볼릭링크 설정 이 되었는지 검사 과정을 추가합니다.
  • 가능하면 임시파일을 만들지 않습니다.
  • 임시파일에 umask를 022정도로 유지하여 파일이 공격자에 의해 악의적으로 삭제되지 않도록 합니다.

- 백도어

서비스 기술자나 유지보수 프로그래머의 접근 편의를 위해 시스템 설계자가 고의적으로 만들어 놓은 통로를 백도어라고 합니다. 이러한 통로를 만드는 이유는 현장에서 업무 편의성을 향상시키기 위함입니다. 악의적인 목적으로 만들어놓은 통로도 있는데 백 오리피스(back orifice)가 대표적입니다. 이프로그램은 pc에 내장되어 사용자 몰래 사용자의 정보를 저장,유출하는 프로그램입니다.

 

<대응책>

  1. 윈도우와 유닉스 시스템의 정상 프로세스를 어느정도 외워서  정상 프로세스인지 의심스러운 프로세스인지 구별을 해야합니다. 특히 윈도우의 경우 Csrss.exe와 Svhost.exe 프로세스는 윔/바이러스나 백도어가 가장 애용하는 프로세스입니다. 아래는 윈도우의 기본적인 프로세스 종류입니다.
  • Csrss.exe(client/service runtime subsystem) : 윈도우 콘솔을 관장하고 스레드를 생성/삭제하며 32비트 가상 ms-dos를 지원하는 프로세스입니다.
  • Explorer.exe : 작업 표시줄, 바탕화면 같은 사용자 셸을 지원하는 프로세스입니다.
  • Lsass.exe(local security authentication server) : winlog 서비스에 필요한 인증 프로세스를 담당하며 인증 성공 시 초기 셸을 실행합니다.
  • Mstask.exe(window task schedular) : 시스템에대한 백업이나 업데이트 등에 관련된 작업의 스케줄러 프로세스입니다.
  • Smss.exe(session manager subsystem) : 사용자 세션 시작 기능을 담당하는 프로세스입니다. 
  • Spoolsv.exe(printer spooler service) : 프린터와 팩스의 스플링 기능을 담당하는 프로세스입니다.
  • Svchost.exe(service host process)DLL애 의해 실행되는 프로세스의 기본 프로세스입니다. 한 시스템에서 svchost 프로세스를 여러개 볼 수 있습니다.
  • Services.exe(Service control manager) : 시스템 섭스를 시작/정지하여 그들 간의 상호 작용하는 기능을 수행하는 프로세스입니다.
  • Taskmgr.exe(task manager) : window 작업 관리자 자신의 프로세스입니다.
  • Winlogon.exe(windows logon process) : 사용자 로그인/로그오프를 담당하는 프로세스입니다. 윈도우 시작/종료시나 ctl+alt+del 키를 눌렀을때 활성화 됩니다.

   2. H-IDS를 사용하여 백도어가 특정포트에 대하여 대기하고 있기때문에 의심스러운 포트의 활동을 감지하여 백도어를           탐지할 수 있습니다.

 

- 시스템 자원 고갈 공격(시스템 서비스 거부 공격)

대부분의 시스템을 대상으로 하는 서비스 거부 공격은 시스템이 보유하고 있는 자원을 선점하거나 모두 고갈하는 방식으로 수행됩니다. 대표적으로 디스크 채우기, 메모리 고갈, 모든 프로세스 죽이기, 프로세스 무한 생성 방법등이 있습니다.

<디스크 자원 고갈 공격>

#include<unistd.h>
#inlcude<sys/file.h>
void main(){
	int fd;
    char vuf[1000];
    fd = creat("/root/temfile", 0777)
    while(1) write(fd, buf, sizeof(buf));
}

 

<메모리 자원 고갈 공격>

디스크 고갈 공격보다 시스템 자원을 더 많이 차지하여 터미널 창 하나만 띄우는데도 몇분을 소모하게 만드는 공격입니다.

#include <stdio.h>
void main(){
	char *m;
    while(1)
    	m = malloc(1000);
}

 

<프로세스 자원 고갈 공격>

시스템 자원을 많이 차지하지않지만 가용 프로세스가 꽉차면 골치아픕니다. 공격 계속 기다리다가 운영체제를 다시 설치해야할 수 도 있습니다.

#include <unistd.h>
void main(){
	while(1)	
    	fork();
        
    return0;
}

 

<프로세스 죽이기 공격>

공격자가 루트 권한을 획득한 상태에서 스크립트를 통해 사용중인 프로세스를 죽이는 기법입니다. 

#!/bin/sh
sync
kill 15 1

 

- 리버스 엔지니어링

장치나 시스템의 구조를 분석하여 원리를 발견하는 과정을 리버스 엔지니어링이라합니다. 이는 상업적이나 군사적으로 하드웨어를 분석하는 것에서 시작되었지만 분석을 수행한 후 취약점을 찾을 수 있으며 이 취약점을 공격할 수 있는 코드를 생성해낼 수 있습니다.

 

<대응책>

프로그램 코드를 읽기 어렵게 만드는 기술로 소스코드 난독화와 바이너리 난독화로 구분합니다.

  • 소스코드 난독화 : 자바와 같은 프로그램 소스코드를 알아보기 힘들게 만드는 기술입니다.
  • 바이너리 난독화 : 컴파일 후 생성된 바이너리를 역공학을 통해 분석하기 어렵게 변조하는 기술을 말합니다.

 

- 기타 시스템 보안 위협

  • 루트킷 : 시스템에 설치되어 그 존재의 흔적을 최대한도로 숨기면서 공격자가 언제든지 시스템에 관리자 권한으로 접근할 수 있도록 비밀 통로를 지속적으로 유지시켜주는 일련의 프로그램 집합을 말합니다. 루트킷은 자신의 존재를 숨기기위해 시스템을 많이 변경하지만 사용자가 어떤걸 변경하고 루트킷이 들어와잇는지 조차 알기 어렵게 만듭니다.
  • 논리 폭탄 : 특정한 사건이 발생했을때 프로그램이나 일련의 코드를 실행하는 것을 논리 폭탄이라고 합니다. 만약 포렌식 활동이 실행된다면 논리 폭탄이 시작되어 모든 디지털 증거를 삭제하도록 할 수 있습니다. 이것은 조사팀의 분석을 무력화하고 공격자의 신원과 방식을 숨깁니다.

 

 

Comments