Linux

[Linux] 서버 운영 보안 요소 - forkbomb, 레인보우 테이블과 Salt, 패스워드 크래킹, File system destruction

여백 :: 2024. 11. 21. 00:49

해당 포스팅은 rocky linux 기반으로 예제를 작성하였음

 

정보보안의 3요소?

- 정보보안의 목적은 정보의 세 가지 성질 (CIA : 기밀성, 무결성, 가용성)을 유지하는 것

 

1. 기밀성 (Confidentiality)

- 정보 자산에 접근할 수 있도록 인가된 사람이나 프로그램만이 "권한의 범위 내에서 정보에 접근"할 수 있도록 하는 성질

- 비공개 정보를 누구나 열람할 수 있다면 기밀성이 손상된 상태

 

2. 무결성 (Integrity)

- 정보 자산이 손상되진 않았는지, 일관성, 완전성을 유지하는 성질

- 전송 혹은 보관된 데이터가 중간에 손실되거나 파손된다면 무결성을 잃은 것임

 

3. 가용성 (Availability)

- 인가된 사람이나 프로그램이 "언제든지 정보 자산에 접근"할 수 있는 성질

- 웹사이트 과부하로 사용할 수 없는 상태가 되거나 서버 구축이 잘못돼 처리가 오래 걸리는 등의 문제가 생긴다면 가용성이 손상된 상태 

 

Forkbomb

- 프로세스가 지속적으로 자기 자신을 복제하여 사용 가능한 시스템 리소스를 고갈시키고, 리소스 부족으로 인해 시스템이 느려지거나 작동 중단되는 서비스 거부 (DoS) 공격

:(){ :|:& };:

 

위와 같은 명령어를 입력하면 bash 에서 forkbomb이 발생하게 된다. (따라하지 말 것)

# dnf install gcc
$ vi main.c // 소스코드 입력
$ gcc -o forkbomb main.c
$ ./forkbomb
#include <sys/types.h>
#include <unistd.h>
int main() {
  while (1) {
    fork();
  }
  return 0;
}

 

C에서 forkbomb을 일으키는 코드이다.

 

 

Disk Overflow attack (DoS attack)

cat /dev/zero > /tmp/log

 

- /dev/zero : NULL(ASCII=0) character를 무한히 반환하는 특수 파일

- Ctrl+C 인터럽트로 멈추지 않으면 디스크 공간이 고갈될 때까지 실행됨

touch `seq 1 100000`

 

- 리눅스 파일시스템의 파일 생성 갯수 제한 (=2^32, 약 43억)을 노리는 공격

- 10만개의 파일 생성, 그 다음 추가 10만개의 파일 생성, ..., 무한 반복

 

 

Memory allocation attacks (malloc bomb)

- 많은 양의 메모리를 할당하는 프로그램

- 프로그램을 수용하기 위해 시스템이 swapping을 시작하면서 swap space를 모두 사용하고 최종적으로 crash 하게됨

 

  • Bash에서의 Malloc Bomb 예시 코드 
while true; do echo $(</dev/zero) & done

 

 

  • Python에서의 Malloc Bomb 예시 코드 
$ free -h
	total used free shared buff/cache available
Mem: 1.6Gi 814Mi 200Mi 3.0Mi 728Mi 825Mi
Swap: 4.0Gi 63Mi 3.9Gi

$ python
>>> a = 'A' * 800 * (1024**2) # 800MB 크기의 문자열 “AAAAAAA…" 할당
>>> Ctrl+Z
[1]+ Stopped python

$ free -h
	total used free shared buff/cache available
Mem: 1.6Gi 1.4Gi 166Mi 0.0Ki 182Mi 248Mi
Swap: 4.0Gi 212Mi 3.8Gi

# 메모리 잔여공간 감소 825 -> 248MB. Swap 사용량 증가 63 -> 212MB

 

 

Process Limits

- 기본적으로는 아래와 같이 unlimited가 기본값으로 설정되어있다.

 

 

이를 차단하기 위해 아래 예시와 같이 ulimit 커맨드를 활용하면 된다!

-v : 프로세스에 의해 할당된 최대 가상 메모리

-u : 유저가 생성할 수 있는 프로세스의 최대 수

ulimit -v 1048576 # Limit virtual memory allocation for each process to 1GB
ulimit -u 100 # Limit user created processes to 100

 

단 현재 쉘의 유저에 한해 임시적으로 변경되는 것이 특징이다. 

이를 영구적으로 변경하고 싶은 경우 다음과 같이 /etc/security/limits/conf 파일을 수정하면 된다!

 

/etc/security/limits/conf 의 일부

 

 

디스크 쿼터 (Disk quota)

  • 디스크 쿼터
    • 파일 시스템마다 사용자나 그룹이 생성할 수 있는 파일의 용량과 개수를 제한하는 것
    • 디스크 자원 고갈을 방지하여 디스크 관련 가용성을 확보할 수 있음
    • 메일, samba 서버 등과 연계하여 유저의 사용량을 효과적으로 제어할 수 있음

쿼터 구현 순서

 

 

Linux user DB 무결성

  • 만약 /etc/passwd 에 기록된 user4의 UID가 0으로 변경되었다면, user4 계정으로 로그인할 경우 root가 된다.

 

즉 여기서 user4의 1004 부분이 0으로 변경되면 이후 su - user4를 입력하여 user4의 비밀번호를 입력해도 바로 root 유저로 진입할 수 있게 된다.

 

  • /etc/shadow의 두 번째 column에 기록된 user5의 password hash가 지워져서 아래와 같은 형태가 되었다면, 비밀번호 없이 바로 user5로 로그인할 수 있게 된다! (Backdoor 파놓은 셈)
[rocky@localhost ~]$ sudo cat /etc/shadow | grep user5
user5::20044:0:99999:7:::
[rocky@localhost ~]$ su - user5
Last login: Mon Nov 18 00:53:57 KST 2024 on pts/0
[user5@localhost ~]$

 

  • /etc/passwd의 두 번째 column에 기록된 'x'가 지워졌다면 해당 유저의 비밀번호가 없다는 의미이므로
  • /etc/shadow를 참조하지 않고 해당 유저로 로그인됨
  • 'x' 표시는 비밀번호가 있었는데 shadow 파일로 이동했다는 의미이다.
user3:x:1003:1004::/home/user3:/bin/bash
user4:x:0:1005::/home/user4:/bin/bash
user5::1004:1006::/home/user5:/bin/bash

 

 

Rainbow Table과 Salt

 

여기서 노란색은 비밀번호를 hash algorithm (6=SHA512)라는 알고리즘에 넣은 것, 녹색이 Salt, 파란색이 평문비밀번호+Salt 기반으로 생성된 hash 이다.

 

MD5, SHA와 같은 Hash 함수의 특징으로는, "같은 입력"이 주어졌을 때 반드시 "같은 값"을 출력하는 특징이 존재한다.

그런데 이제 공격자 관점에서 이 해시 함수의 특징을 바라봤을 때 아래의 rainbow table을 생각해볼 수 있다.

 

  • Rainbow table
    • 가능한 입력들에 대해 미리 구해둔 해쉬 값의 테이블
    • password hash가 담긴 파일이 유출되면 rainbow table과 join 연산하여 빠르게 평문을 유추할 수 있음!

소문자 a부터 대문자 Z까지 해시값을 떠놓은 것 (52개 해쉬)

 

이러한 레인보우 테이블을 개인 해커는 갖고있지 않지만 state sponsored hacker와 같은 정부의 지원을 받는 해커 집단들은 다 갖고 있다.

따라서 이런 shadow 파일이 딱 유출이 되었을 때 이 해시값과 해킹된 shadow 파일을 join해서 쉽게 패스워드를 찾아낼 수 있는데, 이때 아래의 Salt라는 것을 더하면 이 rainbow table을 사용하지 못하도록 제한할 수 있다!

 

  • Salt
    • Rainbow table의 대응수단으로, 시스템에서 정의한 상수 (랜덤 값)
    • 사용자가 지정한 비밀번호와 salt를 합쳐 해쉬를 구한다.

 

여기서 녹색이 랜덤하게 시스템에서 정해준 상수 salt 값이다.

예를 들어 루트의 비밀번호를 "password" 로 똑같은 평문으로 지정했을 때, salt값을 랜덤이기 때문에 다 다를 것이다.

그래서 이 salt 값과 우리가 입력한 패스워드를 결합해서 계속 그 결과로 나오는 저 파란색 hash 값이 다르게 출력되도록 하는 개념이 바로 Salt 인 것이다!

 

즉 위 사진속 문구를 해석하면 다음과 같다.

user3이 입력한 비밀번호와 salt=Am.LluHMBDzg7r0X (녹색)가 결합되어 해쉬 함수의 입력이 된다.

이후 해시 함수 6(노란색)을 사용하여 zYCJsx4JDN9C4Rjl4vvNH18N4dKT6dTg3dw4n3VHl24eX38fyywVw9LyaYcS 0cevvztCJONfvcwkOk.ygaEKr0 (파란색) 라는 출력이 나오면 인증에 성공하는 것!

 

그렇다면 이제 salt값이 있는 상황에서 rainbow table도 사용할 수 없는데, 여전히 shadow 파일이 유출되어도 괜찮은가?

그렇지 않다.

 

salt 값이 있어도 여전히 패스워드 크래킹 위협이 존재하며, 다음 예시를 통해 확인할 수 있다.

 

 

John the Ripper : 사전 기반 + 브루트포스 패스워드 크래킹 프로그램

패키지 관리 시스템 "snap" 설치
# dnf install -y epel-release
# dnf install -y snapd
# systemctl enable --now snapd.socket

snap으로 john-the-ripper 설치
# snap install john-the-ripper

쉘에 재로그인 이후부터 john 명령어를 사용할 수 있음
$ john (root, non-root 모두 해당 프로그램 사용 가능)

 

이를 이용해 패스워드 크래킹 (/etc/shadow) 를 진행하면,

공격자의 경우 계정 비밀번호 평문을 획득할 수 있고, 서버 운영자라면 취약한 계정을 식별할 수 있다.

따라서 유추하기 어려운 (사전에 없고 길이가 긴) 비밀번호를 사용해야 한다.

 

크래킹된 비밀번호를 모자이크 하였음

 

여기엔 /etc/shadow로 나의 shadow 파일을 넣었지만, 여기에 이제 외부에서 획득한 shadow 파일의 경로를 입력하면 해당 파일에서 비밀번호를 크래킹할 수 있다.

 

 

File system destruction

루트 권한의 쉘이 잠시라도 탈취당할 경우 다음과 같은 위험한 커맨드들이 실행될 수 있다...

 

# rm -rf / 2>/dev/null &

 

- 시스템에 존재하는 모든 파일 삭제

# dd if=/dev/zero of=/dev/sda bs=1024 count=1
# python -c "print('A'*1024)" > /dev/sda

 

리눅스에서 보조기억장치(HDD, SSD)를 sda, sdb, sdc, sdd와 같은 파일로 표현한다.

 

여기서 첫 번째 줄의 /dev/zero는 0을 무한히 반환하는 파일이며 이를 input으로 부여한 것이다.

/dev/sda 파일은 하드디스크나 SSD를 의미하여 어떤 비트나 바이너리를 저장할 수 있는 저장장치

즉 첫 번째 코드를 해석해보면 첫 번째 구역으로 가서 1024 바이트를 한 번 복사하라는 의미! (0으로 덮어쓰는 셈)

두 번째 코드는 파이썬으로 디스크의 첫 구역을 A로 덮어쓰는 것이다.

 

즉 저장장치 "sda"의 첫 1024 바이트를 NULL 혹은 A 로 덮어쓰는 코드!

 

  • 또한 owner=root인 find, python 등의 프로그램에 set-uid-bit가 걸린 경우, 언제든 root 권한의 쉘이 탈취될 수 있다고 보아야 한다!
$ whoami
rocky
$ ls -al `which find`
-rwsr-xr-x. 1 root root 336272 Nov 5 2023 /usr/bin/find
$ find . -exec python \;
Python 3.9.18 (main, Jan 24 2024, 00:00:00)
[GCC 11.4.1 20231218 (Red Hat 11.4.1-3)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.getuid(), os.geteuid()
(1000, 0)
>>> os.setuid(0)
>>> os.system('bash')
# whoami
root

원래는 이렇게 rwx인게 정상이지만, 위 예제처럼 rws인 경우 backdoor를 생성할 수 있다!

 

또한 꼭 필요한 경우가 아니라면, 모든 유저의 기본 쉘을 /sbin/nologin으로 지정한다.

non-root 유저의 쉘이라도 시스템에 악영향을 끼칠 수가 있으며, 특히 jupyterhub로 python 컴퓨팅 환경을 제공하려는 경우 가급적 모든 유저의 기본 쉘을 nologin으로 바꿔야 한다.

 

현재 유저가 디폴트로 /bin/bash로 설정되어 있는 모습

 

 

 

리눅스 서버 해킹 cycle overview

  • 로컬 시스템 해킹
    • Actor : 사무환경의 직원 혹은 공공장소의 임시 방문객
    • user permission 쉘 획득 -> local privilege escalation -> credential 획득/backdoor 설치 -> 증거 인멸 (history, login 기록 삭제) -> login 기록 삭제 -> hacked.
  • 원격 시스템 해킹
    • Actor : 인터넷에 접속 가능한 누구나
    • Target : HTTP 서버, FTP 서버, SSH 서버
    • 공격 대상 서버 & 서비스 식별 -> 배너를 통한 서비스 정보 획득 -> 서비스 취약점 익스플로잇 -> user permission 획득 -> user permission 쉘 획득
    • 쉘 획득 이후 과정은 위와 동일하다.