강좌
클라우드/리눅스에 관한 강좌입니다.
해킹&보안 분류

리눅스마스터1급: DoS(Denial of Service) 공격의 유형-내부에서의 공격

작성자 정보

  • 관리자 작성
  • 작성일

컨텐츠 정보

본문

리눅스마스터1: DoS(Denial of Service) 공격의 유형-내부에서의 공격

 

 

 

 

대부분의 전문가들이 구분하기를 DoS 공격을 외부에서의 공격, 내부에서의 공격 두 가지 유형으로 나누고 있다.

 

 

 

 

 

DoS 공격에 있어서 관심이 되고 있는 부분은 대부분이 내부에서의 공격보다는 외부에서 공격이고 실제로 공격 방법을 살펴보면 내부에서의 공격은 간단한 스크립트 몇 줄로 써도 가능한 데 비해서 외부에서의 공격은 좀 더 복잡하고 고도의 기술을 요하고 있다.

 

 

 

또한 내부에서의 공격은 이미 그 시스템에 계정을 가지고 있어야만 가능하기 때문에 DoS가 시스템의 루트 권한을 획득하는 공격법이 아니라는 것을 고려한다면 큰 의미를 가질 수 있다고 볼 수는 없다.

 

 

 

하지만 일반 사용자의 권한으로 시스템을 마비시킬 수 있다는 사실 자체는 간과할 수 없음에 분명하다.

 

 

 

 

 

DoS공격 - 내부에서의 공격

 

 

대부분의 내부에서의 공격은 시스템이 보유하고 있는 리소스를 점유하거나 모두 고갈시켜 버림으로써 가능해 진다.

 

 

 

실제로 이를 위해서는 간단한 C 코드나 쉘 스크립트를 이용하여 가능하다.

 

 

 

하지만 이러한 공격 방법의 문제점은 반드시 시스템에 계정을 가지고 있어야 한다는 사실이다.

 

 

 

대부분의 침입자들이 시스템을 침입할 경우 일단 루트를 먼저 획득하는 데 관심을 가지기 때문에 내부에서의 공격은 사실상 고의에 의해서라기보다는 사용자들의 실수로 인해서 발생하는 경우가 대부분이라고 볼 수 있다.

 

 

 

 

 

아래의 간단한 예들을 통해서 DoS 공격이 어떻게 가능해지는지 살펴보도록 하자. 주의할 점은 DoS 공격에는 아래에 소개되는 예제 말고도 다른 수많은 방법이 존재한다는 사실이다.

 

 

 

 

 

디스크 채우기

 

 

아래의 방식은 임의의 파일을 만들어서 파일 시스템을 가득 차게 하는 방식이다.

 

 

 

소스 코드를 보면 알 수 있듯이 임의의 파일을 열고나서 그 파일을 unlink시킨다.

 

 

 

이 부분에 대해서는 아래의 매뉴얼 페이지를 유심히 읽어 볼 필요가 있다.

 

 

 

 

 

 

 

 

 

unlink() removes the directory entry named by the pathname pointed to by path and decrements the link count of the file referred to by that entry. If this entry was the last link to the file, and no process has the file open, then all resources associated whit the file are reclaimed. If, however, the file was open in any process, the actual resource reclamation is delayed until it is closed, even thought the directory entry has disappeared.

 

 

 

 

 

unlink 시킨 후에 파일의 크기를 무한정 증가시켜 파일 시스템을 가득 차게 함으로써 시스템을 마비 상태로 만들게 된다.

 

 

 

 

 

 

 

 

 

/* Creates massive files with no Inode info, making deletion difficult */

/* The files do not appear under or ls b/c they have no dir entries */

/*#include <io.h>

#include <stdio.h>

#include <process.h>*/

#include <stdio.h>

#include <sys/file.h>

void main()

{

int ifd;

char buf[8192];

ifd=open("./attckfil",O_WRONLYIO_CREAT,0777);

unlink("./attckfil");

while(1)

write(ifd,buf,sizeof(buf));

}

 

 

 

 

 

 

해결 방안으로는 문제의 프로세스를 알아내어 죽이는 방법뿐이다.

 

 

 

하지만 이 경우에 문제의 프로세스를 알아내는 것은 매우 어렵다.

 

 

 

왜냐하면 ps나 다른 방법을 이용하여 문제의 프로세스를 알아내려고 하여도 시스템이 거의 비정상적이기 때문에 이러한 방법을 적용시키려고 하여도 잘 동작하지 않는다는 사실 때문이다.

 

 

 

그러므로 어쩔 수 없는 경우에는 최후의 방법으로 시스템을 다시 시작하게 되는 것도 하나의 방법일 수 있다.

 

 

 

이 경우 프로세스가 죽게 되면 늘어났던 파일도 자연적으로 사라지게 되므로 파일 시스템이 다시 정상적으로 돌아오게 된다(이는 운영체제의 경우에 따라 차이가 있을 수 있다고 본다). 이를 위한 대비책으로 각 사용자들에 대해서 quota를 할당하는 것도 하나의 좋은 방법이 될 수 있다.

 

 

 

하지만 이 tmp 디렉토리와 같이 여러 사용자 프로세스들이 공동으로 사용하는 디렉토리에 이 공격을 한다면 quota를 할당하는 것 또한 무용지물이 된다.

 

 

 

 

 

메모리 고갈

 

 

아래의 예제는 메모리 리소스를 고갈시켜 시스템을 마비시키는 코드이다.

 

 

 

이는 실제 메모리를 모두 사용한 후에 스왑(Swap) 공간까지 모두 잡아먹다가 결국에는 몇 초 안에 시스템이 제공할 수 있는 모든 메모리를 고갈시켜 심지어는 ps 명령어까지 동작하지 않게 하여 프로세스를 죽이는 일조차 하지 못하게 된다.

 

 

 

 

 

매우 간단한 예제이므로 쉽게 이해할 수 있을 것이고 실제로 이러한 방식의 DoS는 누구나 프로그래밍을 하다가 한 번쯤은 경험할 수 있는 경우이므로 자세한 설명은 생략하겠다.

 

 

 

 

 

 

 

 

 

/* For information use only. Watch as your vg. CPU and MEM use climb to */

/* new heights... */

#include <stdio.h>

void main()

{

char c;

while(1)

c=malloc(1000);

}

 

 

 

 

 

 

 

해결 방안으로는 모두 고갈된 후에는 더 이상 메모리를 할당받을 수 없기 때문에 다른 프로세스를 죽여서 약간의 메모리를 확보한 다음 ps를 이용하여 문제의 프로세스를 죽이는 것이다.

 

 

 

하지만 이 방법이 모든 UNIX에서 가능한 것은 아니고 시스템에 따라서 완전히 죽어버리는 경우도 있음을 기억하기 바란다.

 

 

 

물론 문제의 프로세스를 알아내는 방법은 관리자의 재량에 맡길 수밖에 없다.

 

 

 

프로세스가 죽게 되면 잡혔던(Allocated) 메모리가 모두 사용 가능하게(Free) 되므로 다시 시스템이 정상적으로 돌아오게 된다.

 

 

 

이는 운영체제가 반드시 제공해야 할 특징 중의 하나이므로 대부분의 Unix에서 지원되리라고 본다.

 

 

 

문제의 프로세스를 찾아내는 방법이 곤란할 경우 최후의 방법으로 시스템을 다시 시작하게 하는 방법이 있을 수 있다.

 

 

 

 

 

모든 프로세스 죽이기

 

 

아래의 예제는 존재하는 모든 프로세스를 죽이는 방법이다.

 

 

 

이는 init 프로세스에 SIGTERM 시그널을 보냄으로써 가능하다.

 

 

 

 

 

 

 

 

 

#define SIGTERM 15 /* software termination signalfrom kill */

 

 

 

 

 

이 경우 모든 프로세스를 죽이기 위해서는 루트 권한을 가지고 있어야 한다.

 

 

 

그러므로 사실은 침입자가 시스템에 침입한 후 이미 루트 권한을 획득한 후에야 가능한 방법이다.

 

 

 

그러므로 이는 침입 후 사용자나 시스템의 데이터를 파괴하는 방법은 아니지만 시스템을 사용 불능 상태로 만드는 방법이므로 루트 권한 획득 후 할 수 있는 일 중에서도 상당히 얌전한 것으로 생각 할 수도 있다.

 

 

 

 

 

관련된 매뉴얼의 내용은 다음과 같다.

 

 

 

 

 

 

 

 

 

To shut the system down and bring it up single user the super-user may send the initialization process a TERM (terminate) signal by 'kill 1'; see init(8). To force init to close and open terminals according to what is currently in /etc/ttytab use 'kill -HUP 1' (sending a hangup signal to process 1) .

init terminates multi-user operations and resumes single-user mode if sent a terminate (SIGTERM) signal: use 'kill -TERM 1'. If there are processes outstanding which are deadlocked (due to hardware or software failure), init does not wait for them all to die (which might take forever), but times out after 30 seconds and prints a warning message.

 

 

 

 

 

 

이는 다음과 같은 간단한 스크립트로써 가능해 진다.

 

 

 

 

 

 

 

 

 

# run as root to kill all processes

#!/bin/sh

sync

kill -15 1

 

 

 

 

 

 

 

해결책으로는 시스템을 다시 재가동하는 방법이 있다.

 

 

 

 

 

프로세스 만들기

 

 

아래의 예제는 시스템의 프로세스 테이블을 모두 고갈시켜 이루어지는 공격 방법이다.

 

 

 

일반적으로 커널이 만들어질 때 가능한 프로세스의 수를 한정시켜 놓게 되는데 이때 이 정해진 수를 넘어서게 되면 프로세스 테이블이 모두 고갈되면서 시스템의 모든 서비스가 거의 중단되게 된다.

 

 

 

실제로 테스트해 본 결과 시스템을 정상화시키기 위해서 재가동을 해야 하는 상태가 되었다.

 

 

 

 

 

 

 

 

 

/* Will paralyze some systems */

void main()

{

while(1) fork();

}

또는

void main()

{

fork();

main();

}

 

 

 

 

 

 

 

이 경우에는 그때그때의 상황에 따라 관리자가 능동적으로 대처하도록 하자. 한 예로 그 문제의 프로세스를 알아내어 죽이는 것인데 이 방법이 어려울 경우에는 시스템을 재가동시키는 수밖에 없다.

 

 

 

 

 

앞에서 소개한 간단한 예들은 인터넷에서 쉽게 구할 수 있는 내부에서의 공격에 해당되는 수많은 예들 중에서 몇 가지 대표적인 것만을 골라보았다.

 

 

 

이 예들에서 알 수 있듯이 내부에서의 공격은 모두가 시스템이 가지고 있는 리소스를 독점하여서 문제를 야기하고 있는데 이러한 방법들의 공통적인 문제점은 시스템의 재시동을 제외하고는 현재로서는 확실한 해결책이 없다는 것이다.

 

 

 

운영체제가 보다 더 안전하게(Robust) 설계되는 것이 이 문제의 근본적인 해결책이라고 생각된다

관련자료

댓글 0
등록된 댓글이 없습니다.

공지사항


뉴스광장


  • 현재 회원수 :  60,043 명
  • 현재 강좌수 :  35,853 개
  • 현재 접속자 :  76 명