Debian Oval auto check

วันก่อนเขียนสคริปต์ตรวจสอบ Debian oval อัตโนมัติเขียนเสร็จ อ่ะ ไหนๆ สมัครโปรของ เจ๊มินิ (gemini.google.com) แล้ว ให้เจ๊ช่วยขัดเกลาสคริปต์ bash script บ้านๆ เสร็จปุบ ดูหรูไฮ… ทันตาเห็น จากสคริปต์ พบว่าเขียน bash ยังไงให้ถูก ? โวะเพิ่งรู้ว่ามีนั่นนี่โน่น…

  • สร้างสคริปต์ gem-oval-check.sh มีข้อความว่า
gem-oval-check.sh
#!/usr/bin/env bash
# OVAL Updater & Parser - Final Fixed Version 
# Description: Downloads Debian OVAL definitions, checks for CVEs, generates links, and sends an email report.

# -------------------------
# 1. Configuration & Variables
# -------------------------
readonly DEBIAN_CODENAME=$(lsb_release -c | awk '{print $2}')
readonly DEBIAN_RELEASE=$(cat /etc/debian_version)
readonly SERVER_HOSTNAME=$(hostname -f)
readonly SERVER_IP=$(hostname -I | awk '{print $1}')
readonly URL="https://www.debian.org/security/oval/oval-definitions-${DEBIAN_CODENAME}.xml.bz2"
readonly DEST_BZ2="oval-definitions-${DEBIAN_CODENAME}.xml.bz2"
readonly DEST_XML="oval-definitions-${DEBIAN_CODENAME}.xml"
readonly TMP_BZ2="/tmp/${DEST_BZ2}"
readonly RESULT_XML="oval_result.xml"
readonly ID_FILE="/tmp/oval_ids_${DEBIAN_CODENAME}"
readonly MSG_FILE="/tmp/oval_messages_${DEBIAN_CODENAME}"
readonly CVE_REPORT="/tmp/oval_cve_titles_parsed_${DEBIAN_CODENAME}"

readonly REPORT_TO="***************YOUR E-MAIL ADDRESS******************"
SUBJECT="OVAL Report ${SERVER_HOSTNAME} $(date +%F)"

# -------------------------
# 2. Functions
# -------------------------

# Function for clean up temporary files
cleanup() {
    rm -f "${ID_FILE}" "${MSG_FILE}" "${CVE_REPORT}"
}
trap cleanup EXIT

# Function to generate URL based on the security ID (CVE or DSA)
generate_url() {
    local id_string=$1
    if [[ "$id_string" =~ ^CVE-[0-9]{4}-[0-9]+$ ]]; then
        echo "https://cve.mitre.org/cgi-bin/cvename.cgi?name=${id_string}"
    elif [[ "$id_string" =~ ^DSA-[0-9]+-[0-9]+$ ]]; then
        echo "https://www.debian.org/security/${id_string}"
    else
        echo "(No Link Available)"
    fi
}

# Function to generate and send email
send_report() {
    local exit_status=$1
    local message_type=$2 # 'SUCCESS', 'INFO', 'ERROR', 'CVE_FOUND'
    
    # กำหนด SUBJECT ด้วยข้อความธรรมดาแทน Emoji/Non-ASCII
    local status_prefix=""
    case "${message_type}" in
        "SUCCESS")
            status_prefix="[OVAL OK] Not Found"
            ;;
        "INFO")
            status_prefix="[OVAL INFO] Not Found (Old File Check)"
            ;;
        "ERROR")
            status_prefix="[OVAL ERROR]"
            ;;
        "CVE_FOUND")
            status_prefix="[OVAL ALERT] CVE Found!"
            ;;
    esac
    
    local final_subject="${status_prefix} - OVAL Report ${SERVER_HOSTNAME} $(date +%F)"

    # FIX: เพิ่ม IP Address ในส่วนหัวของรายงาน
    {
        echo "Host Name: ${SERVER_HOSTNAME}"
        echo "IP Address: ${SERVER_IP}"
    } > "${MSG_FILE}"

    case "${message_type}" in
        "SUCCESS")
            echo "**********************" >> "${MSG_FILE}"
            echo "* Congratulations!  *" >> "${MSG_FILE}"
            echo "**********************" >> "${MSG_FILE}"
            echo "Distribution: ${DEBIAN_CODENAME} Release: ${DEBIAN_RELEASE}" >> "${MSG_FILE}"
            echo "No CVE found" >> "${MSG_FILE}"
            echo "No definitions with result=true found" >> "${MSG_FILE}"
            ;;
        "INFO")
            echo "**********************" >> "${MSG_FILE}"
            echo "* OVAL Check Ran   *" >> "${MSG_FILE}"
            echo "**********************" >> "${MSG_FILE}"
            echo "File not modified (HTTP 304). Check performed on local file." >> "${MSG_FILE}"
            echo "Distribution: ${DEBIAN_CODENAME} Release: ${DEBIAN_RELEASE}" >> "${MSG_FILE}"
            echo "No CVE found" >> "${MSG_FILE}"
            ;;
        "ERROR")
            echo "**********************" >> "${MSG_FILE}"
            echo "* ERROR!       *" >> "${MSG_FILE}"
            echo "**********************" >> "${MSG_FILE}"
            echo "$3" >> "${MSG_FILE}"
            ;;
        "CVE_FOUND")
            echo "**********************" >> "${MSG_FILE}"
            echo "* CVE Found!!!   *" >> "${MSG_FILE}"
            echo "**********************" >> "${MSG_FILE}"
            echo "Distribution: ${DEBIAN_CODENAME} Release: ${DEBIAN_RELEASE}" >> "${MSG_FILE}"
            echo "--------------------------------------------------------" >> "${MSG_FILE}"
            echo "Package | Security ID | URL" >> "${MSG_FILE}"
            echo "--------------------------------------------------------" >> "${MSG_FILE}"
            cat "${CVE_REPORT}" >> "${MSG_FILE}" 
            ;;
    esac

    if ! mail -s "${final_subject}" "${REPORT_TO}" < "${MSG_FILE}"; then
        echo "🚨 ERROR: Failed to send email report to ${REPORT_TO}" >&2
    fi
    echo "Report sent to ${REPORT_TO}. Exiting with status ${exit_status}."
    exit "${exit_status}"
}

# -------------------------
# 3. Main Logic
# -------------------------

echo "🚀 Starting OVAL check for Debian ${DEBIAN_CODENAME} (${DEBIAN_RELEASE}) on ${SERVER_HOSTNAME} (${SERVER_IP})..."

STATUS=$(curl -s -f -w "%{http_code}" -z "${TMP_BZ2}" -o "${TMP_BZ2}" "${URL}" || echo "999")

case "${STATUS}" in
    200)
        echo "✅ New/updated file downloaded (HTTP 200). Processing..."
        
        rm -f "${DEST_XML}" "${RESULT_XML}"
        cp "${TMP_BZ2}" "${DEST_BZ2}"
        
        ;&

    304)
        if [ "$STATUS" -eq 304 ]; then
            echo "ℹ️ OVAL file not modified (HTTP 304). Running check on existing file..."
        fi
        
        if [ ! -f "${DEST_XML}" ] && [ ! -f "${DEST_BZ2}" ]; then
            if [ -f "${TMP_BZ2}" ]; then
                echo "⚠️ Local file missing. Using cached file for check."
                cp "${TMP_BZ2}" "${DEST_BZ2}"
            else
                send_report 1 "ERROR" "Cannot process OVAL check. Local files missing (HTTP ${STATUS})."
            fi
        fi

        if [ ! -f "${DEST_XML}" ]; then
            if ! bunzip2 -f "${DEST_BZ2}"; then
                send_report 1 "ERROR" "Failed to decompress OVAL file: bunzip2 failed."
            fi
        fi

        echo "🔬 Running OVAL evaluation with oscap..."
        oscap oval eval --results "${RESULT_XML}" "${DEST_XML}" || true 

        grep "<definition " "${RESULT_XML}" 2>/dev/null | \
          sed -nE 's/.*id="([^"]+)".*result="([^"]+)".*/\1,\2/p' | \
          awk -F, 'tolower($2) ~ /true/ {print $1}' | sort -u > "${ID_FILE}"
        
        if [ -s "${ID_FILE}" ]; then
            echo "🚨 Found $(wc -l < "${ID_FILE}") definitions with result=true."
            
            : > "${CVE_REPORT}" 
            
            while IFS= read -r ID || [ -n "${ID}" ]; do
                [ -z "${ID}" ] && continue
                
                CVE_TITLE=$(grep -a -A6 -F -- "$ID" "${RESULT_XML}" 2>/dev/null | \
                            sed -n 's/.*<title>\(.*\)<\/title>.*/\1/p' | head -n1 || true)

                if [ -n "$CVE_TITLE" ]; then
                    SECURITY_ID=$(echo "${CVE_TITLE}" | awk '{print $1}')
                    PACKAGE_NAME=$(echo "${CVE_TITLE}" | awk '{print $2}')
                    
                    LINK=$(generate_url "${SECURITY_ID}")
                    
                    PARSED_CVE="${PACKAGE_NAME} | ${SECURITY_ID} | ${LINK}"
                else
                    PARSED_CVE="(no-title-found-for-${ID})"
                fi
                
                echo "${PARSED_CVE}" >> "${CVE_REPORT}"
            done < "${ID_FILE}"

            send_report 0 "CVE_FOUND"

        else
            echo "✅ No vulnerable definitions found (result=true)."
            if [ "$STATUS" -eq 304 ]; then
                 send_report 0 "INFO"
            else
                 send_report 0 "SUCCESS"
            fi
        fi
        ;;

    999)
        send_report 1 "ERROR" "Network/Curl failed to reach ${URL}"
        ;;

    *)
        send_report 1 "ERROR" "Something went wrong: Unexpected HTTP status code ${STATUS} from ${URL}"
        ;;
esac
  • เปลี่ยนสิทธิ์
Bash
chmod +x gem-oval-check.sh
  • อย่าลืมก่อนใช้งานต้องติดตั้ง openscap-scanner ด้วยคำสั่ง
Bash
apt install -y openscap-scanner
  • จากนั้นตั้ง crontab รันวันละครั้ง
Bash
crontab -e
  • กรอกข้อมูล
Bash
30 2 * * * /path_to_script/gem-oval-check.sh > /dev/null 2>&1
  • ก็จะมีอีเมลส่งมาทุกวันนนน
  • จบ
  • ขอให้สนุก

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *