미니 프로젝트

[Ansible 프로젝트] 리눅스 서버 취약점 점검 도구

종바깅 2021. 5. 7. 17:09

IaC 미니프로젝트 - Ansible

미니프로젝트 주제

  • 주요정보통신기반시설_기술적_취약점_분석_평가_방법_상세가이드 중 UNIX/LINUX 항목에 대한 취약점 점검 도구
  • 범위: 주요정보통신기반시설_기술적_취약점_분석_평가_방법_상세가이드 문서 내 UNIX 서버 항목 중 중요도 '상'에 해당하는 항목 중 10개 선정

목표

  1. 중요도 '상' 항목 총 43개 중 10개를 임의로 선정 (작성하기 편한 것으로)
  2. 동작방식
    • 각 취약점 진단항목 별 점검을 수행할 수 있는 스크립트 작성
    • 취약점 항목 하나당 하나의 스크립트 파일로 작성
      • ex) u01.sh, u02.sh, u03.sh
    • 또는 진단 항목 중 ansible playbook을 작성하여 진단가능한 항목에 대하여 검토
    • 스크립트는 ansible을 통해 점검대상 호스트에 배포하여 실행하고, 결과 취합 또한 ansible을 통해 이루어지도록 작성
    • 스크립트 실행 시 진단 항목별 점검방식에 따라 점검을 수행하여 결과는 양호/취약으로 판단하도록 작성
    • 스크립트의 실행결과는 각 호스트의 /tmp/경로에 '취약점항목:취약여부' 형태로 저장된 후 취합되도록

inventory

[webservers]
managed1.example.local

[dbservers]
managed2.example.local

[allservers:children]
webservers
dbservers

ansible.cfg

[defaults]
inventory = ./inventory
remote_user = user
ask_pass = false

[privilege_escalation]
become = false
become_method = sudo
become_user = root
become_ask_pass = false

스크립트 목록

u01.sh : root 계정 원격 접속 제한 스크립트
u02.sh : 패스워드 복잡성 설정
u03.sh : 계정 잠금 임계값 설정
u04.sh : 패스워드 파일 보호
u06.sh : 파일 및 디렉터리 소유자 설정
u07.sh : /etc/passwd 파일 소유자 및 권한 설정
u08.sh : /etc/shadow 파일 소유자 및 권한 설정
u09.sh : /etc/hosts 파일 소유자 및 권한 설정
u12.sh : /etc/services 파일 소유자 및 권한 설정
u26.sh : automountd 제거 스크립트

- u01.sh

#!/bin/bash

REPORT=/tmp/report.txt
grep -r '^PermitRootLogin no' /etc/ssh/sshd_config  >> /dev/null
if [[ "$?" -eq 0 ]]
then

    if [ -f "$REPORT" ] ; then

    echo -e "U01\tGOOD\n" >> /tmp/report.txt

    else

    echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
    echo -e "U01\tGOOD\n" >> /tmp/report.txt
    fi
else

    if [ -f "$REPORT" ] ; then

    echo -e "U01\tFAIL\n" >> /tmp/report.txt

    else

    echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
    echo -e "U01\tFAIL\n" >> /tmp/report.txt

    fi
fi

- u02.sh

#!/bin/bash

REPORT=/tmp/report.txt

MIN=`awk -F" " '$1 ~ /^minlen/ {print $3}' /etc/security/pwquality.conf`
LCD=`awk -F" " '$1 ~ /^lcredit/ {print $3}' /etc/security/pwquality.conf`
UCD=`awk -F" " '$1 ~ /^ucredit/ {print $3}' /etc/security/pwquality.conf`
DCD=`awk -F" " '$1 ~ /^dcredit/ {print $3}' /etc/security/pwquality.conf`
OCD=`awk -F" " '$1 ~ /^ocredit/ {print $3}' /etc/security/pwquality.conf`

 if [[ $MIN -gt 8 ]] &&[ $LCD -eq 1 ] && [ $UCD -eq -1 ] && [ $DCD -eq -1 ] && [ $OCD -eq -1 ] 
 then
    if [ -f "$REPORT" ] ; then

    echo -e "U02\tGOOD\n" >> /tmp/report.txt

    else

    echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
    echo -e "U02\tGOOD\n" >> /tmp/report.txt

    fi
 else
     if [ -f "$REPORT" ] ; then

    echo -e "U02\tFAIL\n" >> /tmp/report.txt

    else

    echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
    echo -e "U02\tFAIL\n" >> /tmp/report.txt

    fi
 fi

- u03.sh

#!/bin/bash

REPORT=/tmp/report.txt

FILE1=/etc/pam.d/system-auth

PAM_MODULE=pam_tally.so

LINE1=`cat $FILE1 | egrep -v '(^#|^$)' | grep $PAM_MODULE`

if [ $? -ne 0 ] ; then

        if [ -f "$REPORT" ] ; then

        echo -e "U03\tFAIL\n" >> /tmp/report.txt

        else

        echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
        echo -e "U03\tFAIL\n" >> /tmp/report.txt

        fi
else

    LINE2=`echo $LINE1 | cut -d ' ' -f 4-`

    for VAR in `echo $LINE2`

    do

        FIRST=`echo $VAR | awk '{print $1}'`

        CHECK1=`echo $FIRST | awk -F= '{print $1}'`

        CHECK2=`echo $FIRST | awk -F= '{print $2}'`

        case $CHECK1 in

            deny) if [ $CHECK -lt 5 ] ; then

                          if [ -f "$REPORT" ] ; then

                            echo -e "U03\tGOOD\n" >> /tmp/report.txt

                            else

                            echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
                            echo -e "U03\tGOOD\n" >> /tmp/report.txt

                            fi

                  else

                          if [ -f "$REPORT" ] ; then

                            echo -e "U03\tFAIL\n" >> /tmp/report.txt

                            else

                            echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
                            echo -e "U03\tFAIL\n" >> /tmp/report.txt

                            fi

                  fi ;;

            *) ;;

        esac

        shift

    done

fi

- u04.sh

#!/bin/bash

REPORT=/tmp/report.txt

FILE1=/etc/passwd

FILE2=/etc/shadow



if [ -f $FILE1 -a -f $FILE2 ] ; then

    if [ -f "$REPORT" ] ; then

    echo -e "U04\tGOOD\n" >> /tmp/report.txt

    else

    echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
    echo -e "U04\tGOOD\n" >> /tmp/report.txt

    fi
else

    if [ -f "$REPORT" ] ; then

    echo -e "U04\tFAIL\n" >> /tmp/report.txt

    else

    echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
    echo -e "U04\tFAIL\n" >> /tmp/report.txt

    fi
fi

- u06.sh

#!/bin/bash

REPORT=/tmp/report.txt

nouser_list=`find / -xdev -nouser -print 2>/dev/null > /nouserlist.txt`
nogroup_list=`find / -xdev -nogroup -print 2>/dev/null > /nogrouplist.txt`

if [ -s "/nouserlist.txt" -a -s "/nogrouplist.txt" ]; then
     if [ -f "$REPORT" ] ; then

    echo -e "U06\tFAIL\n" >> /tmp/report.txt

    else

    echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
    echo -e "U06\tFAIL\n" >> /tmp/report.txt

    fi
elif [ -s "/nouserlist.txt" -a ! -s "/nogrouplist.txt" ]; then
    if [ -f "$REPORT" ] ; then

    echo -e "U06\tFAIL\n" >> /tmp/report.txt

    else

    echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
    echo -e "U06\tFAIL\n" >> /tmp/report.txt

    fi

elif [ ! -s "/nouserlist.txt" -a -s "/nogrouplist.txt"  ]; then
    if [ -f "$REPORT" ] ; then

    echo -e "U06\tFAIL\n" >> /tmp/report.txt

    else

    echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
    echo -e "U06\tFAIL\n" >> /tmp/report.txt

    fi

else
    if [ -f "$REPORT" ] ; then

    echo -e "U06\tGOOD\n" >> /tmp/report.txt

    else

    echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
    echo -e "U06\tGOOD\n" >> /tmp/report.txt

    fi
fi

- u07.sh

#!/bin/bash

REPORT=/tmp/report.txt

find /etc/passwd -perm 644 > /dev/null 2>&1

if [ $? -eq 0 ] ; then
    if [ -f "$REPORT" ] ; then

    echo -e "U07\tGOOD\n" >> /tmp/report.txt

    else

    echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
    echo -e "U07\tGOOD\n" >> /tmp/report.txt

    fi
else

    if [ -f "$REPORT" ] ; then

    echo -e "U07\tFAIL\n" >> /tmp/report.txt

    else

    echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
    echo -e "U07\tFAIL\n" >> /tmp/report.txt

    fi
fi

- u08.sh

#!/bin/bash

REPORT=/tmp/report.txt

find /etc/shadow -perm 400 > /dev/null 2>&1

if [ $? -eq 0 ] ; then
    if [ -f "$REPORT" ] ; then

    echo -e "U07\tGOOD\n" >> /tmp/report.txt

    else

    echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
    echo -e "U07\tGOOD\n" >> /tmp/report.txt

    fi
else

    if [ -f "$REPORT" ] ; then

    echo -e "U07\tFAIL\n" >> /tmp/report.txt

    else

    echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
    echo -e "U07\tFAIL\n" >> /tmp/report.txt

    fi
fi

- u09.sh

#!/bin/bash

REPORT=/tmp/report.txt

FILE=/etc/hosts

TMP1=`ls -l $FILE | awk '{print $3}'`

if [ $TMP1 == 'root' ] ; then

    find /etc/hosts -perm 600 > /dev/null 2>&1

    if [ $? -eq 0 ] ; then
        if [ -f "$REPORT" ] ; then

        echo -e "U09\tGOOD\n" >> /tmp/report.txt

        else

        echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
        echo -e "U09\tGOOD\n" >> /tmp/report.txt

        fi
    else
        if [ -f "$REPORT" ] ; then

        echo -e "U09\tFAIL\n" >> /tmp/report.txt

        else

        echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
        echo -e "U09\tFAIL\n" >> /tmp/report.txt

        fi
    fi

else

    if [ -f "$REPORT" ] ; then

    echo -e "U09\tFAIL\n" >> /tmp/report.txt

    else

    echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
    echo -e "U09\tFAIL\n" >> /tmp/report.txt

    fi

fi

- u12.sh

#!/bin/bash

REPORT=/tmp/report.txt

FILE=/etc/services

TMP1=`ls -l $FILE | awk '{print $3}'`

if [ $TMP1 == 'root' ] || [ $TMP1 == 'bin' ] || [ $TMP1 == 'sys' ]; then

    find /etc/services -perm 644 > /dev/null 2>&1

    if [ $? -eq 0 ] ; then
        if [ -f "$REPORT" ] ; then

        echo -e "U12\tGOOD\n" >> /tmp/report.txt

        else

        echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
        echo -e "U12\tGOOD\n" >> /tmp/report.txt

        fi
    else
        if [ -f "$REPORT" ] ; then

        echo -e "U12\tFAIL\n" >> /tmp/report.txt

        else

        echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
        echo -e "U12\tFAIL\n" >> /tmp/report.txt

        fi
    fi

else

    if [ -f "$REPORT" ] ; then

    echo -e "U12\tFAIL\n" >> /tmp/report.txt

    else

    echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
    echo -e "U12\tFAIL\n" >> /tmp/report.txt

    fi

fi

- u26.sh

#!/bin/bash

REPORT=/tmp/report.txt

systemctl status autofs.service >> afs.txt

CHK=`awk -F" " '$1 ~ /Active/ {print $2}' afs.txt`

if [ "$CHK"="inactive" ]
then

    if [ -f "$REPORT" ] ; then

    echo -e "U26\tGOOD\n" >> /tmp/report.txt

    else

    echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
    echo -e "U26\tGOOD\n" >> /tmp/report.txt

    fi
else

    if [ -f "$REPORT" ] ; then

    echo -e "U26\tFAIL\n" >> /tmp/report.txt

    else

    echo -e "   RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
    echo -e "U26\tFAIL\n" >> /tmp/report.txt

    fi
fi

rm afs.txt

playbook

---
- name: execute a script
  hosts: allservers
  tasks:
    - name: copy_file # 호스트에서 노드로 파일복사
      copy: src={{ item }} dest=/home/user mode=0777
      loop:
        - u01.sh
        - u02.sh
        - u03.sh
        - u04.sh
        - u06.sh
        - u07.sh
        - u08.sh
        - u09.sh
        - u12.sh
        - u26.sh

    - name: run_script # 스크립트 파일 실행
      command: sh /home/user/{{ item }}
      loop:
        - u01.sh
        - u02.sh
        - u03.sh
        - u04.sh
        - u06.sh
        - u07.sh
        - u08.sh
        - u09.sh
        - u12.sh
        - u26.sh

    - name: delete_script
      file:
        path: /home/user/{{ item }}
        state: absent
      loop:
        - u01.sh
        - u02.sh
        - u03.sh
        - u04.sh
        - u06.sh
        - u07.sh
        - u08.sh
        - u09.sh
        - u12.sh
        - u26.sh

플레이북 실행결과

  • 스크립트 복사

  • 스크립트 실행

  • 스크립트 파일 제거

호스트에서 report 확인

결론

CentOS7 환경에서 스크립트와 ansible을 기반으로 기술적 취약점 진단을 정해진 호스트에 배포하고 실행하는 일련의 작업들을 수행하였다. 이 프로젝트를 통해 보안을 위해 점검해야 할 부분이 어떤 것들이 있는지 조금은 이해할 수 있었다, 또한 점검하는 스크립트를 작성하고 ansible 플레이북을 작성하는 과정에서 쉘 프로그래밍과 ansible 활용에도 익숙해진 것 같다.