| Server IP : 119.195.102.159 / Your IP : 216.73.217.134 Web Server : nginx/1.18.0 System : Linux picell 5.15.0-181-generic #191-Ubuntu SMP Fri May 22 19:09:02 UTC 2026 x86_64 User : altablue ( 1000) PHP Version : 8.3.31 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /home/altablue/ |
Upload File : |
#!/bin/bash
# ============================================================
# π ν΄μ κΈ°λ° νμΌ λ¬΄κ²°μ± κ²μ¦ (Integrity Baseline)
# μλ² λ°°ν¬ κ²½λ‘: /home/altablue/integrity_baseline.sh
#
# WordPress μ½μ΄ νμΌ λ±μ SHA256 ν΄μ λ² μ΄μ€λΌμΈμ μμ±νκ³
# μ£ΌκΈ°μ μΌλ‘ λΉκ΅νμ¬ λ³μ‘°λ₯Ό κ°μ§ν©λλ€.
#
# μ¬μ©λ²:
# ./integrity_baseline.sh --init # λ² μ΄μ€λΌμΈ μ΅μ΄ μμ±
# ./integrity_baseline.sh --verify # λ² μ΄μ€λΌμΈ λλΉ κ²μ¦
# ./integrity_baseline.sh --update # λ² μ΄μ€λΌμΈ κ°±μ
# ./integrity_baseline.sh --status # νμ¬ μν νμΈ
# ============================================================
set -uo pipefail
# ββ μ€μ λ‘λ βββββββββββββββββββββββββββββββββββββ
CONFIG_FILE="/etc/security-watchdog/config"
if [ ! -f "$CONFIG_FILE" ]; then
echo "β μ€μ νμΌμ μ°Ύμ μ μμ΅λλ€: $CONFIG_FILE"
exit 1
fi
source "$CONFIG_FILE"
# ββ κ²½λ‘ μ€μ βββββββββββββββββββββββββββββββββββββ
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
NOTIFY="$SCRIPT_DIR/telegram_notify.sh"
LOG_FILE="${LOG_DIR}/integrity.log"
mkdir -p "$LOG_DIR" "$BASELINE_DIR"
# ββ λ‘κ·Έ ν¨μ βββββββββββββββββββββββββββββββββββββ
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}
# ββ μ¬μ΄νΈ λ£¨νΈ λλ ν 리 μλ νμ§ βββββββββββββββ
# nginx μ€μ μμ root λλ ν 리 μΆμΆ
get_site_roots() {
local roots=()
# λ°©λ² 1: nginx μ€μ νμΌμμ root μΆμΆ
if [ -d "/etc/nginx/sites-enabled" ]; then
while IFS= read -r root; do
root=$(echo "$root" | sed 's/;$//' | xargs)
if [ -d "$root" ]; then
roots+=("$root")
fi
done < <(grep -rh '^\s*root\s' /etc/nginx/sites-enabled/ 2>/dev/null | awk '{print $2}' | sort -u)
fi
# λ°©λ² 2: WATCH_DIRS λ΄ WordPress μ¬μ΄νΈ μλ νμ§
if [ ${#roots[@]} -eq 0 ]; then
for dir in "${WATCH_DIRS[@]}"; do
if [ ! -d "$dir" ]; then
continue
fi
while IFS= read -r wp_config; do
roots+=("$(dirname "$wp_config")")
done < <(find "$dir" -maxdepth 2 -name "wp-config.php" -type f 2>/dev/null)
done
fi
printf '%s\n' "${roots[@]}" | sort -u
}
# ββ μ¬μ΄νΈλ³ λ² μ΄μ€λΌμΈ νμΌ κ²½λ‘ βββββββββββββββββ
get_baseline_file() {
local site_root="$1"
local site_name
site_name=$(echo "$site_root" | sed 's|/|_|g' | sed 's|^_||')
echo "${BASELINE_DIR}/${site_name}.baseline"
}
# ββ νμΌ ν΄μ μμ± ββββββββββββββββββββββββββββββββ
generate_hash() {
local file="$1"
if [ -f "$file" ] && [ -r "$file" ]; then
sha256sum "$file" 2>/dev/null | cut -d' ' -f1
fi
}
# ββ λ² μ΄μ€λΌμΈ μ΄κΈ°ν βββββββββββββββββββββββββββββ
init_baseline() {
log "π λ² μ΄μ€λΌμΈ μ΄κΈ°ν μμ"
local site_count=0
local file_count=0
while IFS= read -r site_root; do
if [ -z "$site_root" ]; then
continue
fi
((site_count++))
local baseline_file
baseline_file=$(get_baseline_file "$site_root")
local site_name
site_name=$(basename "$site_root")
log " π μ¬μ΄νΈ: $site_name ($site_root)"
# λ² μ΄μ€λΌμΈ νμΌ μ΄κΈ°ν
cat > "$baseline_file" << EOF
# Integrity Baseline
# Site: $site_root
# Created: $(date '+%Y-%m-%d %H:%M:%S')
# Format: SHA256_HASH|FILE_PATH|FILE_SIZE|FILE_PERMS|MODIFIED_TIME
EOF
# WordPress μ½μ΄ νμΌ ν΄μ
for pattern in "${INTEGRITY_PATTERNS[@]}"; do
while IFS= read -r -d '' file; do
local hash size perms mtime
hash=$(generate_hash "$file")
size=$(stat -c%s "$file" 2>/dev/null || echo "0")
perms=$(stat -c%a "$file" 2>/dev/null || echo "000")
mtime=$(stat -c%Y "$file" 2>/dev/null || echo "0")
if [ -n "$hash" ]; then
echo "${hash}|${file}|${size}|${perms}|${mtime}" >> "$baseline_file"
((file_count++))
fi
done < <(find "$site_root" -path "*/$pattern" -type f -print0 2>/dev/null)
done
# μΆκ°: λ£¨νΈ λλ ν 리μ .php νμΌ
while IFS= read -r -d '' file; do
local hash size perms mtime
hash=$(generate_hash "$file")
size=$(stat -c%s "$file" 2>/dev/null || echo "0")
perms=$(stat -c%a "$file" 2>/dev/null || echo "000")
mtime=$(stat -c%Y "$file" 2>/dev/null || echo "0")
if [ -n "$hash" ]; then
echo "${hash}|${file}|${size}|${perms}|${mtime}" >> "$baseline_file"
((file_count++))
fi
done < <(find "$site_root" -maxdepth 1 -name "*.php" -type f -print0 2>/dev/null)
# μΆκ°: .htaccess νμΌ
if [ -f "$site_root/.htaccess" ]; then
local hash size perms mtime
hash=$(generate_hash "$site_root/.htaccess")
size=$(stat -c%s "$site_root/.htaccess" 2>/dev/null || echo "0")
perms=$(stat -c%a "$site_root/.htaccess" 2>/dev/null || echo "000")
mtime=$(stat -c%Y "$site_root/.htaccess" 2>/dev/null || echo "0")
echo "${hash}|${site_root}/.htaccess|${size}|${perms}|${mtime}" >> "$baseline_file"
((file_count++))
fi
log " β
λ² μ΄μ€λΌμΈ μμ± μλ£: $(grep -c '|' "$baseline_file" 2>/dev/null)κ° νμΌ"
done < <(get_site_roots)
log "π λ² μ΄μ€λΌμΈ μ΄κΈ°ν μλ£: ${site_count}κ° μ¬μ΄νΈ, ${file_count}κ° νμΌ"
"$NOTIFY" "INFO" "π <b>λ¬΄κ²°μ± λ² μ΄μ€λΌμΈ μμ± μλ£</b>
π μ¬μ΄νΈ: ${site_count}κ°
π νμΌ: ${file_count}κ°
π μ μ₯ κ²½λ‘: ${BASELINE_DIR}"
}
# ββ λ¬΄κ²°μ± κ²μ¦ βββββββββββββββββββββββββββββββββββ
verify_baseline() {
log "π λ¬΄κ²°μ± κ²μ¦ μμ"
local total_checked=0
local modified_count=0
local missing_count=0
local new_count=0
local modified_files=()
local missing_files=()
# λ² μ΄μ€λΌμΈ νμΌ μν
for baseline_file in "${BASELINE_DIR}"/*.baseline; do
if [ ! -f "$baseline_file" ]; then
continue
fi
local site_root
site_root=$(grep "^# Site:" "$baseline_file" | head -1 | sed 's/^# Site: //')
if [ -z "$site_root" ] || [ ! -d "$site_root" ]; then
log " β οΈ μ¬μ΄νΈ λλ ν 리 μμ: $site_root"
continue
fi
local site_name
site_name=$(basename "$site_root")
# λ² μ΄μ€λΌμΈ μνΈλ¦¬ κ²μ¦
while IFS='|' read -r expected_hash filepath expected_size expected_perms expected_mtime; do
# μ£Όμ λ° λΉ μ€ κ±΄λλ°κΈ°
[[ "$expected_hash" =~ ^#.*$ ]] && continue
[ -z "$expected_hash" ] && continue
((total_checked++))
if [ ! -f "$filepath" ]; then
# νμΌ λλ½ (μμ λ¨)
((missing_count++))
missing_files+=("$filepath")
log " β νμΌ λλ½: $filepath"
continue
fi
# νμ¬ ν΄μ κ³μ°
local current_hash
current_hash=$(generate_hash "$filepath")
if [ "$current_hash" != "$expected_hash" ]; then
# ν΄μ λΆμΌμΉ (λ³μ‘°λ¨)
((modified_count++))
local current_size
current_size=$(stat -c%s "$filepath" 2>/dev/null || echo "0")
local current_perms
current_perms=$(stat -c%a "$filepath" 2>/dev/null || echo "000")
modified_files+=("$filepath (ν¬κΈ°: ${expected_size}β${current_size}, κΆν: ${expected_perms}β${current_perms})")
log " π΄ λ³μ‘° κ°μ§: $filepath"
log " μλ³Έ ν΄μ: $expected_hash"
log " νμ¬ ν΄μ: $current_hash"
fi
done < "$baseline_file"
# μλ‘ μμ±λ νμΌ νμΈ (λ² μ΄μ€λΌμΈμ μλ νμΌ)
while IFS= read -r -d '' file; do
local in_baseline=false
if grep -q "|${file}|" "$baseline_file" 2>/dev/null; then
in_baseline=true
fi
if [ "$in_baseline" = "false" ]; then
((new_count++))
log " π μ νμΌ: $file"
fi
done < <(find "$site_root" -maxdepth 1 -name "*.php" -type f -print0 2>/dev/null)
done
log "π κ²μ¦ μλ£: ${total_checked}κ° νμΈ, ${modified_count}κ° λ³μ‘°, ${missing_count}κ° λλ½, ${new_count}κ° μ κ·"
# κ²°κ³Ό μλ¦Ό
if [ "$modified_count" -gt 0 ] || [ "$missing_count" -gt 0 ]; then
local alert_level="WARNING"
if [ "$modified_count" -gt 0 ]; then
alert_level="CRITICAL"
fi
local detail_msg=""
if [ "$modified_count" -gt 0 ]; then
detail_msg="${detail_msg}
π΄ <b>λ³μ‘°λ νμΌ (${modified_count}κ°):</b>"
local count=0
for f in "${modified_files[@]}"; do
((count++))
if [ "$count" -le 10 ]; then
detail_msg="${detail_msg}
β’ <code>${f}</code>"
fi
done
if [ "$count" -gt 10 ]; then
detail_msg="${detail_msg}
... μΈ $((count - 10))κ°"
fi
fi
if [ "$missing_count" -gt 0 ]; then
detail_msg="${detail_msg}
β <b>μμ λ νμΌ (${missing_count}κ°):</b>"
local count=0
for f in "${missing_files[@]}"; do
((count++))
if [ "$count" -le 10 ]; then
detail_msg="${detail_msg}
β’ <code>${f}</code>"
fi
done
if [ "$count" -gt 10 ]; then
detail_msg="${detail_msg}
... μΈ $((count - 10))κ°"
fi
fi
"$NOTIFY" "$alert_level" "π <b>λ¬΄κ²°μ± κ²μ¦ κ²°κ³Ό</b>
π <b>κ²μ¦ μμ½:</b>
ββββββββββββββββββββ
π κ²μ¬ νμΌ: ${total_checked}κ°
π΄ λ³μ‘°: ${modified_count}κ°
β λλ½: ${missing_count}κ°
π μ κ·: ${new_count}κ°
${detail_msg}"
else
log "β
λͺ¨λ νμΌ λ¬΄κ²°μ± νμΈ"
# μ μμΌ λλ λ³λ μλ¦Ό μ 보λ (λ‘κ·Έλ§ κΈ°λ‘)
fi
}
# ββ λ² μ΄μ€λΌμΈ κ°±μ βββββββββββββββββββββββββββββββ
update_baseline() {
log "π λ² μ΄μ€λΌμΈ κ°±μ μμ"
# κΈ°μ‘΄ λ² μ΄μ€λΌμΈ λ°±μ
local backup_dir="${BASELINE_DIR}/backup_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$backup_dir"
cp "${BASELINE_DIR}"/*.baseline "$backup_dir/" 2>/dev/null
log " π¦ κΈ°μ‘΄ λ² μ΄μ€λΌμΈ λ°±μ
: $backup_dir"
# μ λ² μ΄μ€λΌμΈ μμ±
init_baseline
"$NOTIFY" "INFO" "π <b>λ² μ΄μ€λΌμΈ κ°±μ μλ£</b>
π¦ μ΄μ λ² μ΄μ€λΌμΈ λ°±μ
: <code>${backup_dir}</code>"
}
# ββ μν νμΈ βββββββββββββββββββββββββββββββββββββ
show_status() {
echo "π λ¬΄κ²°μ± λ² μ΄μ€λΌμΈ μν"
echo "ββββββββββββββββββββββββββββββββββ"
echo "π μ μ₯ κ²½λ‘: $BASELINE_DIR"
echo ""
if [ ! "$(ls -A "$BASELINE_DIR"/*.baseline 2>/dev/null)" ]; then
echo "β οΈ λ² μ΄μ€λΌμΈμ΄ μμ±λμ§ μμμ΅λλ€."
echo " μμ±νλ €λ©΄: $0 --init"
return
fi
for baseline_file in "${BASELINE_DIR}"/*.baseline; do
local site_root
site_root=$(grep "^# Site:" "$baseline_file" | head -1 | sed 's/^# Site: //')
local created
created=$(grep "^# Created:" "$baseline_file" | head -1 | sed 's/^# Created: //')
local file_count
file_count=$(grep -c '|' "$baseline_file" 2>/dev/null || echo 0)
echo "π μ¬μ΄νΈ: $(basename "$site_root")"
echo " κ²½λ‘: $site_root"
echo " μμ±: $created"
echo " νμΌ: ${file_count}κ°"
echo ""
done
}
# ββ λ©μΈ ββββββββββββββββββββββββββββββββββββββββββ
case "${1:-}" in
--init|-i)
init_baseline
;;
--verify|-v)
verify_baseline
;;
--update|-u)
update_baseline
;;
--status|-s)
show_status
;;
--help|-h)
echo "π ν΄μ κΈ°λ° νμΌ λ¬΄κ²°μ± κ²μ¦"
echo ""
echo "μ¬μ©λ²:"
echo " $0 --init λ² μ΄μ€λΌμΈ μ΅μ΄ μμ±"
echo " $0 --verify λ² μ΄μ€λΌμΈ λλΉ κ²μ¦"
echo " $0 --update λ² μ΄μ€λΌμΈ κ°±μ (λ°±μ
ν)"
echo " $0 --status νμ¬ μν νμΈ"
echo " $0 --help λμλ§"
;;
*)
echo "β μ΅μ
μ μ§μ ν΄μ£ΌμΈμ. --help λ‘ μ¬μ©λ² νμΈ"
exit 1
;;
esac