Загрузить файлы в «/»
This commit is contained in:
commit
3203b4a20c
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
.venv/
|
||||||
|
.idea/
|
||||||
4
README.md
Normal file
4
README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# SOC Assistant - Система анализа журнала событий информационной безопасности
|
||||||
|
|
||||||
|
SOC Assistant (Security Operations Center Assistant) - это набор утилит для обработки и анализа журналов событий (логов) системы обнаружения вторжений. Система позволяет загружать сырые данные из текстового файла, очищать их, обогащать, агрегировать и формировать аналитическую сводку для выявления потенциальных угроз безопасности.
|
||||||
|
|
||||||
246
import os.py
Normal file
246
import os.py
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def load_logs(filepath):
|
||||||
|
"""Загружает логи из файла"""
|
||||||
|
try:
|
||||||
|
with open(filepath, 'r', encoding='utf-8') as f:
|
||||||
|
lines = []
|
||||||
|
for line in f:
|
||||||
|
if line.strip():
|
||||||
|
lines.append(line.strip())
|
||||||
|
return lines
|
||||||
|
except:
|
||||||
|
print("Ошибка при загрузке файла")
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def parse_line(line):
|
||||||
|
"""Разбирает одну строку лога"""
|
||||||
|
try:
|
||||||
|
# Ищем закрывающую скобку
|
||||||
|
bracket_pos = line.find(']')
|
||||||
|
if bracket_pos == -1:
|
||||||
|
return None
|
||||||
|
|
||||||
|
timestamp = line[1:bracket_pos] # Убираем первую скобку
|
||||||
|
rest = line[bracket_pos + 2:] # Пропускаем '] '
|
||||||
|
|
||||||
|
# Делим на тип и остальное
|
||||||
|
parts = rest.split(' ', 1)
|
||||||
|
event_type = parts[0]
|
||||||
|
|
||||||
|
details = {}
|
||||||
|
if len(parts) > 1:
|
||||||
|
params = parts[1].split()
|
||||||
|
for param in params:
|
||||||
|
if '=' in param:
|
||||||
|
key, value = param.split('=', 1)
|
||||||
|
details[key] = value
|
||||||
|
|
||||||
|
return {"timestamp": timestamp, "event_type": event_type, "details": details}
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_ips(logs):
|
||||||
|
"""Собирает все IP из логов"""
|
||||||
|
ips = []
|
||||||
|
for log in logs:
|
||||||
|
if 'IP' in log.get('details', {}):
|
||||||
|
ip = log['details']['IP']
|
||||||
|
if ip not in ips:
|
||||||
|
ips.append(ip)
|
||||||
|
return ips
|
||||||
|
|
||||||
|
|
||||||
|
def count_events(logs):
|
||||||
|
"""Считает сколько каких событий"""
|
||||||
|
counts = {}
|
||||||
|
for log in logs:
|
||||||
|
event = log['event_type']
|
||||||
|
if event in counts:
|
||||||
|
counts[event] += 1
|
||||||
|
else:
|
||||||
|
counts[event] = 1
|
||||||
|
return counts
|
||||||
|
|
||||||
|
|
||||||
|
def find_bad_ips(logs, threshold):
|
||||||
|
"""Ищет IP с большим числом неудачных входов"""
|
||||||
|
failed = []
|
||||||
|
for log in logs:
|
||||||
|
if log['event_type'] == 'FAILED_LOGIN' and 'IP' in log['details']:
|
||||||
|
failed.append(log['details']['IP'])
|
||||||
|
|
||||||
|
ip_counts = {}
|
||||||
|
for ip in failed:
|
||||||
|
if ip in ip_counts:
|
||||||
|
ip_counts[ip] += 1
|
||||||
|
else:
|
||||||
|
ip_counts[ip] = 1
|
||||||
|
|
||||||
|
bad_ips = []
|
||||||
|
for ip, count in ip_counts.items():
|
||||||
|
if count > threshold:
|
||||||
|
bad_ips.append(ip)
|
||||||
|
|
||||||
|
return bad_ips
|
||||||
|
|
||||||
|
|
||||||
|
def add_severity(event):
|
||||||
|
"""Добавляет уровень важности"""
|
||||||
|
new_event = event.copy()
|
||||||
|
if event['event_type'] == 'FAILED_LOGIN':
|
||||||
|
new_event['severity'] = 'HIGH'
|
||||||
|
elif event['event_type'] == 'FILE_DELETE':
|
||||||
|
new_event['severity'] = 'CRITICAL'
|
||||||
|
else:
|
||||||
|
new_event['severity'] = 'LOW'
|
||||||
|
return new_event
|
||||||
|
|
||||||
|
|
||||||
|
def make_report(stats, bad_ips, total):
|
||||||
|
"""Создает текстовый отчет"""
|
||||||
|
report = []
|
||||||
|
report.append("=" * 50)
|
||||||
|
report.append("ОТЧЕТ ПО ЛОГАМ")
|
||||||
|
report.append("=" * 50)
|
||||||
|
report.append("")
|
||||||
|
|
||||||
|
report.append("Статистика по событиям:")
|
||||||
|
report.append("-" * 30)
|
||||||
|
# Сортируем события по количеству
|
||||||
|
sorted_events = sorted(stats.items(), key=lambda x: x[1], reverse=True)
|
||||||
|
for i, (event, count) in enumerate(sorted_events[:3], 1):
|
||||||
|
report.append(f"{i}. {event}: {count}")
|
||||||
|
|
||||||
|
report.append("")
|
||||||
|
report.append("Подозрительные IP:")
|
||||||
|
report.append("-" * 30)
|
||||||
|
if bad_ips:
|
||||||
|
for ip in bad_ips:
|
||||||
|
report.append(f"• {ip}")
|
||||||
|
else:
|
||||||
|
report.append("Нет подозрительных IP")
|
||||||
|
|
||||||
|
report.append("")
|
||||||
|
report.append(f"Всего событий: {total}")
|
||||||
|
report.append("")
|
||||||
|
report.append("=" * 50)
|
||||||
|
|
||||||
|
return "\n".join(report)
|
||||||
|
|
||||||
|
|
||||||
|
def save_report(text, path):
|
||||||
|
"""Сохраняет отчет в файл"""
|
||||||
|
try:
|
||||||
|
# Создаем папку если нужно
|
||||||
|
folder = path[:path.rfind('/')]
|
||||||
|
if folder:
|
||||||
|
os.makedirs(folder, exist_ok=True)
|
||||||
|
|
||||||
|
with open(path, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(text)
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
print("Не удалось сохранить отчет")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("Начинаем анализ логов...")
|
||||||
|
print("-" * 40)
|
||||||
|
|
||||||
|
# Загружаем логи
|
||||||
|
lines = load_logs("data/security.log")
|
||||||
|
if not lines:
|
||||||
|
print("Нет данных для анализа")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"Загружено строк: {len(lines)}")
|
||||||
|
|
||||||
|
# Парсим логи
|
||||||
|
logs = []
|
||||||
|
bad_lines = 0
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
parsed = parse_line(line)
|
||||||
|
if parsed:
|
||||||
|
logs.append(parsed)
|
||||||
|
else:
|
||||||
|
bad_lines += 1
|
||||||
|
|
||||||
|
if bad_lines:
|
||||||
|
print(f"Не удалось разобрать {bad_lines} строк")
|
||||||
|
else:
|
||||||
|
print(f"Разобрано событий: {len(logs)}")
|
||||||
|
|
||||||
|
if not logs:
|
||||||
|
print("Нет событий для анализа")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Считаем неудачные входы
|
||||||
|
failed = 0
|
||||||
|
for log in logs:
|
||||||
|
if log['event_type'] == 'FAILED_LOGIN':
|
||||||
|
failed += 1
|
||||||
|
print(f"Неудачных попыток входа: {failed}")
|
||||||
|
|
||||||
|
# Собираем статистику
|
||||||
|
stats = count_events(logs)
|
||||||
|
print("\nТипы событий:")
|
||||||
|
for event, count in stats.items():
|
||||||
|
print(f" {event}: {count}")
|
||||||
|
|
||||||
|
# Ищем подозрительные IP
|
||||||
|
bad_ips = find_bad_ips(logs, 3)
|
||||||
|
print(f"\nНайдено IP с брутфорсом: {len(bad_ips)}")
|
||||||
|
|
||||||
|
# Показываем пример обогащения
|
||||||
|
print("\nПример добавления уровня критичности:")
|
||||||
|
for i in range(min(3, len(logs))):
|
||||||
|
enriched = add_severity(logs[i])
|
||||||
|
print(f" {logs[i]['event_type']} -> {enriched['severity']}")
|
||||||
|
|
||||||
|
# Создаем отчет
|
||||||
|
report = make_report(stats, bad_ips, len(logs))
|
||||||
|
|
||||||
|
# Сохраняем
|
||||||
|
if save_report(report, "reports/security_summary.txt"):
|
||||||
|
print("\nОтчет сохранен в reports/security_summary.txt")
|
||||||
|
else:
|
||||||
|
print("\nОшибка при сохранении отчета")
|
||||||
|
|
||||||
|
print("\nГотово!")
|
||||||
|
|
||||||
|
|
||||||
|
# Создаем тестовые данные
|
||||||
|
def create_test_file():
|
||||||
|
os.makedirs("data", exist_ok=True)
|
||||||
|
|
||||||
|
test_data = [
|
||||||
|
"[2023-10-01 12:05:45] FAILED_LOGIN User=admin IP=192.168.1.10",
|
||||||
|
"[2023-10-01 12:06:12] FAILED_LOGIN User=admin IP=192.168.1.10",
|
||||||
|
"[2023-10-01 12:06:45] FAILED_LOGIN User=admin IP=192.168.1.10",
|
||||||
|
"[2023-10-01 12:07:23] FAILED_LOGIN User=admin IP=192.168.1.10",
|
||||||
|
"[2023-10-01 12:08:01] SUCCESS User=admin IP=192.168.1.10",
|
||||||
|
"[2023-10-01 12:10:15] FAILED_LOGIN User=root IP=10.0.0.5",
|
||||||
|
"[2023-10-01 12:11:30] FAILED_LOGIN User=root IP=10.0.0.5",
|
||||||
|
"[2023-10-01 12:12:45] FAILED_LOGIN User=root IP=10.0.0.5",
|
||||||
|
"[2023-10-01 12:14:00] FAILED_LOGIN User=root IP=10.0.0.5",
|
||||||
|
"[2023-10-01 12:15:20] FAILED_LOGIN User=root IP=10.0.0.5",
|
||||||
|
"[2023-10-01 12:16:45] FILE_DELETE User=backup File=/etc/passwd IP=192.168.1.20",
|
||||||
|
"[2023-10-01 12:20:10] INFO Service=web Status=running",
|
||||||
|
]
|
||||||
|
|
||||||
|
with open("data/security.log", 'w', encoding='utf-8') as f:
|
||||||
|
for line in test_data:
|
||||||
|
f.write(line + "\n")
|
||||||
|
|
||||||
|
print("Создан тестовый файл data/security.log")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
create_test_file()
|
||||||
|
main()
|
||||||
Loading…
Reference in New Issue
Block a user