Untitled

 avatar
Lattuse
plain_text
10 months ago
3.3 kB
20
Indexable
#!/usr/bin/env python3
"""
security_log_analyzer.py
Optional version with visualization (matplotlib)
"""

import re
import os
import sys
from collections import Counter
import argparse
import matplotlib.pyplot as plt

parser = argparse.ArgumentParser(description='Security Log Analyzer with Visualization')
parser.add_argument('--log', default='/var/log/auth.log',
                    help='Path to auth log (default: /var/log/auth.log)')
args = parser.parse_args()

log_path = args.log
if not os.path.exists(log_path):
    if os.path.exists('sample_log.txt'):
        print(f"{log_path} not found — using sample_log.txt instead")
        log_path = 'sample_log.txt'
    else:
        print(f"No log file found at {args.log} and no sample_log.txt present.")
        sys.exit(1)

ip_re = re.compile(r'\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b')
u1 = re.compile(r'for (?:invalid user )?([^\s:]+)')
u2 = re.compile(r'user=([^\s,;]+)')

ip_counts = Counter()
user_counts = Counter()

with open(log_path, 'r', errors='ignore') as fh:
    for line in fh:
        if re.search(r'(?i)failed|failure|invalid user|authentication failure|Failed password', line):
            ips = ip_re.findall(line)
            for ip in ips:
                ip_counts[ip] += 1
            m = u1.search(line) or u2.search(line)
            if m:
                user_counts[m.group(1)] += 1

# Save suspicious activity to file
with open('suspicious_activity.txt', 'w') as out:
    out.write('IP,attempts\n')
    for ip, cnt in ip_counts.most_common():
        out.write(f'{ip},{cnt}\n')

print(f"Wrote suspicious_activity.txt ({len(ip_counts)} unique IPs)")

# Check for insecure home directories
insecure = []
if os.path.exists('/etc/passwd'):
    with open('/etc/passwd') as pf:
        for line in pf:
            parts = line.strip().split(':')
            if len(parts) < 6:
                continue
            username, home = parts[0], parts[5]
            if not home or not os.path.isdir(home):
                continue
            try:
                mode = os.stat(home).st_mode & 0o777
                if mode == 0o777 or (mode & 0o077) == 0o077:
                    insecure.append((username, home, oct(mode)))
            except Exception:
                continue

with open('insecure_homes.txt', 'w') as out:
    if insecure:
        out.write('username:home:mode\n')
        for u, h, m in insecure:
            out.write(f'{u}:{h}:{m}\n')
        print(f"Wrote insecure_homes.txt ({len(insecure)} insecure dirs found)")
    else:
        out.write('No insecure home directories found\n')
        print("No insecure home directories found")

# ---------- Visualization Section ----------
if ip_counts:
    # Take top 10 IPs for readability
    top_ips = ip_counts.most_common(10)
    ips, counts = zip(*top_ips)

    plt.figure(figsize=(10, 5))
    plt.bar(ips, counts, color='tomato')
    plt.title('Top 10 IPs with Failed Login Attempts')
    plt.xlabel('IP Address')
    plt.ylabel('Number of Failed Attempts')
    plt.xticks(rotation=45, ha='right')
    plt.tight_layout()

    plt.savefig('failed_login_stats.png')
    print("Saved visualization as failed_login_stats.png")
else:
    print("No failed login attempts found — skipping visualization.")
Editor is loading...
Leave a Comment