Tag: gemini.google.com

  • Debian Oval Security auto check

    Debian Oval Security 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, runs check, 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***********"
    SUBJECT="OVAL Report ${SERVER_HOSTNAME} $(date +%F)"
    
    OVAL_TIMESTAMP="N/A"
    OVAL_VERSION="N/A"
    
    # -------------------------
    # 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'
        
        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)"
    
        {
            echo "Host Name: ${SERVER_HOSTNAME}"
            echo "IP Address: ${SERVER_IP}"
            echo "-------------------------------------"
            echo "OVAL Version: ${OVAL_VERSION}"
            echo "OVAL Timestamp: ${OVAL_TIMESTAMP}"
            echo "-------------------------------------"
        } > "${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 
    
            if [ -f "${RESULT_XML}" ]; then
                OVAL_VERSION=$(grep 'oval:schema_version' "${DEST_XML}" 2>/dev/null | cut -d\> -f2 | cut -d\< -f1 | head -1 || echo "N/A")
                OVAL_TIMESTAMP=$(grep 'oval:timestamp' "${DEST_XML}" 2>/dev/null | cut -d\> -f2 | cut -d\< -f1 | head -1 || echo "N/A")
    
                echo "🔎 Extracted OVAL Version: ${OVAL_VERSION}, Timestamp: ${OVAL_TIMESTAMP} from result.xml"
            fi
            # ----------------------------------------------------------------------
    
            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
    • ก็จะมีอีเมลส่งมาทุกวันนนน
    • จบ
    • ขอให้สนุก