Sh3ll



Directory :  /scripts2/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

Current File : //scripts2/croncheck.sh
n/bash

###############################################################################
# CronCheck
#
# Revisa los crontabs de usuarios cPanel y genera un reporte plano con
# tareas sospechosas.
#
# El script no envía mails. Otro proceso centralizado recolecta los reportes.
###############################################################################

set -o nounset
set -o pipefail

############################
# Configuración
############################

REPORT="/etc/sitioshispanos/croncheck_report.txt"

SCORE_THRESHOLD=8  # Score que deben alcanzar los patrones menos obvios para considerarse sospechosos

MAX_COMMAND_LENGTH=250  # Largo minimo de la cadena del cron antes de considerarse sospechoso

DEBUG=0     # Por testeos


# Reglas de schedule que generan reporte directo. Se pueden agregar mas patrones en el Array

SCHEDULE_CRITICAL_PATTERNS=(
    '^\*[[:space:]]+\*[[:space:]]+\*[[:space:]]+\*[[:space:]]+\*$'  # Si el cron es de tipo * * * * * (1 segundo) se reporta
    '^@reboot'   # Si contiene @reboot probablemente sea virus. 
)


# Reglas críticas sobre el command. Se pueden agregar mas patrones en el Array

CRITICAL_PATTERNS=(
    'base64'
    'base64_decode'
    'eval[[:space:]]*\('
    'php[[:space:]]+-r'
    'perl[[:space:]]+-e'
    'python[[:space:]]+-c'
    '(curl|wget).*\|.*(sh|bash|php|perl|python)'
    '/dev/shm/'
    '/tmp/'
)


# Estos patrones son los que pueden o no ser virus. Se le da un valor a cada uno y no deben sumar mas de 8 por cron o se reportará como sospechoso.
# Formato: patron|puntaje
# Se pueden agregar mas patrones y puntajes en el Array. El puntaje se puede modificar

SCORE_PATTERNS=(
    'http://|3'
    'https://|1'
    'curl|2'
    'wget|2'
    'openssl|2'
    'xxd|2'
)


# Patrones ignorados.
# Inicialmente vacío.

IGNORE_PATTERNS=(
)


############################
# Inicialización
############################

mkdir -p "$(dirname "$REPORT")"

: > "$REPORT"


############################
# Funciones
############################


debug() {

    [[ "$DEBUG" -eq 1 ]] && echo "DEBUG: $*"

}


registrar_reporte() {

    local usuario="$1"
    local tipo="$2"
    local score="$3"
    local cron="$4"


    printf '%s|%s|%s|%s\n' \
        "$usuario" \
        "$tipo" \
        "$score" \
        "$cron" >> "$REPORT"

}


esta_ignorado() {

    local command="$1"


    for patron in "${IGNORE_PATTERNS[@]}"; do

        [[ -z "$patron" ]] && continue

        if [[ "$command" =~ $patron ]]; then
            return 0
        fi

    done


    return 1

}


analizar_schedule() {

    local usuario="$1"
    local schedule="$2"
    local cron="$3"


    for patron in "${SCHEDULE_CRITICAL_PATTERNS[@]}"; do

        if [[ "$schedule" =~ $patron ]]; then

            registrar_reporte \
                "$usuario" \
                "SCHEDULE" \
                "-" \
                "$cron"

            return 0

        fi

    done


    return 1

}


analizar_critical() {

    local usuario="$1"
    local command="$2"
    local cron="$3"


    for patron in "${CRITICAL_PATTERNS[@]}"; do

        if [[ "$command" =~ $patron ]]; then

            registrar_reporte \
                "$usuario" \
                "CRITICAL" \
                "-" \
                "$cron"

            return 0

        fi

    done


    return 1

}


calcular_score() {

    local command="$1"

    local score=0


    for regla in "${SCORE_PATTERNS[@]}"; do

        local patron="${regla%|*}"
        local puntos="${regla##*|}"


        if [[ "$command" =~ $patron ]]; then

            ((score+=puntos))

        fi

    done


    if (( ${#command} > MAX_COMMAND_LENGTH )); then

        ((score+=2))

    fi


    echo "$score"

}


analizar_cron() {

    local usuario="$1"
    local cron="$2"

    local min=""
    local hour=""
    local dom=""
    local month=""
    local dow=""
    local command=""

    local schedule=""
    local score=""


    [[ -z "$cron" ]] && return


    # Ignorar comentarios.

    [[ "$cron" =~ ^[[:space:]]*# ]] && return


    # Ignorar variables:
    # SHELL=
    # MAILTO=
    # PATH=

    [[ "$cron" =~ ^[[:space:]]*[A-Za-z_][A-Za-z0-9_]*= ]] && return


    # Macros de cron:
    # @reboot
    # @daily
    # etc.

    if [[ "$cron" =~ ^[[:space:]]*@ ]]; then

        schedule=$(echo "$cron" | awk '{print $1}')

        command=$(echo "$cron" | cut -d' ' -f2-)


    else

        read -r min hour dom month dow command <<< "$cron"

        schedule="$min $hour $dom $month $dow"

    fi


    [[ -z "$command" ]] && return


    debug "USER=[$usuario]"
    debug "SCHEDULE=[$schedule]"
    debug "COMMAND=[$command]"


    if esta_ignorado "$command"; then

        return

    fi


    if analizar_critical "$usuario" "$command" "$cron"; then

        return

    fi


    if analizar_schedule "$usuario" "$schedule" "$cron"; then

        return

    fi


    score=$(calcular_score "$command")


    if (( score >= SCORE_THRESHOLD )); then

        registrar_reporte \
            "$usuario" \
            "SCORE" \
            "$score" \
            "$cron"

    fi

}


procesar_usuario() {

    local usuario="$1"


    while IFS= read -r cron; do

        analizar_cron "$usuario" "$cron"

    done < <(crontab -u "$usuario" -l 2>/dev/null)

}


############################
# Procesamiento
############################


while IFS= read -r usuario; do

    # Eliminar espacios iniciales y finales.

    usuario="${usuario#"${usuario%%[![:space:]]*}"}"
    usuario="${usuario%"${usuario##*[![:space:]]}"}"


    [[ -z "$usuario" ]] && continue


    procesar_usuario "$usuario"


done < <(cut -f2 -d: /etc/trueuserdomains)


exit 0

Sh3LL