Недавно показывал пример скрипта для проверки целостности файлов, который считает хеши SHA-256, но если файлы большого размера и их под 100 гигабайт или больше, естественно это будет сильно нагружать дисковую систему, по этому если это критично и тормозит другие процессы, то приведу пример простого скрипта, который работает намного быстрее, просто сверяет размер файла и mtime (время модификации), но стоит учесть, в отличии от хеша SHA-256, злоумышленник может указать mtime на новый подмененный зараженный файл аналогичный старому.
Установка python3 в Ubuntu Server:
python3 --version
apt install python3 python3-pip
Содержимое скрипта:
#!/usr/bin/env python3
import os
import json
import time
import subprocess
WATCH_DIR = "/var/www"
DB_FILE = "/root/db_size_mtime.json"
LOG_FILE = "/root/file_monitor.log"
EMAIL_TO = "root"
EMAIL_SUBJECT = "FILE MODIFIED (size+mtime)"
EXCLUDE_EXT = [".log", ".tmp"]
EXCLUDE_NAMES = ["hgrc"]
EXCLUDE_DIRS = [
"/var/www/logs",
"/var/www/tmp",
]
# ============================================
def is_excluded(path):
name = os.path.basename(path)
if name in EXCLUDE_NAMES:
return True
for d in EXCLUDE_DIRS:
if path.startswith(d):
return True
ext = os.path.splitext(name)[1]
return ext in EXCLUDE_EXT
def fingerprint(path):
st = os.stat(path)
return {
"size": st.st_size,
"mtime": int(st.st_mtime)
}
def load_db():
if os.path.exists(DB_FILE):
with open(DB_FILE, "r", encoding="utf-8") as f:
return json.load(f)
return {}
def save_db(db):
os.makedirs(os.path.dirname(DB_FILE), exist_ok=True)
with open(DB_FILE, "w", encoding="utf-8") as f:
json.dump(db, f, indent=2)
def scan():
data = {}
for root, dirs, files in os.walk(WATCH_DIR):
if any(root.startswith(d) for d in EXCLUDE_DIRS):
continue
for name in files:
path = os.path.join(root, name)
if is_excluded(path):
continue
try:
data[path] = fingerprint(path)
except Exception:
continue
return data
def log_changes(changes):
if not changes:
return
os.makedirs(os.path.dirname(LOG_FILE), exist_ok=True)
with open(LOG_FILE, "a", encoding="utf-8", errors="replace") as f:
f.write(f"\n[{time.strftime('%Y-%m-%d %H:%M:%S')}]\n")
for c in changes:
f.write(c + "\n")
def send_email(changes):
if not changes:
return
body = "\n".join(changes)
body = body.encode("utf-8", errors="replace").decode("utf-8")
msg = f"Subject: {EMAIL_SUBJECT}\n\n{body}"
try:
p = subprocess.Popen(
["/usr/sbin/sendmail", EMAIL_TO],
stdin=subprocess.PIPE
)
p.communicate(msg.encode("utf-8"))
except Exception as e:
print("[EMAIL ERROR]", e)
def main():
old = load_db()
new = scan()
changes = []
# Изменённые
for path, meta in new.items():
if path in old and old[path] != meta:
changes.append(f"MODIFIED: {path}")
# Удалённые
for path in old:
if path not in new:
changes.append(f"DELETED: {path}")
# Новые
for path in new:
if path not in old:
changes.append(f"NEW: {path}")
if changes:
log_changes(changes)
send_email(changes)
save_db(new)
if __name__ == "__main__":
main()
Сделаем файл исполняемым:
chmod +x ixnfo.com.py
./ixnfo.com.py
Добавим в cron:
02 7 * * * root /dir/ixnfo.com.py > /dev/null 2>&1
Смотрите также мои статьи:
Использование и настройка CRON
Скрипт проверки целостности файлов (хешами SHA-256)
