Skip to content

PlusMagi's Blog By Pitt Phunsanit

Plus emotional magic to the knowledge of logic.

  • About’s Pitt
Close Button

Linux: ตรวจหาไฟล์แปลกปลอม ปรับแต่ง (Custom Files) ทั่วทั้งระบบLinux: ตรวจหาไฟล์แปลกปลอม ปรับแต่ง (Custom Files) ทั่วทั้งระบบ

2026-08-152026-08-15| phunsanitphunsanit| 0 Comment | 07:00

เคยเจอปัญหานี้ไหมครับ? เวลาที่ต้องเข้าไปดูแลเซิร์ฟเวอร์ต่อจากคนอื่น หรือระบบที่ใช้งานมานานจนไม่รู้ว่ามีใครแอบไปสร้างไฟล์คอนฟิกแปลก ๆ ทิ้งไว้ตรงไหนบ้าง จะตามหาว่าไฟล์ไหนเป็นไฟล์ระบบดั้งเดิม และไฟล์ไหนเป็นไฟล์ที่ถูกเพิ่มเข้ามาใหม่ (Custom Files) ก็ดูจะเป็นเรื่องงมเข็มในมหาสมุทร

วันนี้เราจะมาแจกและเจาะลึกสคริปต์ verify-custom-files.sh ที่จะช่วยสแกนหาไฟล์ที่ไม่ได้มาจากระบบจัดการแพ็กเกจ (dpkg) ของ Ubuntu/Debian แบบ Real-time พร้อมแสดงผล Permissions ในรูปแบบ 4 หลักที่แม่นยำ


verify-custom-files.sh

#!/bin/bash

# ==============================================================================
# Script Name: verify-custom-files.sh
# Description: Finds ALL custom/added files across the entire system (/)
#			   with 100% real-time unbuffered screen output.
#			   Outputs 4-digit octal permissions directly from system stat.
# Author:	   Pitt Phunsannit
# Date:		   2026
# ==============================================================================
# MANUAL & DOCUMENTATION:
#
# OPTIONS:
#   -p <path>  : Base directory path to scan (Default: /)
#   -d <depth> : Maximum directory depth for scanning (Default: Unlimited)
#   -h		   : Display this help message
#
# EXAMPLES:
#   1. Scan entire system (Skips virtual, temp & kernel directories automatically)
#	  sudo ./verify-custom-files.sh
#
#   2. Scan only /etc directory with unlimited depth
#	  sudo ./verify-custom-files.sh -p /etc
#
# LIMITATIONS:
#   - Performance: Scanning the entire root (/) without a depth limit
#	 takes less than a few minutes since kernel directories are now ignored.
#   - Scope: Only identifies files NOT tracked by the dpkg package manager.
# ==============================================================================

# Ensure script is running with root/sudo privileges
if [ "$EUID" -ne 0 ]; then
	echo "❌ Error: Please run this script with root privileges (sudo)."
	exit 1
fi

# Enable lastpipe so variables modified inside the while loop persist outside
shopt -s lastpipe

# Get the directory where this script is located
SCRIPT_DIR=$(dirname "$(readlink -f "$0")")

# Default values
SEARCH_PATH="/"
MAX_DEPTH=""
ISO_DATE=$(date +%Y-%m-%d_%H%M%S)
OUTPUT_FILE="${SCRIPT_DIR}/verify-custom-files-full-${ISO_DATE}.txt"

# Usage help function
usage() {
	echo "Usage: $0 [-p <path>] [-d <depth>]"
	echo " -p : Specify starting directory path (Default: /)"
	echo " -d : Specify maximum search depth (integer)"
	exit 1
}

# Parse command-line arguments
while getopts "p:d:h" opt; do
	case ${opt} in
		p ) SEARCH_PATH=$OPTARG ;;
		d ) MAX_DEPTH=$OPTARG ;;
		h | ? ) usage ;;
	esac
done

echo "🔍 Starting Full System Scan for custom/added files..."
echo "📍 Target Path : $SEARCH_PATH"
[[ -n "$MAX_DEPTH" ]] && echo "↕️ Max Depth : $MAX_DEPTH" || echo "↕️ Max Depth : Unlimited"
echo "📝 Report File : $OUTPUT_FILE"
echo "----------------------------------------------------------------------"

# Clean/Create the output file
> "$OUTPUT_FILE"

# Open File Descriptor 3 for high-performance direct logging
exec 3>>"$OUTPUT_FILE"

# Collect Distro Architecture, OS Version, and Total Package Info for Analysis
DISTRO_NAME=$(lsb_release -is 2>/dev/null || cat /etc/os-release | grep -E '^NAME=' | cut -d= -f2 | tr -d '"')
DISTRO_VER=$(lsb_release -rs 2>/dev/null || cat /etc/os-release | grep -E '^VERSION_ID=' | cut -d= -f2 | tr -d '"')
TOTAL_PKGS=$(dpkg-query -f '${binary:Package}\n' -W 2>/dev/null | wc -l)

# Write metadata header to report file
{
	echo "======================================================================"
	echo " SYSTEM VERIFICATION BASELINE REPORT"
	echo "======================================================================"
	echo "Scan Date	   : $(date '+%Y-%m-%d %H:%M:%S')"
	echo "Distro Name  : $DISTRO_NAME"
	echo "Version	   : $DISTRO_VER"
	echo "Total Packages Installed : $TOTAL_PKGS"
	echo "Target Path  : $SEARCH_PATH"
	echo "======================================================================"
	echo ""
	echo "ID NO. │ PERM (4-DIGIT) │ OWNER:GROUP │ FILE PATH"
	echo "----------------------------------------------------------------------"
} >&3

# Dump official distro files to a temporary reference file
REF_FILE="/tmp/distro_files.tmp"
echo "📦 Loading official package database..."
cat /var/lib/dpkg/info/*.list 2>/dev/null | sort -u > "$REF_FILE"
echo "⚡ Database loaded. Scanning disk now (Real-time output enabled)..."
echo "----------------------------------------------------------------------"
echo "ID NO. │ PERM (4-DIGIT) │ OWNER:GROUP │ FILE PATH"
echo "----------------------------------------------------------------------"

# Configure Prune Expression to skip dynamic, virtual, and kernel directories
PRUNE_EXPR=""
if [[ "$SEARCH_PATH" == "/" ]]; then
	PRUNE_EXPR="\( \
		-path /proc -o \
		-path /sys -o \
		-path /dev -o \
		-path /run -o \
		-path /tmp -o \
		-path /var/tmp -o \
		-path /var/cache -o \
		-path /var/lib/apt -o \
		-path /var/log -o \
		-path /mnt -o \
		-path /media -o \
		-path /snap -o \
		-path /var/lib/snapd -o \
		-path /usr/lib/modules -o \
		-path /usr/lib/firmware \
	\) -prune -o"
fi

DEPTH_EXPR=""
if [[ -n "$MAX_DEPTH" ]]; then
	DEPTH_EXPR="-maxdepth $MAX_DEPTH"
fi

MATCH_COUNT=0

# Core loop: Scan filesystem, check against baseline, output unbuffered metadata
eval stdbuf -oL find \"$SEARCH_PATH\" $DEPTH_EXPR $PRUNE_EXPR -type f 2>/dev/null | while read -r FILE; do
	if ! grep -Fxq "$FILE" "$REF_FILE"; then
		((MATCH_COUNT++))

		# Extract 4-digit octal permissions natively from the system stat
		PERM=$(stat -c "%04a" "$FILE" 2>/dev/null)
		OWNER=$(stat -c "%U:%G" "$FILE" 2>/dev/null)

		RESULT_LINE=$(printf "%-6d │ %-14s │ %-11s │ %s" "$MATCH_COUNT" "$PERM" "$OWNER" "$FILE")

		# Display to screen and write to file immediately
		echo "$RESULT_LINE"
		echo "$RESULT_LINE" >&3
	fi
done

# Clean up and append summary to file
echo "----------------------------------------------------------------------" >&3
echo "✅ Full Scan complete! Total custom files found: $MATCH_COUNT" >&3

exec 3>&-
rm -f "$REF_FILE"

echo "----------------------------------------------------------------------"
echo "✅ Full Scan complete!"
echo "⚠️  Total custom files found across the system: $MATCH_COUNT"
echo "📂 List saved to: $OUTPUT_FILE"


🛠 ความสามารถเด่นของสคริปต์นี้

  • 100% Real-time Output: แสดงผลบนหน้าจอทันทีแบบ Unbuffered ไม่ต้องนั่งรอจนสแกนเสร็จแล้วค่อยขึ้นทีเดียว
  • Smart Pruning: ข้ามไดเรกทอรีที่เป็น Virtual, Temporary และ Kernelอัตโนมัติ (เช่น /proc, /sys, /dev, /run) ทำให้สแกนระบบเสร็จภายในไม่กี่นาที
  • 4-Digit Octal Permissions: ดึงค่าสิทธิ์ของไฟล์ (เช่น 0644, 0755) ออกมาจาก stat ของระบบโดยตรง ช่วยให้ตรวจเช็กช่องโหว่ด้านความปลอดภัยได้ง่ายขึ้น
  • Auto-Save Report: บันทึกผลลัพธ์เป็นไฟล์รายงานแยกตามวันเวลาที่รันสคริปต์ให้อัตโนมัติ

🚀 วิธีการนำไปใช้งาน (Quick Start)

  1. เตรียมสคริปต์
    นำโค้ดสคริปต์ไปบันทึกไว้ในไฟล์ชื่อ verify-custom-files.sh จากนั้นให้สิทธิ์ในการรันสคริปต์
    chmod +x verify-custom-files.sh
  2. ตัวอย่างคำสั่งการใช้งาน
    ⚠️ ข้อควรระวัง: สคริปต์นี้จำเป็นต้องเข้าถึงไฟล์ระบบระดับลึก จึงต้องรันด้วยสิทธิ์ Root (sudo) เท่านั้น
    • สแกนทั้งระบบ (ข้ามโฟลเดอร์ขยะให้อัตโนมัติ)
      sudo ./verify-custom-files.sh
    • สแกนเฉพาะโฟลเดอร์คอนฟิก /etc
      sudo ./verify-custom-files.sh -p /etc
    • สแกนโดยจำกัดความลึกของไดเรกทอรีไว้ที่ 3 ชั้น:
      sudo ./verify-custom-files.sh -d 3

📊 หน้าตาผลลัพธ์การทำงาน (Output Example)

เมื่อคุณสั่งรัน สคริปต์จะดึงฐานข้อมูลของ dpkg มาเปรียบเทียบกับไฟล์จริงในดิสก์ และพ่นผลลัพธ์ออกมาในรูปแบบตารางที่อ่านง่ายแบบนี้

🔍 Starting Full System Scan for custom/added files...
📍 Target Path : /text
↕️ Max Depth  : Unlimited
📝 Report File : /path/to/verify-custom-files-full-2026-07-10_002743.txt
----------------------------------------------------------------------
📦 Loading official package database...
⚡ Database loaded. Scanning disk now (Real-time output enabled)...
----------------------------------------------------------------------
ID NO. │ PERM (4-DIGIT) │ OWNER:GROUP │ FILE PATH
----------------------------------------------------------------------
1      │ 0644           │ root:root   │ /etc/nginx/conf.d/custom-app.conf
2      │ 0755           │ root:root   │ /usr/local/bin/backup-script.sh
3      │ 0600           │ www-data:www│ /var/www/html/.env.backup
----------------------------------------------------------------------
✅ Full Scan complete!
⚠️  Total custom files found across the system: 3
📂 List saved to: /path/to/verify-custom-files-full-2026-07-10_002743.txt

💡 เจาะลึกเทคนิคเบื้องหลังสคริปต์ (Code Breakdown)

สำหรับสาย Hardcore Bash มาดูกันว่าสคริปต์นี้มีเทคนิคอะไรซ่อนอยู่บ้าง

  • การแก้ปัญหาตัวแปรตายใน While Loop ด้วย lastpipe
    ปกติแล้วเวลาเรา Pipe ผลลัพธ์เข้า while read ตัวแปรภายใน Loop จะหายไปเมื่อจบ Loop (เพราะทำงานใน Subshell) สคริปต์นี้แก้เกมด้วยการใช้
    shopt -s lastpipe
    ทำให้ตัวแปรนับจำนวน MATCH_COUNT ที่สะสมใน Loop สามารถนำมาใช้งานต่อนอก Loop ได้จริง
  • การทำ Unbuffered Output ด้วย stdbuf
    เพื่อให้เห็นผลลัพธ์วิ่งบนหน้าจอแบบเรียลไทม์ วินาทีต่อวินาที สคริปต์จึงเลือกใช้คำสั่ง
    eval stdbuf -oL find ...
    ช่วยให้ระบบไม่เก็บแคชของ Line Output ไว้ ส่งผลให้ผู้ดูแลระบบเห็นการทำงานได้ทันที
  • การดึงสิทธิ์แบบ 4 หลัก (Natively)
    หมดปัญหาเรื่องการตัดคำจาก ls -l ให้วุ่นวาย สคริปต์ใช้ความสามารถของ stat ตรง ๆ
    stat -c "%04a" "$FILE"
    ทำให้ได้เลขสิทธิ์แบบ Octal 4 หลัก (รวมถึงพวก Sticky bit หรือ SUID) อย่างแม่นยำ

🎯 สรุป

สคริปต์ verify-custom-files.sh ตัวนี้เหมาะอย่างยิ่งสำหรับเป็นเครื่องมือคู่ใจของ SysAdmin และ DevOps ในการทำ System Auditing, ตรวจสอบความปลอดภัยหลังโดนแฮก (Post-compromise Analysis) หรือแม้กระทั่งใช้เช็กเพื่อทำ Backup คอนฟิกที่หลงเหลืออยู่ก่อนที่จะสั่งล้างเครื่อง (Re-install) แล้วจะรู้ว่าการตามหาไฟล์แปลกปลอมใน Linux ไม่ใช่เรื่องยากอีกต่อไป!


อ่านเพิ่มเติม

  • Stalwart mail server: reset admin password
  • Jujutsu (jj): ต่างจาก GIT อย่างไร
  • PHP: การอัปเดต PHP เวอร์ชันใหม่อยู่เสมอเพื่อรับ Patch ความปลอดภัย
Read MoreRead More

Posts pagination

ก่อนหน้า 1 … 23 24 25 … 4,503 ถัดไป

Projects

  • Statement Columns Mapping Helper
  • PlusMagi Site Search
  • PlusMagi Tags Reindex
  • jQuery Plus Repeater

Recent Posts

  • Project Hail Mary: สองชีวิตต่างโลก กับหนึ่งภารกิจ สะเทือนจักรวาล
  • ขึ้นทางด่วนคุ้มไหม? วิธีตั้งค่า Google Maps คำนวณค่าผ่านทาง เทียบเวลาและค่าน้ำมันให้เห็นชัด ๆ
  • เลิกปวดหัวกับทางลัดมหาภัย: วิธีตั้งค่า Google Maps ให้เลือก “ทางขับง่าย” มากกว่า “เร็วกว่าแค่ 1-2 นาที”
  • OOD: Object-Oriented Design
  • CMS

Archives

Categories

  • .net core (16)
  • AI (52)
  • business (33)
  • Businesses (32)
  • cd (59)
  • ci (62)
  • culture (2)
  • data (5)
  • Design (160)
    • UX/UI (23)
  • devops (200)
  • devsecops (35)
  • dotnet (58)
  • envoy (2)
  • Histories (22)
  • history (2)
  • ios (4)
  • Life (1,209)
    • Books (59)
    • Cartoon (13)
    • Mindset (41)
    • Movies (35)
    • Philosophy (4)
    • Psychology (3)
    • Sci-Fi (53)
    • Tips and Tricks (67)
    • ปรัชญา (267)
    • พัฒนาตนเอง (883)
    • พุทธ (70)
    • สิ่งแวดล้อม (46)
  • mobile (1)
  • mystery (8)
  • net core (10)
  • Network (353)
    • Apache HTTP Server (19)
    • IOT (24)
    • Nginx (41)
    • Stalwart (6)
  • networking (131)
  • Operating Systems (448)
    • Unix-like (313)
      • Android (24)
        • F-Droid (5)
      • Homebrew (22)
      • iPhone (12)
      • Linux (195)
      • macOS (135)
        • OrbStack (12)
      • Oh My ZSH (4)
      • Shell Script (80)
      • SSH (15)
    • Windows (163)
      • PowerShell (28)
      • WSL (25)
  • Programming (1,714)
    • .NET (68)
      • .NET Core EF (7)
      • C# (60)
    • API (145)
      • REST (54)
      • Swagger (13)
    • Database (412)
      • DBeaver (5)
      • MariaDB (38)
      • MySql (81)
      • Oracle Database (8)
        • 10g (3)
      • PostgreSQL (30)
      • RDBMS (78)
      • SQL Server (91)
        • SSMS (10)
        • T-SQL (30)
      • SQLite (2)
    • PowerBuilder (20)
    • Python (27)
    • Rust (44)
    • System Analyst (SA) (97)
    • Testing (110)
      • Automated Testing (45)
        • Playwright (11)
    • UML (53)
    • Web (904)
      • Backend (589)
        • Golang (2)
        • Java (113)
          • Spring Boot (27)
        • Node.js (12)
        • PHP (281)
          • Laravel (60)
          • Yii (5)
      • Frontend (290)
        • CSS (28)
          • Tailwind CSS (6)
        • JavaScript (230)
          • Angular (4)
          • jQuery (70)
          • Tabulator (28)
          • Vue.js (7)
      • WordPress (27)
  • Programs (112)
    • Excel (20)
  • r (2)
  • science (10)
  • script (3)
  • SecDevOps (200)
    • CI/CD (11)
    • Docker (92)
    • GIT (61)
    • SVN (18)
  • Security (370)
  • sistema (1)
  • social (2)
  • system (376)
  • system analyst (31)
  • technology (923)
  • technologyระบบ (101)
  • technologyและระบบ (3)
  • typescript (10)
  • ui (63)
  • Uncategorized (6)
  • ux (58)
  • กฎหมาย (305)
  • การจัดการ (606)
  • การจัดการข้อมูล (351)
  • การจัดการข้อมูลและองค์ความรู้ (3)
  • การพัฒนาตนเอง (12)
  • การออกแบบ (77)
  • ข้อมูล (2)
  • คณิตศาสตร์ (31)
  • ความคิด (110)
  • ความปลอดภัย (224)
  • จริยธรรม (85)
  • จิตวิทยา (885)
  • ชีวิต (115)
  • ทั่วไป (16)
  • ธุรกิจ (622)
  • บุคคล (35)
  • บุคลากร (10)
  • บุคลิก (88)
  • ประวัติศาสตร์ (39)
  • ปัญญาประดิษฐ์ (28)
  • พฤติกรรม (168)
  • ภาษาศาสตร์คอมพิวเตอร์ (28)
  • ระบบ (357)
  • วัฒนธรรม (52)
  • วิชาการ (87)
  • วิชาการข้อมูล (64)
  • วิทยาการข้อมูล (162)
  • วิทยาการข้อมูลและภาษาศาสตร์คอมพิวเตอร์ (1)
  • วิทยาศาสตร์ (163)
  • วิทยาศาสตร์ข้อมูล (28)
  • สังคม (338)
  • สุขภาพ (210)
  • หนังสือ (2)
  • องค์ความรู้ (187)
  • ออกแบบ (18)
  • เทคโนโลยี (290)
  • เทคโนโลยีระบบ (156)
  • 기술 (1)
  • 사회 (1)
  • 시스템 (1)
  • 철학 (1)

Sirat WordPress Theme By VWThemes

Scroll Up
Go to mobile version