mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-20 14:30:59 +03:00
Add 5 new cybersecurity skills batch 2 - oauth token theft, binary exploitation, STIX2 sharing, linux audit logs, timestomping detection
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Mahipal
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
name: analyzing-linux-audit-logs-for-intrusion
|
||||
description: >
|
||||
Parse and analyze Linux auditd logs to detect intrusion indicators
|
||||
including unauthorized file access, privilege escalation, syscall
|
||||
anomalies, and suspicious process execution using ausearch and Python.
|
||||
domain: cybersecurity
|
||||
subdomain: log-analysis
|
||||
tags: [auditd, linux-forensics, syscall-monitoring, intrusion-detection]
|
||||
version: "1.0"
|
||||
author: mahipal
|
||||
license: Apache-2.0
|
||||
---
|
||||
|
||||
# Analyzing Linux Audit Logs for Intrusion
|
||||
|
||||
Parse auditd logs to detect file access violations, privilege escalation,
|
||||
suspicious syscalls, and unauthorized process execution.
|
||||
@@ -0,0 +1,89 @@
|
||||
# API Reference: Analyzing Linux Audit Logs for Intrusion
|
||||
|
||||
## Audit Log Location
|
||||
```
|
||||
/var/log/audit/audit.log
|
||||
```
|
||||
|
||||
## ausearch CLI
|
||||
```bash
|
||||
# Search by key
|
||||
ausearch -k file_access
|
||||
|
||||
# Search by message type
|
||||
ausearch -m EXECVE
|
||||
|
||||
# Failed events only
|
||||
ausearch --success no
|
||||
|
||||
# By user
|
||||
ausearch -ua 1000
|
||||
|
||||
# CSV output for Python processing
|
||||
ausearch --format csv > audit_events.csv
|
||||
|
||||
# By time range
|
||||
ausearch --start today --end now
|
||||
ausearch --start 01/15/2025 00:00:00 --end 01/16/2025 00:00:00
|
||||
```
|
||||
|
||||
## aureport CLI
|
||||
```bash
|
||||
# Summary report
|
||||
aureport --summary
|
||||
|
||||
# Authentication report
|
||||
aureport -au
|
||||
|
||||
# Failed events
|
||||
aureport --failed
|
||||
|
||||
# Executable report
|
||||
aureport -x
|
||||
|
||||
# File access report
|
||||
aureport -f
|
||||
|
||||
# Anomaly report
|
||||
aureport --anomaly
|
||||
```
|
||||
|
||||
## Audit Rules (auditctl)
|
||||
```bash
|
||||
# Monitor sensitive files
|
||||
auditctl -w /etc/passwd -p rwxa -k passwd_access
|
||||
auditctl -w /etc/shadow -p rwxa -k shadow_access
|
||||
auditctl -w /etc/sudoers -p rwxa -k sudoers_access
|
||||
|
||||
# Monitor privilege escalation
|
||||
auditctl -a always,exit -F arch=b64 -S execve -F euid=0 -F uid!=0 -k priv_esc
|
||||
|
||||
# Monitor module loading
|
||||
auditctl -a always,exit -F arch=b64 -S init_module -S finit_module -k modules
|
||||
|
||||
# Monitor network connections
|
||||
auditctl -a always,exit -F arch=b64 -S connect -k network_connect
|
||||
```
|
||||
|
||||
## Audit Log Fields
|
||||
| Field | Description |
|
||||
|-------|------------|
|
||||
| type | Event type (SYSCALL, PATH, EXECVE, USER_CMD) |
|
||||
| msg | audit(timestamp:event_id) |
|
||||
| syscall | System call number |
|
||||
| uid/euid | User ID / Effective UID |
|
||||
| comm | Command name |
|
||||
| exe | Executable path |
|
||||
| key | Audit rule key |
|
||||
| success | yes/no |
|
||||
| name | File path (in PATH records) |
|
||||
|
||||
## Suspicious Syscalls
|
||||
| Syscall | Concern |
|
||||
|---------|---------|
|
||||
| execve | Program execution |
|
||||
| ptrace | Process debugging/injection |
|
||||
| init_module | Kernel rootkit loading |
|
||||
| connect | Outbound connection |
|
||||
| setuid | Privilege change |
|
||||
| open_by_handle_at | Container escape |
|
||||
@@ -0,0 +1,222 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Linux audit log analysis agent for intrusion detection.
|
||||
|
||||
Parses /var/log/audit/audit.log entries to detect privilege escalation,
|
||||
unauthorized file access, suspicious syscalls, and process execution anomalies.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import datetime
|
||||
import collections
|
||||
import subprocess
|
||||
|
||||
|
||||
SUSPICIOUS_SYSCALLS = {
|
||||
"execve": "Program execution",
|
||||
"connect": "Network connection",
|
||||
"bind": "Port binding",
|
||||
"ptrace": "Process tracing/debugging",
|
||||
"init_module": "Kernel module loading",
|
||||
"finit_module": "Kernel module loading",
|
||||
"delete_module": "Kernel module unloading",
|
||||
"mount": "Filesystem mount",
|
||||
"umount2": "Filesystem unmount",
|
||||
"setuid": "UID change",
|
||||
"setgid": "GID change",
|
||||
"sethostname": "Hostname change",
|
||||
"open_by_handle_at": "File open by handle (container escape)",
|
||||
}
|
||||
|
||||
SENSITIVE_PATHS = [
|
||||
"/etc/passwd", "/etc/shadow", "/etc/sudoers",
|
||||
"/etc/ssh/sshd_config", "/root/.ssh/authorized_keys",
|
||||
"/etc/crontab", "/var/spool/cron",
|
||||
]
|
||||
|
||||
SUSPICIOUS_COMMANDS = [
|
||||
"curl", "wget", "nc", "ncat", "nmap", "tcpdump",
|
||||
"python", "perl", "ruby", "gcc", "cc", "make",
|
||||
"useradd", "usermod", "groupadd", "visudo",
|
||||
"iptables", "ip6tables", "nft",
|
||||
]
|
||||
|
||||
|
||||
def parse_audit_log(log_path, max_lines=50000):
|
||||
"""Parse raw audit.log file into structured events."""
|
||||
events = []
|
||||
current = {}
|
||||
try:
|
||||
with open(log_path, "r") as f:
|
||||
for i, line in enumerate(f):
|
||||
if i >= max_lines:
|
||||
break
|
||||
match = re.match(
|
||||
r"type=(\S+)\s+msg=audit\((\d+\.\d+):(\d+)\):\s*(.*)", line
|
||||
)
|
||||
if not match:
|
||||
continue
|
||||
event_type = match.group(1)
|
||||
timestamp = float(match.group(2))
|
||||
event_id = match.group(3)
|
||||
data_str = match.group(4)
|
||||
fields = dict(re.findall(r'(\w+)=("[^"]*"|\S+)', data_str))
|
||||
for k, v in fields.items():
|
||||
fields[k] = v.strip('"')
|
||||
event = {
|
||||
"type": event_type,
|
||||
"timestamp": datetime.datetime.fromtimestamp(timestamp).isoformat(),
|
||||
"event_id": event_id,
|
||||
**fields,
|
||||
}
|
||||
events.append(event)
|
||||
except FileNotFoundError:
|
||||
return {"error": f"Log file not found: {log_path}"}
|
||||
return events
|
||||
|
||||
|
||||
def detect_privilege_escalation(events):
|
||||
"""Detect privilege escalation indicators in audit events."""
|
||||
findings = []
|
||||
for e in events:
|
||||
if e.get("type") == "SYSCALL" and e.get("syscall_name") in ("setuid", "setgid", "execve"):
|
||||
if e.get("uid") != "0" and e.get("euid") == "0":
|
||||
findings.append({
|
||||
"type": "privilege_escalation",
|
||||
"detail": f"UID {e.get('uid')} escalated to eUID 0",
|
||||
"command": e.get("comm", ""),
|
||||
"exe": e.get("exe", ""),
|
||||
"timestamp": e.get("timestamp"),
|
||||
"severity": "CRITICAL",
|
||||
})
|
||||
if e.get("type") == "USER_CMD" and "sudo" in e.get("cmd", "").lower():
|
||||
findings.append({
|
||||
"type": "sudo_usage",
|
||||
"user": e.get("acct", e.get("uid", "")),
|
||||
"command": e.get("cmd", ""),
|
||||
"timestamp": e.get("timestamp"),
|
||||
"severity": "MEDIUM",
|
||||
})
|
||||
return findings
|
||||
|
||||
|
||||
def detect_file_access(events):
|
||||
"""Detect access to sensitive files."""
|
||||
findings = []
|
||||
for e in events:
|
||||
if e.get("type") in ("PATH", "SYSCALL"):
|
||||
path = e.get("name", e.get("exe", ""))
|
||||
for sensitive in SENSITIVE_PATHS:
|
||||
if sensitive in path:
|
||||
findings.append({
|
||||
"type": "sensitive_file_access",
|
||||
"path": path,
|
||||
"syscall": e.get("syscall_name", e.get("syscall", "")),
|
||||
"user": e.get("uid", ""),
|
||||
"timestamp": e.get("timestamp"),
|
||||
"severity": "HIGH",
|
||||
})
|
||||
break
|
||||
return findings
|
||||
|
||||
|
||||
def detect_suspicious_commands(events):
|
||||
"""Detect execution of suspicious commands."""
|
||||
findings = []
|
||||
for e in events:
|
||||
if e.get("type") in ("EXECVE", "SYSCALL"):
|
||||
comm = e.get("comm", "").lower()
|
||||
exe = e.get("exe", "").lower()
|
||||
for cmd in SUSPICIOUS_COMMANDS:
|
||||
if cmd in comm or cmd in exe:
|
||||
findings.append({
|
||||
"type": "suspicious_command",
|
||||
"command": comm,
|
||||
"exe": exe,
|
||||
"user": e.get("uid", ""),
|
||||
"timestamp": e.get("timestamp"),
|
||||
"severity": "MEDIUM",
|
||||
})
|
||||
break
|
||||
return findings
|
||||
|
||||
|
||||
def run_ausearch(key=None, message_type=None, success=None):
|
||||
"""Run ausearch command and return results."""
|
||||
cmd = ["ausearch"]
|
||||
if key:
|
||||
cmd.extend(["-k", key])
|
||||
if message_type:
|
||||
cmd.extend(["-m", message_type])
|
||||
if success is not None:
|
||||
cmd.extend(["--success", "yes" if success else "no"])
|
||||
cmd.extend(["--format", "csv"])
|
||||
try:
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
||||
return {"output": result.stdout[:5000], "exit_code": result.returncode}
|
||||
except (FileNotFoundError, subprocess.TimeoutExpired) as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
|
||||
def generate_summary(events, findings):
|
||||
"""Generate audit log analysis summary."""
|
||||
event_types = collections.Counter(e.get("type") for e in events)
|
||||
finding_types = collections.Counter(f.get("type") for f in findings)
|
||||
severity_counts = collections.Counter(f.get("severity") for f in findings)
|
||||
return {
|
||||
"total_events": len(events),
|
||||
"event_types": dict(event_types.most_common(10)),
|
||||
"total_findings": len(findings),
|
||||
"finding_types": dict(finding_types),
|
||||
"by_severity": dict(severity_counts),
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Linux audit log intrusion detection agent")
|
||||
parser.add_argument("log_file", nargs="?", default="/var/log/audit/audit.log",
|
||||
help="Path to audit.log (default: /var/log/audit/audit.log)")
|
||||
parser.add_argument("--max-lines", type=int, default=50000, help="Max log lines to parse")
|
||||
parser.add_argument("--ausearch-key", help="Run ausearch with this key")
|
||||
parser.add_argument("--output", "-o", help="Output JSON report path")
|
||||
args = parser.parse_args()
|
||||
|
||||
print("[*] Linux Audit Log Intrusion Detection Agent")
|
||||
|
||||
if args.ausearch_key:
|
||||
result = run_ausearch(key=args.ausearch_key)
|
||||
print(json.dumps(result, indent=2))
|
||||
sys.exit(0)
|
||||
|
||||
events = parse_audit_log(args.log_file, args.max_lines)
|
||||
if isinstance(events, dict) and "error" in events:
|
||||
print(f"[!] {events['error']}")
|
||||
print("[DEMO] Specify a valid audit.log path or run on a Linux system")
|
||||
print(json.dumps({"demo": True, "monitored_syscalls": len(SUSPICIOUS_SYSCALLS)}, indent=2))
|
||||
sys.exit(0)
|
||||
|
||||
findings = []
|
||||
findings.extend(detect_privilege_escalation(events))
|
||||
findings.extend(detect_file_access(events))
|
||||
findings.extend(detect_suspicious_commands(events))
|
||||
|
||||
summary = generate_summary(events, findings)
|
||||
print(f"[*] Events parsed: {summary['total_events']}")
|
||||
print(f"[*] Findings: {summary['total_findings']}")
|
||||
print(f" By severity: {summary['by_severity']}")
|
||||
for f in findings[:15]:
|
||||
print(f" [{f['severity']}] {f['type']}: {f.get('command', f.get('path', ''))}")
|
||||
|
||||
if args.output:
|
||||
report = {"summary": summary, "findings": findings}
|
||||
with open(args.output, "w") as f:
|
||||
json.dump(report, f, indent=2, default=str)
|
||||
|
||||
print(json.dumps(summary, indent=2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user