보안취약점점검_요약

[리눅스 보안취약점 점검] 파일 및 디렉터리 관리 U-14~U-18 자동화 스크립트 분석

보안실무자J 2026. 9. 8. 09:48
반응형

 

리눅스 서버의 파일과 디렉터리는 단순히 데이터를 저장하는 공간이 아니다.

/etc/passwd, /etc/shadow와 같은 계정·인증 파일부터 시스템 시작 과정에서 실행되는 스크립트, 관리자 환경변수, 애플리케이션이 생성한 파일까지 운영체제의 주요 기능이 파일 시스템을 통해 연결되어 있다.

따라서 파일 하나의 소유자나 권한이 잘못 설정되거나, 관리자의 PATH에 안전하지 않은 경로가 포함되어 있는 경우 단순한 설정 오류를 넘어 권한 상승이나 인증정보 노출, 시스템 기동 과정의 악성 코드 실행으로 이어질 가능성이 있다.

이번 글에서는 파일 및 디렉터리 관리 영역의 U-14~U-18을 대상으로 현재 사용 중인 자동 진단 스크립트가 실제로 어떤 범위를 검사하는지 분석한다.

특히 자동화 점검 결과만 보고 파일을 삭제하거나 권한을 일괄 변경하면 정상적인 서비스까지 영향을 받을 수 있으므로, 점검 결과의 의미와 조치 시 주의해야 할 부분을 함께 확인하는 것을 목적으로 한다.


1. U-14~U-18에서 무엇을 확인하는가

이번 영역은 크게 네 가지 관점으로 나눌 수 있다.

  • 실행 경로의 안전성 → U-14
  • 소유자가 사라진 파일의 존재 여부 → U-15
  • 계정 및 인증 관련 핵심 파일 보호 → U-16, U-18
  • 시스템 시작 과정에서 실행되는 파일 보호 → U-17
점검코드 점검 명칭 주요 점검 대상 현재 스크립트의 핵심 검사 위험도
U-14 root 홈, 패스 디렉터리 권한 및 패스 설정 $PATH, /etc/profile, root 환경 설정 현재 PATH에 . 또는 빈 경로가 포함되는지 확인 상
U-15 소유자 없는 파일 및 디렉터리 존재 여부 /, /home, /var, /tmp, /usr, /opt nouser 또는 nogroup 파일을 검색 하
U-16 /etc/passwd 파일 소유자 및 권한 설정 /etc/passwd 소유자와 Group/Other의 쓰기·실행 권한 확인 상
U-17 시스템 시작 스크립트 권한 설정 /etc/rc.d, /etc/init.d, /etc/systemd/system 등 Other 쓰기 권한이 있는 파일 검색 상
U-18 /etc/shadow 파일 소유자 및 권한 설정 /etc/shadow root 소유 여부와 400/000, 600/640 권한을 구분하여 확인 상

주의: 위 표는 일반적인 보안 가이드의 모든 판단 요소가 아니라 현재 사용 중인 자동화 스크립트가 실제로 검사하는 범위를 기준으로 작성했다.


2. U-14 — PATH가 공격 경로가 될 수 있는 이유

2.1 점검 배경

관리자가 Linux에서 명령어를 입력하면 Shell은 PATH에 등록된 디렉터리를 순서대로 검색하여 실행할 프로그램을 찾는다.

예를 들어 다음과 같은 PATH가 있다고 가정한다.

PATH=.:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin

현재 디렉터리인 .이 PATH의 가장 앞에 있기 때문에 관리자가 단순히 다음 명령을 실행했을 때,

ls

현재 디렉터리에 공격자가 만들어 놓은 ls라는 실행 파일이 있다면 시스템의 정상적인 /usr/bin/ls보다 먼저 실행될 가능성이 있다.

따라서 root 계정의 PATH에는 현재 디렉터리나 빈 경로가 포함되지 않도록 구성하는 것이 중요하다.


2.2 현재 자동화 스크립트가 검사하는 것

# [상세 해설] U-14 점검 항목 시작 알림
CODE "[ U-14 ] root 홈, 패스 디렉터리 권한 및 패스 설정"

# [상세 해설] echo "$PATH" 출력을 확장 정규식으로 검사
# 정규식 패턴 분석:
#   - \. : 현재 디렉터리를 나타내는 점(dot) 포함 여부
#   - \:\: : 디렉터리 경로 누락으로 빈 경로(현재 디렉터리로 간주됨)가 발생하는 이중 콜론
#   - \:$ : PATH 문자열 끝에 콜론이 위치하여 현재 디렉터리가 마지막 검색 경로로 잡히는 형태
#   - ^\: : PATH 문자열 시작에 콜론이 위치하여 현재 디렉터리가 최우선 검색 경로로 잡히는 형태
if echo "$PATH" | grep -E -q "\.|\:\:|\:$|^\:"; then
    WARN "root 계정의 PATH 환경변수에 '.' 또는 빈 경로가 포함되어 있습니다." "현재 PATH=$PATH"
else
    OK "root 계정의 PATH 환경변수에 '.' 또는 빈 경로가 안전하게 제거되어 있습니다." "현재 PATH=$PATH"
fi

FINISH "[ U-14 ] 점검완료"

2.3 이 스크립트의 판정 방식

U-14는 현재 Shell에 로드되어 있는 $PATH 문자열을 대상으로 다음 패턴을 검색한다.

.
::
:

정확히는 다음과 같은 형태를 위험 요소로 검색한다.

PATH=.:/usr/bin
PATH=/usr/bin:.
PATH=/usr/bin::/bin
PATH=:/usr/bin
PATH=/usr/bin:

따라서 현재 스크립트에서는 위험한 패턴이 발견되면 WARN, 발견되지 않으면 OK가 출력된다.

중요한 부분은 현재 스크립트가 /etc/profile, /root/.bashrc, /etc/profile.d/*.sh 등을 직접 하나씩 분석하는 것이 아니라 현재 $PATH 값을 검사한다는 점이다.

즉, 어떤 설정 파일에서 PATH가 만들어졌는지를 추적하는 기능은 별도로 포함되어 있지 않다.


2.4 운영 환경에서 확인할 사항

현재 PATH를 먼저 확인한다.

echo "$PATH"

위험한 패턴을 별도로 확인할 수도 있다.

echo "$PATH" | grep -E "(^\:|\:\:|\:$|\.\/|\:\.\:|\:\.$)"

아무런 결과가 나오지 않는 것을 기준으로 확인할 수 있다.

또한 PATH를 변경하기 전에 다음 설정 파일들을 함께 확인하는 것이 안전하다.

/etc/profile
/root/.bash_profile
/root/.bashrc
/etc/profile.d/*.sh

2.5 실무에서 자주 놓치는 부분

일부 애플리케이션 설치 스크립트나 개발 환경에서는 편의를 위해 다음과 같은 설정을 추가하는 경우가 있다.

export PATH=.:$PATH

특히 CI/CD Agent나 개발자가 사용하는 환경에서는 이런 설정이 의도적으로 들어갈 수도 있다.

따라서 .을 발견했다고 바로 삭제하기보다 어떤 설정 파일에서 추가되었는지와 해당 환경에서 왜 필요한지를 먼저 확인하는 것이 필요하다.

보안점검에서는 위험한 설정을 제거하는 것만큼 기존 운영 환경의 의존성을 확인하는 과정도 중요하다.


2.6 안전한 조치

변경 전에 관련 파일을 백업한다.

cp -p /etc/profile /etc/profile.bak_$(date +%Y%m%d)
cp -p /root/.bash_profile /root/.bash_profile.bak_$(date +%Y%m%d) 2>/dev/null
cp -p /root/.bashrc /root/.bashrc.bak_$(date +%Y%m%d) 2>/dev/null

이후 해당 설정에서 . 또는 불필요한 빈 경로를 제거한다.

예를 들어 다음 설정이 있다면,

export PATH=.:$PATH

운영 환경에 맞는 절대 경로 기반 PATH로 변경한다.

변경 후에는 새 Shell에서 실제 적용값을 확인한다.

source /etc/profile
echo "$PATH"

3. U-15 — 소유자가 사라진 파일을 발견했을 때

U-15는 다른 항목과 접근 방식이 조금 다르다.

/etc/passwd나 /etc/shadow처럼 특정 파일의 권한을 확인하는 것이 아니라 시스템 안에서 정상적인 소유자 또는 그룹과 연결되지 않는 파일을 찾는 항목이다.

3.1 왜 고아 파일이 생기는가

사용자 계정이 삭제되거나 패키지가 비정상적으로 제거된 이후에도 해당 계정이 생성했던 파일은 남아 있을 수 있다.

이 경우 파일의 UID/GID는 그대로 존재하지만 현재 시스템의 /etc/passwd, /etc/group에서 해당 ID를 사용하는 계정을 찾지 못할 수 있다.

이런 파일을 흔히 고아 파일(Orphan File)이라고 한다.

다만 고아 파일 = 즉시 삭제해야 하는 파일은 아니다.

애플리케이션 데이터, 로그, 컨테이너 환경의 파일 등 정상적인 운영 과정에서도 이러한 상황이 발생할 수 있기 때문이다.


3.2 자동 진단 스크립트

# [상세 해설] U-15 점검 항목 시작 알림
CODE "[ U-15 ] 소유자 없는 파일 및 디렉터리 존재 여부"

# [상세 해설] 대용량 스토리지 및 네트워크 마운트로 인한 부하를 방지하기 위해 로컬 핵심 디렉터리 지정
TARGET_DIRS="/ /home /var /tmp /usr /opt"

# [상세 해설] find 명령어로 -nouser 또는 -nogroup 조건을 검색하되,
# -xdev 옵션을 통해 다른 파일시스템(NFS 등)으로 탐색이 넘어가는 것을 차단함
# EXEC_TIMEOUT 함수를 통해 60초 초과 시 탐색을 중단하여 I/O 병목 방지
ORPHAN_FILES=$(EXEC_TIMEOUT 60 "find $TARGET_DIRS -xdev -type f \( -nouser -o -nogroup \) 2>/dev/null | head -n 5 | xargs")
EXIT_CODE=$?

# [상세 해설] Exit Code 124(타임아웃 발생) 여부 및 파일 존재 여부 조건 분기
if [ "$EXIT_CODE" -eq 124 ]; then
    INFO "소유자 없는 파일 검색 중 응답 지연(60초 초과)이 발생하여 점검을 중단했습니다." "수동 점검 요망"
elif [ -n "$ORPHAN_FILES" ]; then
    WARN "소유자나 그룹이 존재하지 않는 고아 파일이 발견되었습니다." "발견된 파일(최대 5개): [ $ORPHAN_FILES ]"
else
    OK "시스템 내에 소유자나 그룹이 존재하지 않는 파일이 발견되지 않았습니다." "정상 확인"
fi

FINISH "[ U-15 ] 점검완료"

3.3 이 스크립트가 실제로 보는 범위

현재 스크립트는 다음 경로를 대상으로 한다.

/
/home
/var
/tmp
/usr
/opt

그리고 find에 -xdev 옵션을 사용한다.

find $TARGET_DIRS -xdev

따라서 다른 파일시스템으로 넘어가서 검색하지 않는다.

또한 결과를 최대 5개까지만 가져온다.

head -n 5

즉, U-15에서 WARN이 발생했다고 해서 고아 파일이 정확히 5개만 존재한다는 의미는 아니다.

스크립트 출력은 발견된 파일의 일부를 보여주는 용도이며, 실제 조치 전에는 전체 목록을 별도로 확인해야 한다.


3.4 60초 타임아웃도 점검 결과의 일부다

U-15는 대용량 서버에서 find 자체가 상당한 부하를 발생시킬 수 있다.

현재 스크립트는 EXEC_TIMEOUT 60을 사용하기 때문에 60초를 초과하면 점검을 중단하고 INFO를 출력한다.

따라서 다음 결과를 단순히 양호로 해석해서는 안 된다.

소유자 없는 파일 검색 중 응답 지연(60초 초과)이 발생하여 점검을 중단했습니다.

이 경우는 정상 확인이 아니라 자동점검 범위 내에서 확인을 완료하지 못한 상태로 보고 수동 점검이 필요하다.


3.5 수동 확인

전체 파일을 확인하려면 다음과 같이 실행할 수 있다.

find / -xdev \( -nouser -o -nogroup \) -ls 2>/dev/null

발견된 파일은 바로 삭제하지 않고 다음 정보를 먼저 확인한다.

ls -l <파일경로>
stat <파일경로>

그리고 해당 파일이 다음 중 어떤 성격인지 확인한다.

  • 애플리케이션 데이터
  • 로그
  • 임시 파일
  • 백업 파일
  • 패키지 관련 파일
  • 컨테이너 볼륨
  • 삭제된 사용자 계정의 잔여 파일

3.6 특히 컨테이너 환경은 별도 확인

Docker나 Podman 환경에서는 컨테이너 내부 UID/GID와 호스트 OS의 계정 정보가 일치하지 않을 수 있다.

따라서 /var/lib/docker, /var/lib/containers 등의 저장 영역에서 발견된 파일을 일반적인 로컬 파일과 동일하게 판단하면 오탐 가능성이 있다.

컨테이너 관련 경로는 별도의 컨테이너 보안점검 기준으로 관리하는 방법도 고려할 수 있다.


3.7 안전한 조치

먼저 발견 목록을 저장한다.

find / -xdev \( -nouser -o -nogroup \) 2>/dev/null > /root/orphan_files_list.txt

그 다음 파일의 업무상 용도를 확인한다.

정상적인 애플리케이션 파일이라면 적절한 계정으로 소유권을 변경할 수 있다.

chown root:root <파일_또는_디렉터리_경로>

반대로 명백하게 불필요한 임시 파일인 경우에도 즉시 rm -rf를 실행하기보다 백업 후 삭제하는 방법이 안전하다.

tar -czf /root/orphan_backup_$(date +%Y%m%d).tar.gz \
    -T /root/orphan_files_list.txt

삭제가 필요한 파일만 선별하여 처리한다.


4. U-16 — /etc/passwd는 왜 권한을 함부로 줄이면 안 되는가

/etc/passwd는 이름만 보면 비밀번호가 저장되는 파일처럼 보이지만 실제로는 계정명, UID, GID, 홈 디렉터리, 로그인 Shell 등의 계정 정보를 담고 있다.

이 파일에 일반 사용자의 쓰기 권한이 있다면 계정정보 변조를 통한 권한 상승으로 이어질 수 있다.

반대로 보안성을 높이겠다는 이유로 읽기 권한까지 과도하게 제한하면 일반 사용자와 시스템 서비스가 정상적으로 계정 정보를 조회하지 못하는 문제가 발생할 수 있다.

따라서 U-16은 “권한을 최대한 낮추는 것”이 목적이 아니라 적절한 권한을 유지하면서 비인가자의 변경을 막는 것이 핵심이다.


4.1 현재 자동 진단 스크립트

# [상세 해설] U-16 점검 항목 시작 알림
CODE "[ U-16 ] /etc/passwd 파일 소유자 및 권한 설정"

# [상세 해설] 파일 존재 여부 확인 후 소유자 및 권한 마스크 파싱
if [ -f /etc/passwd ]; then
    OWNER=$(ls -l /etc/passwd | awk '{print $3}')
    PERMS=$(ls -l /etc/passwd | awk '{print $1}')

    # [상세 해설] 그룹(5~7번째 글자) 및 타사용자(8~10번째 글자) 권한 필드 추출
    PERM_G=$(echo "$PERMS" | cut -c 5-7)
    PERM_O=$(echo "$PERMS" | cut -c 8-10)

    # [상세 해설] 소유자가 root이고 그룹 및 Other에 쓰기(w) 또는 실행(x) 권한이 없는지 판정
    if [ "$OWNER" == "root" ] && ! echo "$PERM_G" | grep -q "[wx]" && ! echo "$PERM_O" | grep -q "[wx]"; then
        OK "/etc/passwd 파일의 소유자가 root이고, 권한이 644 이하로 안전합니다." "소유자: $OWNER, 권한: $PERMS"
    else
        WARN "/etc/passwd 파일의 소유자가 root가 아니거나, 권한이 644를 초과합니다." "소유자: $OWNER, 권한: $PERMS"
    fi
else
    WARN "/etc/passwd 파일이 존재하지 않습니다." "파일 누락 또는 경로 다름"
fi

FINISH "[ U-16 ] 점검완료"

4.2 코드에서 실제로 확인하는 부분

이 스크립트는 다음 두 가지를 확인한다.

소유자

OWNER == root

Group 및 Other 권한

Group과 Other에 다음 권한이 있는지를 검사한다.

w
x

즉, 현재 스크립트는 Group과 Other에 쓰기 또는 실행 권한이 존재하는지를 확인한다.

따라서 단순히 파일 권한 숫자가 644인지 문자열로 비교하는 방식은 아니다.

예를 들어 640, 600, 400 등도 현재 조건에서는 Group과 Other에 쓰기·실행 권한이 없으면 조건을 만족할 수 있다.


4.3 수동 확인

현재 파일 상태는 다음과 같이 확인할 수 있다.

stat -c "%a %U:%G %n" /etc/passwd

일반 계정에서 계정정보를 정상적으로 조회할 수 있는지도 확인한다.

su - nobody -s /bin/bash -c "id"

운영 환경에 따라 nobody 계정의 Shell이나 로그인 정책이 다를 수 있으므로, 테스트 명령 자체가 실패했다고 해서 /etc/passwd 권한 문제로 단정해서는 안 된다.


4.4 권한을 600 또는 400으로 줄이는 것이 항상 좋은가?

그렇지 않다.

/etc/passwd는 시스템의 여러 프로그램이 계정 정보를 조회하는 데 사용된다.

따라서 단순히

chmod 400 /etc/passwd

처럼 권한을 강제로 낮추는 것은 실제 운영환경에서 예상하지 못한 문제를 만들 수 있다.

U-16에서 중요한 것은 비인가 사용자의 쓰기를 막는 것과 시스템이 필요한 계정 정보를 읽을 수 있도록 하는 것 사이의 균형이다.


4.5 안전한 조치

먼저 원본을 백업한다.

cp -p /etc/passwd /etc/passwd.bak_$(date +%Y%m%d)

현재 스크립트의 조치 방법은 다음과 같다.

chown root:root /etc/passwd
chmod 644 /etc/passwd

변경 후 확인한다.

stat -c "%a %U:%G %n" /etc/passwd
id nobody

5. U-17 — 시스템 시작 파일은 왜 별도로 봐야 하는가

U-17은 파일 권한 자체보다 “그 파일이 언제 실행되는가”가 중요한 항목이다.

시스템 부팅 과정에서 자동으로 실행되는 파일에 일반 사용자가 내용을 변경할 수 있다면, 공격자는 해당 파일에 명령을 삽입한 후 시스템 재부팅을 기다리는 방식으로 권한 상승을 시도할 수 있다.

특히 과거 SysV init 기반 시스템뿐 아니라 현재의 systemd 환경까지 고려해야 한다.


5.1 현재 스크립트의 검사 범위

# [상세 해설] U-17 점검 항목 시작 알림
CODE "[ U-17 ] 시스템 시작 스크립트 권한 설정"

# [상세 해설] SysV init 및 systemd 서비스 유닛 경로를 점검 대상 리스트에 등록
START_SCRIPTS="/etc/rc.d /etc/rc*.d /etc/init.d /etc/rc.local /etc/rc.sysinit /etc/systemd/system"
VULN_SCRIPTS=""

# [상세 해설] 각 디렉터리를 순회하며 Other 사용자에게 쓰기 권한(-perm -002)이 부여된 파일 탐색
for dir in $START_SCRIPTS; do
    if [ -d "$dir" ] || [ -f "$dir" ]; then
        RES=$(find "$dir" -type f -perm -002 2>/dev/null | head -n 3 | xargs)
        if [ -n "$RES" ]; then
            VULN_SCRIPTS="$VULN_SCRIPTS $RES"
        fi
    fi
done

# [상세 해설] 취약 파일 검출 결과에 따른 출력
if [ -n "$VULN_SCRIPTS" ]; then
    WARN "타사용자 쓰기 권한이 부여된 시작 스크립트가 존재합니다." "취약 스크립트(일부): [ $VULN_SCRIPTS ]"
else
    OK "주요 시스템 시작 스크립트에 비인가자 쓰기 권한이 부여되지 않았습니다." "점검 경로 내 취약 파일 없음"
fi

FINISH "[ U-17 ] 점검완료"

5.2 여기서 중요한 스크립트의 한계

U-17의 원래 요약표에는 시작 스크립트의 소유자가 root이고 Other 쓰기 권한이 없는 경우를 양호 기준으로 설명하고 있다.

하지만 현재 자동화 코드는 실제로 다음 조건을 검색한다.

find "$dir" -type f -perm -002

-perm -002는 Other 사용자에게 쓰기 권한이 있는 파일을 찾는 조건이다.

따라서 현재 스크립트는 파일 소유자가 root인지까지 직접 확인하지 않는다.

이 부분은 포스팅에서도 명확히 구분해 두는 것이 좋다.

현재 자동화 스크립트는 시작 파일의 Other 쓰기 권한을 검사한다. 파일 소유자까지 자동 판정하는 로직은 포함되어 있지 않으므로 소유권은 별도의 수동 확인이 필요하다.

이렇게 작성하면 실제 스크립트보다 넓은 범위를 검사한다고 오해시키지 않는다.


5.3 수동 점검

다음 명령으로 현재 검사 대상에서 Other 쓰기 권한이 있는 파일을 확인할 수 있다.

find /etc/rc.d /etc/rc*.d /etc/init.d /etc/rc.local /etc/systemd/system \
    -type f -perm -002 -ls 2>/dev/null

파일 소유권은 별도로 확인한다.

find /etc/rc.d /etc/init.d /etc/systemd/system \
    -type f -ls 2>/dev/null

systemd 환경에서는 서비스 파일이 실제로 어디에서 제공되는지도 함께 확인할 필요가 있다.

현재 스크립트는 /usr/lib/systemd/system을 검사하지 않으므로 이 경로의 서비스 파일까지 확인하려면 별도의 수동 점검이 필요하다.


5.4 안전한 조치

먼저 관련 파일을 백업한다.

tar -czf /root/init_scripts_backup_$(date +%Y%m%d).tar.gz \
    /etc/rc.d /etc/init.d /etc/systemd/system 2>/dev/null

Other 쓰기 권한을 제거한다.

find /etc/rc.d /etc/rc*.d /etc/init.d /etc/rc.local /etc/systemd/system \
    -type f -exec chmod o-w {} + 2>/dev/null

소유권을 변경해야 하는 파일이라면 업무상 소유 관계를 먼저 확인한 후 적용한다.

현재 조치 스크립트에서는 다음과 같이 root 소유로 변경한다.

find /etc/rc.d /etc/rc*.d /etc/init.d /etc/rc.local /etc/systemd/system \
    -type f -exec chown root:root {} + 2>/dev/null

systemd 설정을 변경한 경우에는 다음 명령으로 데몬 설정을 다시 읽도록 한다.

systemctl daemon-reload

단, 모든 서비스 파일의 소유권을 일괄적으로 변경하는 작업은 운영환경에서 반드시 대상 파일을 확인한 후 적용해야 한다.


6. U-18 — /etc/shadow는 권한 숫자만 보면 안 되는 이유

/etc/shadow는 비밀번호 해시와 계정의 비밀번호 관련 정보를 포함하는 핵심 인증 파일이다.

따라서 일반 사용자가 내용을 읽거나 변경할 수 있는 상태라면 심각한 보안 문제가 발생할 수 있다.

그러나 /etc/shadow는 Linux 배포판에 따라 소유 그룹과 권한 구성이 다를 수 있기 때문에, 단순히 400이 아니면 모두 취약하다고 판단하는 것은 위험하다.

현재 U-18 스크립트도 이 차이를 고려하여 400/000과 600/640을 서로 다르게 처리한다.


6.1 자동 진단 스크립트

# [상세 해설] U-18 점검 항목 시작 알림
CODE "[ U-18 ] /etc/shadow 파일 소유자 및 권한 설정"

# [상세 해설] shadow 파일의 소유자와 10자리 권한 마스크 파싱
if [ -f /etc/shadow ]; then
    OWNER=$(ls -l /etc/shadow | awk '{print $3}')
    PERMS=$(ls -l /etc/shadow | awk '{print $1}' | cut -c 1-10)

    # [상세 해설] KISA 기준 400(r--------) 및 최신 OS 기본값 000(----------)인 경우 양호 판정
    if [ "$OWNER" == "root" ] && [[ "$PERMS" == "-r--------" || "$PERMS" == "----------" ]]; then
        OK "/etc/shadow 파일 소유자가 root이고, 권한이 400 이하로 안전합니다." "소유자: $OWNER, 권한: $PERMS"

    # [상세 해설] 일부 OS의 기본값인 640/600에 대한 정보성 처리
    elif [ "$OWNER" == "root" ] && [[ "$PERMS" == "-rw-------" || "$PERMS" == "-rw-r-----" ]]; then
        INFO "/etc/shadow 파일 권한이 600 또는 640입니다." "Linux 환경 등 일부 OS에서는 600/640이 기본값이나 가이드 기준(400) 초과"

    else
        WARN "/etc/shadow 파일의 권한 또는 소유자가 취약합니다. (권고: root, 400 이하)" "소유자: $OWNER, 권한: $PERMS"
    fi
else
    INFO "/etc/shadow 파일이 존재하지 않습니다." "AIX의 /etc/security/passwd 등 다른 인증 체계 확인 요망"
fi

FINISH "[ U-18 ] 점검완료"

6.2 스크립트 결과를 어떻게 해석할 것인가

현재 스크립트에서는 다음과 같이 구분한다.

소유자권한스크립트 결과

root 400 OK
root 000 OK
root 600 INFO
root 640 INFO
root가 아님 기타 WARN
파일 없음 - INFO

따라서 INFO가 출력됐다고 해서 즉시 권한을 400으로 변경해야 하는 것은 아니다.

특히 root:shadow 640과 같은 배포판별 기본 구성은 현재 시스템의 인증 구조와 함께 확인해야 한다.


6.3 실제 파일 상태 확인

stat -c "%a %U:%G %n" /etc/shadow

예를 들어 다음과 같은 결과라면,

640 root:shadow /etc/shadow

단순히 400으로 변경하기 전에 해당 시스템에서 shadow 그룹이 어떻게 사용되는지 확인해야 한다.


6.4 인증 기능 정상 여부 확인

파일 권한 변경 후에는 인증 기능까지 확인하는 것이 중요하다.

pwck -r /etc/shadow

또한 테스트 가능한 환경에서는 실제 사용자 비밀번호 변경 및 로그인 동작까지 확인해야 한다.


6.5 안전한 조치

변경 전 백업한다.

cp -p /etc/shadow /etc/shadow.bak_$(date +%Y%m%d)

RHEL/CentOS/Rocky 계열 등 현재 운영환경의 정책이 root:root, 400을 사용하는 경우 다음과 같이 조치할 수 있다.

chown root:root /etc/shadow
chmod 400 /etc/shadow

반대로 Ubuntu/Debian 환경에서 기존 인증 구조가 root:shadow, 640을 사용하는 경우에는 해당 구성을 무조건 400으로 변경하기보다 현재 시스템의 인증 구성과 패키지 기본 정책을 확인해야 한다.

원문에서 제시한 환경별 예시는 다음과 같다.

# Ubuntu/Debian 환경에서 필요한 경우
chown root:shadow /etc/shadow
chmod 640 /etc/shadow

변경 후에는 다음과 같이 무결성을 확인한다.

pwck -r

7. 다섯 항목을 점검할 때 특히 주의할 부분

U-14~U-18은 단순히 취약 → 명령어 실행으로 끝내면 안 되는 항목이 많다.

U-14

PATH에서 .을 발견했다면 어떤 설정 파일에서 추가됐는지부터 확인한다.

U-15

고아 파일을 발견했다고 바로 삭제하지 않는다.

애플리케이션, 컨테이너, 로그 등의 정상적인 운영 파일일 수 있다.

U-16

/etc/passwd의 권한을 보안 강화 목적으로 과도하게 제한하지 않는다.

시스템에서 필요한 읽기 기능까지 차단될 수 있다.

U-17

Other 쓰기 권한뿐 아니라 실제 소유자와 서비스 파일의 역할을 함께 확인한다.

현재 자동화 스크립트는 소유자를 자동 판정하지 않는다.

U-18

/etc/shadow는 배포판별 기본 권한과 인증 구조를 확인한 후 조치한다.

특히 640을 발견했다고 무조건 400으로 변경하는 방식은 피하는 것이 좋다.


8. 자동화 스크립트의 검사 범위와 한계

자동화 스크립트는 많은 서버를 동일한 기준으로 빠르게 검사할 수 있다는 장점이 있다.

하지만 U-14~U-18에서는 스크립트가 검사하는 범위와 실제 시스템의 전체 보안 상태가 동일하지 않다.

U-14

현재 $PATH만 검사한다.

/etc/profile.d/*.sh, /etc/environment 등 PATH가 구성되는 모든 파일을 직접 추적하지 않는다.

U-15

/, /home, /var, /tmp, /usr, /opt를 대상으로 -xdev 방식으로 검색하며, 60초 초과 시 중단한다.

대용량 저장소나 컨테이너 저장소가 있는 서버에서는 점검 결과가 제한될 수 있다.

U-16

/etc/passwd의 소유자와 Group/Other 권한을 검사한다.

현재 코드에서는 파일 권한 숫자를 직접 644와 비교하는 방식이 아니라 Group과 Other에 w/x 권한이 있는지를 확인한다.

U-17

현재 코드에서는 시작 관련 경로의 Other 쓰기 권한을 검사한다.

파일 소유자가 root인지 여부까지 자동으로 검사하지 않는다.

U-18

400/000은 OK, 600/640은 INFO로 처리한다.

따라서 실제 운영환경에서는 배포판과 인증 구성까지 확인해야 한다.


9. 정밀 점검이 필요한 경우의 개선 예시

현재 자동화 스크립트의 검사 범위를 확대하려면 다음과 같은 방법을 사용할 수 있다.

9.1 U-14 — 설정 파일까지 PATH 검색 범위 확대

VULN_PATH_CONF=$(grep -E -H "PATH=.*(\.:|::|:\.|\:\$)" \
    /etc/profile /etc/profile.d/*.sh /etc/environment 2>/dev/null |
    grep -v "^#")

if [ -n "$VULN_PATH_CONF" ]; then
    WARN "설정 파일 내 안전하지 않은 PATH 선언이 발견되었습니다." \
        "내역: $VULN_PATH_CONF"
fi

현재 $PATH만 보는 방식에서 PATH를 구성하는 설정 파일까지 확인하는 방식으로 범위를 확대하는 예시다.


9.2 U-18 — OS별 /etc/shadow 권한 확인

SHADOW_OWNER=$(stat -c "%U" /etc/shadow)
SHADOW_GROUP=$(stat -c "%G" /etc/shadow)
SHADOW_PERM=$(stat -c "%a" /etc/shadow)

if [[ "$SHADOW_OWNER" == "root" ]] && \
   [[ "$SHADOW_PERM" =~ ^(000|400)$ ]]; then

    OK "/etc/shadow 권한이 매우 안전합니다." \
       "권한: $SHADOW_PERM ($SHADOW_OWNER:$SHADOW_GROUP)"

elif [[ "$SHADOW_OWNER" == "root" && \
        "$SHADOW_GROUP" == "shadow" && \
        "$SHADOW_PERM" == "640" ]]; then

    OK "/etc/shadow가 데비안/우분투 표준 권한(640, root:shadow)에 부합합니다." \
       "권한: $SHADOW_PERM"

else
    WARN "/etc/shadow 권한 및 소유자가 가이드라인에 미달합니다." \
         "권한: $SHADOW_PERM ($SHADOW_OWNER:$SHADOW_GROUP)"
fi

이 방식은 단순히 400만을 양호 기준으로 보는 것이 아니라 소유자·그룹·권한을 함께 판단하는 방식이다.


10. U-14~U-18 자동화 점검을 실제 서버에 적용하는 방법

이번 영역은 다음 순서로 점검하면 효율적이다.

1단계 — 자동 진단

먼저 전체 스크립트를 실행하여 U-14~U-18의 결과를 확인한다.

2단계 — 결과가 나온 파일을 직접 확인

자동화 결과만 보고 바로 조치하지 않고 해당 파일의 실제 상태를 확인한다.

ls -l <파일>
stat <파일>

3단계 — 운영 영향 확인

특히 다음 환경을 별도로 확인한다.

  • Docker/Podman
  • NFS 및 별도 파일시스템
  • systemd
  • LDAP/SSSD
  • CI/CD Agent
  • 애플리케이션 서비스 계정
  • Ubuntu/Debian의 shadow 그룹 구성

4단계 — 원본 백업

권한이나 소유권을 변경하기 전에 원본 파일을 백업한다.

5단계 — 필요한 항목만 조치

자동화 결과에 포함된 모든 파일을 일괄 변경하지 않고, 실제 취약성이 확인된 대상만 조치한다.

6단계 — 변경 후 재점검

동일한 스크립트를 다시 실행하여 변경 결과를 확인한다.

7단계 — 서비스 정상 여부 확인

파일 권한 변경 이후에는 단순히 [양호]가 출력되는 것만 확인하지 않는다.

사용자 로그인, 애플리케이션 서비스, systemd 서비스, 인증 기능 등 해당 파일과 연관된 실제 기능이 정상적으로 동작하는지 확인하는 과정까지 점검의 일부로 보는 것이 안전하다.


주의사항

본 포스팅의 스크립트 및 조치 방법은 Linux 시스템의 파일 및 디렉터리 관리 보안점검과 보안 강화를 목적으로 작성되었다. Linux 배포판, 버전, 파일시스템 구성, 설치된 서비스 및 인증 구성에 따라 점검 대상과 적용 방식이 다를 수 있다.

특히 /etc/passwd, /etc/shadow, 시스템 시작 스크립트의 권한 및 소유권을 변경하거나 root 계정의 PATH를 수정할 경우 사용자 인증, 서비스 실행 및 시스템 부팅에 영향을 줄 수 있으므로 운영 서버에 적용하기 전에 반드시 테스트 환경에서 검증한 후 적용해야 한다.

소유자가 없는 파일이나 디렉터리를 발견하더라도 즉시 삭제하지 말고 해당 파일의 업무상 용도와 애플리케이션·컨테이너 환경에서의 사용 여부를 먼저 확인해야 한다. 또한 /etc/shadow는 Linux 배포판에 따라 기본 소유 그룹과 권한이 다를 수 있으므로 현재 시스템의 인증 구성과 함께 확인한 후 조치해야 한다.

스크립트 실행 및 설정 변경으로 인해 발생하는 시스템 장애에 대해서는 사용 환경에 맞는 사전 검증이 필요하다.


함께 보면 좋은 글

Linux 보안취약점 점검 자동화 스크립트 공통 함수 및 환경 설정

Linux 보안취약점 점검 스크립트를 여러 항목에서 공통으로 사용하기 위한 함수와 환경 설정에 대한 내용은 별도의 글에서 확인할 수 있다.

자동화 스크립트 공통 함수 및 환경 설정

반응형