아메바시큐리티

Section 17. 각종 시스템 보안 위협 및 대응책 본문

정보보안기사(필기)

Section 17. 각종 시스템 보안 위협 및 대응책

am2ba 2021. 3. 1. 19:23

Buffer Overflow 공격

버퍼 오버플로우 공격 개요

1) 프로세스 메모리 구조

- Text 영역, Data 영역 , Heap 영역, Stack 영역

 

Text 영역

- 프로그램 코드와 상수 저으이

- 읽기만 가능한 메모리 영역

- 데이터를 저장하려고 하면 분할 충돌로 인해 프로세스 중지

 

Data 영역

- 전역 변수와 정적 변수가 저장

 

Heap 영역

- 프로그래머의 필요에 따라 동적 메모리 호출에 의해 할당되는 메모리 영역

 

Stack 영역

- 함수 인자 값, 함수 내의 지역 변수, 함수의 변환 주소 등이 저장되는 영역

- 상위메모리에서 하위 메모리로 주소 데이터가 저장

 

2) 스택 프레임 구조

 

 

3) Buffer Overflow 공격의 기본 개념

- 버퍼 또는 데이터 저장 영역에 할당된 용량보다 더 많은 입력이 위치하면 다른 정보를 변경할 수 있는 조건

- 공격자는 이런 조건을 이용하여 시스템을 중지시키거나 시스템의 제어를 갖기 위한 특별한 코드를 삽입

- 프로세스가 정해진 크기의 버퍼 한계를 벗어나 이웃한 메모리 위치에 데이터를 겹쳐 쓰려고 시도하는 것과 같은 프로그래밍 오류의 결과로 발생

 

4) 공격 원리

int main(int argc, char *argv[]){
	char buff[10];
    	stcpy(buffer, argv[1]);
        printf("%s\n", buffer);
}

이 프로그램은 실행시 인자값을 넣어주어 해당 인자값을 출력해주는 프로그램이다. 

해당 코드에서 버퍼 오버플로우는 "strcpy(buffer, argv[1])" 에서 일어난다 

 

Stack buffer overflow

- 보통 SetUID 가 설정된 루트 권한의 프로그램을 대상으로 공격

- 스택에 정해진 버퍼보다 큰 공격 코드를 삽입하여 반환주소를 변경함으로써 임의의 공격 코드를 root 권한으로 실행하도록 하는 방법

 

1) Shellcode

- 많은 버퍼 오플로우 공격의 핵심 요소는 오버플로우가 발생하는 버퍼에 저장되는 공격자의 코드로 실행제어를 이동시키는 것

- 이 코드를 shell 코드라고 한다.

- 사용자 명령어 라인의 해석기인 셸로 제어를 넘기고 공격당한 프로그램의 권한으로 시스템의 다른 프로그램이 접근하기 때문

 

2) stack buffer overflow 공격 절차

1단계 : 공격 셸 코드를 버퍼에 저장

2단계 : 루트 권한으로 실행되는 프로그램의 특정 함수의 스택 반환주소 버퍼를 오버플로우시켜서 공격 셸 코드가 저장되어 있는 버퍼의 주소로 덮어 씌우기

3단계 : 특정 함수의 호출이 완료되면 조작된 반환 주소로 셸코드의 주소가 반환되어 셸 코드가 실행되고, 루트 권한을 획득

 

Heap overflow

- 힙은 전역 데이터 위에 위치하며 메모리 위 방향으로 커짐

- 힙에 요청되는 메모리는 레코드의 연결리스트와 같은 동적 데이터 구조를 위해 사용

- 레코드가 오버플로우에 취약한 버퍼를 가지고 있다면 연속된 메모리가 손상 가능

- 실행제어를 쉽게 이동시킬 수 있는 반환주소는 없음.

- 할당된 공간이 함수에 대한 포인터를 포함하고 있다면.... 공격자는이 주소를 변경하여 겹쳐 쓴 버퍼에 있는 셸코드를 가리키도록 할 수 있음.

 

Buffer overflow 공격 대응책

컴파일 시간 방어

- 새 프로그램 내에서 공격을 저지하도록 프로그램을 강화하는 것을 목표로 함

- 프로그램을 컴파일할 때 검사하여 버퍼 오버플로우를 방지하거나 발견하는 것

- 버퍼 오버플로우를 허용하지 않는 Java, ADA, Python과 같은 현대화된 고급 프로그래밍 언어를 사용하여 소프트웨어를 작성하면 방지 가능

- C나 C++ 과 같이 메모리 접근에 높은 자유도를 가진 프로그래밍 언어를 사용하는 경우, 반드시 할당된 버퍼 크기를 초과하지 않도록 로직을 설정해야함

- 기존의 프로그램을 다시 컴파일 해야하는 단점이 있음. 

 

1) 프로그래밍 언어의 선택

- 현대의 고급 수준의 프로그래밍 언어를 사용하여 프로그램을 작성하면 방지 가능

- 컴파일러가 범위 검사를 강제로 수행하는 코드를 자동으로 추가했기 때문

 

2) 안전한 코딩 기법들

- 사용을 자제해야하는 함수 : strcat, strcpy, gets, scanf, sscanf, vscanf, vsscanf, sprintf, vsprintf, gethosbyname, realpath

- 사용을 권장하는 함수 : strncat, strncpy, fgets, fscanf , vfscanf, snprintf, vsnprintf

 

3) 언어 확장과 안전한 라이브러리 사용

- 표준 문자열 라이브러리를 안전한것으로 교체하는 방법

- Libsafe. 표준 의미를 구현하면서 추가적으로 복사 연산이 스택 프레임 내부의 지역 변수 공간을 넘어가지 않도록 검사하는 기능을 구현

 

4) 스택 보호 메커니즘

- 함수의 진입과 종료 코드를 조사하고 함수의 스택 프레임에 대해 손상이 있는지를 검사하는 것.

- 만약 검사에 이상이 있다면 프로그램 종료

- 컴파일러가 프로그램의 함수 호출 시에 ret 앞에 canary 값을 주입하고 종료 시에 canary 값이 변조되었는지 여부를 확인하여 버퍼 오버 플로우를 탐지

 

실행 시간 방어

- 운영체제의 업데이트로 배포할 수 있음

- 실행 가능 주소 공간 보호(Executable Address Space Protection) 기법과 주소 공간 임의화(Address Space Randomization)기법 사용

 

Executable Address space Protection

- 실행 코드가 프로세스 메모리상의 특정위치에서만 실행될 수 있게 함으로서 공격자가 스택 버퍼에 주입한 실행코드를 원천적으로 실행될 수  없게 만드는 방법

- 대부분의 공격은 스택 버퍼에 실행 코드를 주입하므로 재컴파일 없이 기존 프로그램들을 보호하는데 효과적

 

Address Space Randomization

- 스택 버퍼가 위치하는 주소 공간을 메모리 내에서 임의적으로 배치함으로써, 공격자가 스택 버퍼 속에 주입한 실행코드의 주소를 예측할 수 없게 만드는 방법

- 실행코드로의 반환 주소 변경이 매우 어렵게 되어 스택버퍼오버플로우 공격이 어려워짐

 

1) ASLR과 NOP

 

Address Space Layout Randomization

- 프로세스 주소 공간에 있는 중요 데이터 구조의 위치를 조작하는 방법

- 공격자는 셸 코드로 제어를 넘기기 위해 공격에 사용할 적당한 반환주소를 결정하는데 예측된 주소를 사용

- 이러한 예측을 어렵게 하는 방법으로, 각 프로세스 안의 스택이 임의의 다른 곳에 위치하도록 변경하는 방법

 

NOP sled

- NOP는 아무 기능도 수행하지 않는 명령어를 의미

- 기계어 코드 핵사값이 0x90

- 빈공간을 채우기 위한 명령어로, 해당 명령어를 만나면 아무런 동작 없이 다음 명령어로 넘어감

- 셸 코드 실행을 위해 NOP 명령을 삽입하는 이유는 Return Address가 셸코드 주소를 정확히 가리켜야 하는데 프로그램 실행시마다 셸 코드 주소가 조금씩 바뀔 수 있기 때문에 정확한 주소를알기 어려움

- 실행 확률을 높이기 위해 다수의 NOP 명령을 셸 코드 앞에 삽입하여 해당 영역을 가리키기만 하면 NOP을 타고 최종적으로 셸 코드가 실행되도록 하기 위해 공격시 NOP을 삽입한 셸 코드를 사용

 

2) 실행 가능 주소 공간의 보호

- 스택과 힙을 Non-Executable Stack으로 만듦으로써 기존 프로그램을 위한 여러가지 유형의 버퍼 오버플로우에 대한 방어를 제공 

- 최신 운영체제는 이 기법을 포함

- 프로그램이 실행 가능 스택을 사용안함으로 설정하는 방법은 /etc/system 파일 설정을 통해 가능

set noexec_user_stack = 1
set noexec_user_stack_log = 1

* 우회 방법

return to libc 공격사용.

- 스택에 있는 ret 주소를 실행 가능한 임의의 주소 (libc 영역 주소)로 돌려 원하는 함수를 수행하게 만드는 기법. 

- 메모리에 적재된 공유 라이브러리는 스택에 존재하는 것이 아니므로, 우회 가능

 

Format String Attack

- printf, fprintf, sprintf와 같이 포맷스트링을 사용하는 함수를 사용할 때, 외부로 입력된 값을 검증하지 않고, 입출력 함수의 포맷 문자열을 그대로 사용하는 경우 발생할 수 있는 취약점

- 포맷문자열을 이용하여 취약한 프로세스를 공격하거나 메모리 내용을 읽거나 쓰기 가능

- 공격자는 취약한 프로세스의 권한을 획득하여 임의의 코드를 실행 가능

 

공격 원리

- 데이터의 형태에 대한 불명확한 정의로 인해 발생

#include <stdio.h>

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

- 여기서 포맷 스트링 공격은 %s를 변경하는 것

- 포맷 스트링을 지정하지 않고, 사용자 입력을 통해서 포맷 스트링이 결정된다면, 이를 조작하여 메모리 내용을 참조하고 특정 영역의 값을 변경할 수 있음.

예시)

공격자가 스택 프레임 구조를 고려하면서 %x를 통해 메모리 내용 참조 및 원하는 위치로 이동한 후 %n을 통해 Return Address를 악성코드가 위치한 주소로 변조하여 악성코드를 실행할 수 있음. 

 

취약점 위협 요소

1) 프로그램의 파괴

- 가장 간단한 공격

- core를 덤프하는 데몬을 죽이는데 유용하게 사용 가능

- DNS 스푸핑을 할 때 어떤 서비스가 반응하지 않도록 하는데도 유용

 

2) 프로세스 메모리 보기

- 포맷 함수의 응답을 볼 수 있다면 그것으로부터 유용한 정보를 수집 가능

- 공격자는 결과를 통해 포맷 스트링이 무엇을 하며, 프로세스 배치가 어떻게 생겼는지 대략적인 내용 획득 가능

 

3) 메모리 덮어 쓰기

- 어떤 프로세스의 명령 통제권 장악 가능

 

보안 대책

- printf(), snprintf() 등 포맷 문자열을 사용하는 함수를 사용할 때는, 사용자 입력값을 직접적으로 포맷 문자열로 사용하거나, 포맷 문자열 생성에 포함하지 않는다.

- 포맷 문자열을 사용하는 함수에서 입력값을 사용할 때는 포맷 스트링을 변경할 수 있는 구조로 쓰지 않는다.

- 특히, %n, %hn은 공격자가 이를 이용해 특정 메모리 위치에 값을 변경할 수 있으므로, 포맷 스트링 매개체로 사용하지 않는다.

- 사용자 입력값을 포맷 문자열을 사용하는 함수에 사용할 때는 가능한 %s 포맷 문자열을 지정한다.

 

 

Race Condition Attack

- 둘 이상의 프로세스나 스레드가 공유자원에 동시에 접근할 때 접근하는 순서에 따라 비정상적인 결과가 발생하는 조건상황

- 프로세스가 임시 파일을 만드는 경우, 악의적인 프로그램을 통해 그 프로세스의 실행중에 끼어들어 임시파일을 목적파일로 연결(심볼릭 링크)하여 악의적인 행위를 하는 것

- 프로세스가 setuid 설정이 되어, root 권한으로 실행된다면 권한 상승을 통한 중요 자원에 접근 가능

 

파일 링크

1) 하드링크

- 하드 링크를 간단히 말하면 똑같이 복사된 파일을 만드는 것.

- 하드 링크 파일을 수정하면 원래 파일도 수정됨

- 두 파일 중 하나를 삭제하면 파일의 내용은 바뀌지 않고 링크만 줄어듬

- 두 파일이 각각 동일한 수준의 데이터를 가지며 서로 그 데이터를 동기화

- 링크하고자 하는 파일이 다른 파티션에 존재하면 안됨

 

2) 심볼릭 링크

- 데이터가 있는 파일이 처음부터 하나뿐이고, 심볼릭 링크는 단지 원본 파일 데이터를 가리키는 링크 정보만 가져옴

- 원본 파일과 심볼릭 링크는 원본 파일이 상제되더라도, 원본 파일의 이름과 위치를 기억하고 계속 그 파일을 바라보는 상태로 남음

- 삭제된 원본 파일 대신 처음 원본 파일과는 다르지만 같은 경로에 같은 파일명으로 생성하면, 심볼릭 링크 파일은 새로 생성된 파일에 여전히 링크 파일로 존재하게됨

 

심볼릭 링크와 레이스 컨디션 공격

- 대상 : 소유자가 root이고, SetUID 비트를 가지며, 임시파일을 생성하는 파일

- 조건 : 소유자 root, SetUID, 생성되는 임시 파일의 이름을 알고 있어야 함

- losf 명령어로 특정파일에 접근하는 프로세스 목록을 확인할 수 있으며, 특정 프로세스가 사용하는 파일 목록을 뽑을 수 있음. 이를 통해 임시파일이름을 확보

- 임시 파일이름으로 프로그램이 실행되기 전의 심볼릭 링크 파일을 생성

- 해당 심볼릭 링크 파일은 관리자 권한으로만 접근 가능한 /etc/passwd 파일 등을 가르키고 있으면 됨

 

레이스 컨디션 공격에 대한 대응책

- 프로그램 로직 중에 임시파일을 생성한 후, 임시파일에 대한 심볼릭 리크 설정 여부와 권한에 대한 검사 과정을 추가

- 가능하면 임시파일을 생성하지 않는 것이 좋음

- umask를 최하(022) 정도로 유지하여 임시로 생성한 파일이 공격자에 의해 악의적으로 삭제되지 않도록 해야함

 

Backdoor

- 시스템의보안이 제거된 비밀 통로

- 서비스 기술자나 유지보수 프로그래머의 접근 편의를 위해 시스템 설계자가 고의적으로 만들어 놓은 통로

- 현장에서 서비스 기술자가 공급사 유지보수 프로그래머의 업무 편의성을 향상 시켜줌

- 악의적으로 만는 통로의 대표 예시 : Back orifice

- 해킹 프로그램의 일종으로 PC에 내장되어 사용자 몰래 사용자의 정보를 저장, 유출하기 위한 프로그램

 

리눅스/유닉스의 백도어

- root 권한으로 운영되는 경우는, httpd 데몬이 시작 프로그램으로 자동 실행되거나 관리자가 보안에 관심 없는 경우

- root 권한으로 운영되는 http 데몬은 보안에 매우 취약

- 인터넷을 사용하는 동안에는 차이는 못느끼지만, root 계정으로 운영되는 웹서버에 접속하고 있을 때는, root ㅜ건한으로, nobody 계정으로 웹에 접속하고 있을 때는 nobody 권한으로 시스템에 자료를 요청하는 것

 

백도어 탐지와 대응책

1) 현재 동작중인 프로세스 확인

- 백도어가 아닌 정상 프로세스를 아는 것도 중요

- 윈도우나 유닉스 시스템의 정상 프로세스를 알아두는 것이 좋음

- 윈도우 프로세스의 경우 이름을 인지해두면 웜/바이러스나 백도어에 대응하는데 큰 도움이 됨. 

웜/바이러스나 백도어가 가장 애용하는 것은 Csrss와 Svchost 프로세스

 

Csrss.exe(Client/Server Runtime Subsystem:Win32)

- 윈도우 콘솔을 관장하고, 스레드를 생성/삭제하며 32 비트 가장 MS_DOS 모드를 지원하는 프로세스

Explorer.exe

- 작업 표시줄, 바탕화면 같은 사용자 셸을 지원하는 프로세스

Lsass.exe(Local security Authentication Server)

- Winlogon 서비스에 필요한 인증 프로세스를 담당, 인증 성공시 초기 셸을 실행

- 사용자별 엑세스 토큰을 생성하여 다른 프로세스들이 해당 토큰을 상속받게 됨

Mstask.exe(Windows Task Scheduler) 

- 시스템에 대한 백업이나 업데이트 등에 관련된 작업의 스케줄러 프로세서

Smss.exe(Session Manager SubSystem) 

- 사용자 섹션 시작 기능을 담당하는 프로세스

- Winlogon, Win32을 구동하고, 시스템 변수 설정

- Smss는 Winlogon이나 Csrss가 끝나기를 기다려 정상적인 Winlogon, Csrss 종료 시 시스템 종료

Spoolsv.exe(Printer Spoller Service)

- 프린터와 팩스의 스풀링 기능을 담당하는 프로세스

Svchost.exe(Service Host Process)

- DLL에 의해 실행되는 프로세스의 기본 프로세스

- 따라서 한 시스템에서 scvhost 프로세스를 여러개 볼 수 있음

Services.exe(Service Control Manager)

- 시스템 서비스를 시작/정지하여 그들간의 상호 작용하는 기능을 수행하는 프로세스

Taskmgr.exe(Task Manager)

- Window 작업관리자 자신의 프로세스

Winlogon.exe (Windows Logon Process)

- 사용자 로그인/로그오프를 담당하는 프로세스

 

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

- DoS 공격

- 시스템이 보유하고 있는 자원을 선점하거나 모두 고갈하는 방식으로 사용

- 디스크 채우기, 메모리 고갈, 모든 프로세스 죽이기, 프로세스 무한 생성 등... 

 

System resource Exhaustion Attack 종류

1) 가용 디스크 자원 고갈 공격

 

#include <unistd.h>
#include <sys/file.h>

void main(){
	int fd;
    char buf[1000];
    fd = create("/root/temfile", 0777)
    while(1) write(fd,buf,sizeof(buf));
}

위와 같은 코드를 사용하여 공격하는 방식. 

파일을 생성하고 이 파일에 1,000 바이트씩 계속 써 나가는 프로그램

 

2) 가용 메모리 자원 고갈 공격

- 다른 특별한 함수 없이, malloc 함수를 통해 메모리 할당만 계속 수행하는 프로그램

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

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

 

3) 가용 프로세스 자원 고갈 공격

- fork() 라는 프로세스 할당 함수만 무한대로 사용하는 방법

- 당장 시스템 자원을 많이 차지하지 않지만, 가용 프로세스가 가득 차면 문제가 발생

- 심한 경우 운영체제를 재 설치 해야할 수도 있음.

#include <unistd.h>

void main(){
	while(1)
    	fork();
    return 0;
}

 

4) 프로세스 죽이기 공격

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

- 웹 또는 FTP 서비스를 제공하는 데몬이 함께 죽으면서 시스템에서 제공하는 모든 서비스가 동작하지 못하게됨

#!/bin/sh

sync
kill -15 1

 

리버스 엔지니어링

- 장치나 시스템의 구조를 분석하여 원리를 발견하는 과정

- 상업적이나 군사적으로 하드웨어를 분석하는것에서 시작

- 어떤 대상을 생산하기 위한 지식이나 절차가 거의 없는 상태에서 최종 제품을 통해 설계하는 과정을 역추론하는 것이 목적

 

리버스 엔지니어링 공격

- 공격 대상 시스템 또는 응용프로그램에 대한 분석 수행

- 분석 이후, 해당 시스템이나 응용 프로그램이 갖고 있는 취약점을 찾아 공격하는 방식으로 주로 사용

 

리버스 엔지니어링에 대한 대응책

- 프로그램 코드를 어렵게 하는 난독화 기술

- 코드의 난독화를 통해 가독성을 낮추어, 분석을 어렵게 하거나 패턴/시그니처 기반 보안 장비의 탐지를 위회하기 위해 사용

 

소스코드 난독화

- C/C++/JAVA 등의 프로그램 소스코드를 알아보기 힘들게 만드는 기술. 

바이너리 난독화

- 생성된 바이너리를 역공하을 통해 분석하기 어렵게 변조하는 기술

 

기타 시스템 보안위협 및 대응책

Rootkit

- 시스템에 설치되어 그 존재의흔적을 최대 한도로 숨기면서 공격자가 언제든지 시스템에 관리자 권한으로 접근할 수 있도록 비밀통로를 지속적으로 유지시켜주는 일련의 프로그램 집합

- 공격자는 운영체제의 모든 기능과 서비스를 제어할 수 있게 됨.

- 자신의 존재를 숨기기 위해 시스템을 변경하여, 루트킷의 탐지와 행위를 어렵게 한다.

 

1) Rootkit의 확인

- 공격자는 자신의 행동을 숨기기 위해 정상적인 프로그램을 대신하도록 바이너리 파일을 변조시키는 경우가 많음

- ls 명령어를 수정하여 자신의 프로세스가 보이지 않도록 하는 등의 해우이

- rootkit을 찾기 위해서는 시스템 프로그램의 파일 크기, 생성시간 등 메타데이터를 확인

- /bin/usr/bin에서 다른 프로그램이 기본적으로 설치된 시간과 다르게 변경된 파일이 있는지 확인

- 트로이목마로 자주 변조되는 ls, ps 등과 같은 파일의 경우 똑같은 OS 의 다른 시스템 파일 사이즈를 비교하여 변조 여부 확인

 

2) 논리폭탄(logic bomb)

- 특정한 사건이 발생할 때 프로그램이나 일련의 코드를 실행

예시) 네트워크 관리자는 그가 해고되었다면 기업의 전체 데이터 베이스를 삭제하도록 프로그램된 논리폭탄 설치 가능

- 사용자가 특정한 행위를 수행할 때, 그것의 페이로드 실행을 활성화하는 많은 유형의 트리거를 가질 수 있음

- 공격자가 시스템에 포렌식활동일 실행되면 다 지우도록 논리폭탄을 심어둔다면 이것으로 수사를 어렵게 할 수 있음