mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-11 21:54:56 +03:00
282 lines
9.4 KiB
Python
282 lines
9.4 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
NextDNS Zero Trust DNS Configuration and Monitoring.
|
|
|
|
Manages NextDNS profiles, analyzes DNS logs for threats,
|
|
and generates compliance reports for DNS security posture.
|
|
"""
|
|
|
|
import json
|
|
import datetime
|
|
from dataclasses import dataclass, field
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
import math
|
|
|
|
|
|
@dataclass
|
|
class DNSPolicy:
|
|
name: str
|
|
security_features: list = field(default_factory=list)
|
|
privacy_blocklists: list = field(default_factory=list)
|
|
native_tracking: list = field(default_factory=list)
|
|
allowlist: list = field(default_factory=list)
|
|
denylist: list = field(default_factory=list)
|
|
log_retention_days: int = 90
|
|
|
|
|
|
@dataclass
|
|
class DNSQueryLog:
|
|
timestamp: str
|
|
domain: str
|
|
query_type: str
|
|
status: str # "allowed", "blocked"
|
|
blocked_reason: str = ""
|
|
device: str = ""
|
|
client_ip: str = ""
|
|
|
|
|
|
class NextDNSPolicyGenerator:
|
|
"""Generate NextDNS configuration profiles."""
|
|
|
|
SECURITY_FEATURES = [
|
|
"threat_intelligence_feeds",
|
|
"ai_driven_threat_detection",
|
|
"google_safe_browsing",
|
|
"cryptojacking_protection",
|
|
"dns_rebinding_protection",
|
|
"idn_homograph_attacks",
|
|
"typosquatting_protection",
|
|
"dga_protection",
|
|
"nrd_protection",
|
|
"ddns_blocking",
|
|
"parked_domains",
|
|
"csam_blocking",
|
|
]
|
|
|
|
PRIVACY_BLOCKLISTS = [
|
|
"nextdns_recommended",
|
|
"oisd_full",
|
|
"easyprivacy",
|
|
"adguard_dns_filter",
|
|
"hagezi_pro",
|
|
"steven_black_unified",
|
|
]
|
|
|
|
NATIVE_TRACKING = [
|
|
"windows", "apple", "samsung", "xiaomi",
|
|
"huawei", "roku", "sonos", "alexa",
|
|
]
|
|
|
|
def create_enterprise_policy(self, name: str) -> DNSPolicy:
|
|
return DNSPolicy(
|
|
name=name,
|
|
security_features=self.SECURITY_FEATURES.copy(),
|
|
privacy_blocklists=["nextdns_recommended", "oisd_full", "easyprivacy"],
|
|
native_tracking=["windows", "apple"],
|
|
log_retention_days=90,
|
|
)
|
|
|
|
def create_strict_policy(self, name: str) -> DNSPolicy:
|
|
return DNSPolicy(
|
|
name=name,
|
|
security_features=self.SECURITY_FEATURES.copy(),
|
|
privacy_blocklists=self.PRIVACY_BLOCKLISTS.copy(),
|
|
native_tracking=self.NATIVE_TRACKING.copy(),
|
|
log_retention_days=365,
|
|
)
|
|
|
|
def create_minimal_policy(self, name: str) -> DNSPolicy:
|
|
return DNSPolicy(
|
|
name=name,
|
|
security_features=[
|
|
"threat_intelligence_feeds",
|
|
"cryptojacking_protection",
|
|
"dns_rebinding_protection",
|
|
"dga_protection",
|
|
"nrd_protection",
|
|
],
|
|
privacy_blocklists=["nextdns_recommended"],
|
|
native_tracking=[],
|
|
log_retention_days=30,
|
|
)
|
|
|
|
def export_policy(self, policy: DNSPolicy, output_path: str):
|
|
config = {
|
|
"name": policy.name,
|
|
"security": {
|
|
"features_enabled": policy.security_features,
|
|
},
|
|
"privacy": {
|
|
"blocklists": policy.privacy_blocklists,
|
|
"native_tracking_protection": policy.native_tracking,
|
|
"block_cname_cloaking": True,
|
|
},
|
|
"allowlist": policy.allowlist,
|
|
"denylist": policy.denylist,
|
|
"logging": {
|
|
"enabled": True,
|
|
"retention_days": policy.log_retention_days,
|
|
"storage_location": "US",
|
|
},
|
|
}
|
|
path = Path(output_path)
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
with open(path, "w") as f:
|
|
json.dump(config, f, indent=2)
|
|
return config
|
|
|
|
|
|
class DNSLogAnalyzer:
|
|
"""Analyze DNS query logs for security threats."""
|
|
|
|
def __init__(self):
|
|
self.logs: list[DNSQueryLog] = []
|
|
self.findings: list[dict] = []
|
|
|
|
def add_log(self, log: DNSQueryLog):
|
|
self.logs.append(log)
|
|
|
|
def calculate_entropy(self, domain: str) -> float:
|
|
"""Calculate Shannon entropy of a domain name (DNS tunneling indicator)."""
|
|
label = domain.split(".")[0]
|
|
if not label:
|
|
return 0.0
|
|
freq = {}
|
|
for c in label:
|
|
freq[c] = freq.get(c, 0) + 1
|
|
entropy = 0.0
|
|
for count in freq.values():
|
|
p = count / len(label)
|
|
if p > 0:
|
|
entropy -= p * math.log2(p)
|
|
return entropy
|
|
|
|
def detect_dns_tunneling(self, threshold: float = 4.0) -> list[dict]:
|
|
"""Detect potential DNS tunneling based on subdomain entropy and length."""
|
|
suspects = []
|
|
for log in self.logs:
|
|
if log.status == "blocked":
|
|
continue
|
|
subdomain = log.domain.split(".")[0]
|
|
entropy = self.calculate_entropy(log.domain)
|
|
if entropy > threshold and len(subdomain) > 20:
|
|
suspects.append({
|
|
"domain": log.domain,
|
|
"entropy": round(entropy, 2),
|
|
"subdomain_length": len(subdomain),
|
|
"device": log.device,
|
|
"timestamp": log.timestamp,
|
|
})
|
|
if suspects:
|
|
self.findings.append({
|
|
"type": "dns_tunneling_suspect",
|
|
"severity": "HIGH",
|
|
"count": len(suspects),
|
|
"details": suspects[:20],
|
|
})
|
|
return suspects
|
|
|
|
def detect_dga_domains(self) -> list[dict]:
|
|
"""Detect domain generation algorithm patterns."""
|
|
suspects = []
|
|
for log in self.logs:
|
|
parts = log.domain.split(".")
|
|
if len(parts) >= 2:
|
|
sld = parts[-2]
|
|
entropy = self.calculate_entropy(sld + "." + parts[-1])
|
|
if entropy > 3.5 and len(sld) > 8 and not any(
|
|
c in sld for c in ["-", "_"]
|
|
):
|
|
digits = sum(1 for c in sld if c.isdigit())
|
|
if digits / len(sld) > 0.3:
|
|
suspects.append({
|
|
"domain": log.domain,
|
|
"entropy": round(entropy, 2),
|
|
"digit_ratio": round(digits / len(sld), 2),
|
|
})
|
|
if suspects:
|
|
self.findings.append({
|
|
"type": "dga_domain_suspect",
|
|
"severity": "HIGH",
|
|
"count": len(suspects),
|
|
"details": suspects[:20],
|
|
})
|
|
return suspects
|
|
|
|
def get_blocked_summary(self) -> dict:
|
|
"""Summarize blocked queries by reason."""
|
|
blocked = [l for l in self.logs if l.status == "blocked"]
|
|
by_reason = {}
|
|
for log in blocked:
|
|
reason = log.blocked_reason or "unknown"
|
|
by_reason[reason] = by_reason.get(reason, 0) + 1
|
|
|
|
by_domain = {}
|
|
for log in blocked:
|
|
by_domain[log.domain] = by_domain.get(log.domain, 0) + 1
|
|
|
|
top_blocked = sorted(by_domain.items(), key=lambda x: x[1], reverse=True)[:20]
|
|
|
|
return {
|
|
"total_blocked": len(blocked),
|
|
"total_allowed": len(self.logs) - len(blocked),
|
|
"block_rate": round(len(blocked) / len(self.logs) * 100, 2) if self.logs else 0,
|
|
"by_reason": by_reason,
|
|
"top_blocked_domains": dict(top_blocked),
|
|
}
|
|
|
|
def generate_report(self) -> dict:
|
|
return {
|
|
"report_date": datetime.datetime.now().isoformat(),
|
|
"total_queries": len(self.logs),
|
|
"blocked_summary": self.get_blocked_summary(),
|
|
"security_findings": self.findings,
|
|
"unique_devices": len(set(l.device for l in self.logs if l.device)),
|
|
"unique_domains": len(set(l.domain for l in self.logs)),
|
|
}
|
|
|
|
|
|
def main():
|
|
"""Demonstrate NextDNS policy generation and DNS log analysis."""
|
|
# Generate policies
|
|
gen = NextDNSPolicyGenerator()
|
|
enterprise = gen.create_enterprise_policy("Enterprise Standard")
|
|
enterprise.allowlist = ["login.microsoftonline.com", "graph.microsoft.com", "*.company.com"]
|
|
enterprise.denylist = ["malware-c2.example.com", "data-exfil.example.com"]
|
|
|
|
config = gen.export_policy(enterprise, "nextdns_enterprise_policy.json")
|
|
print("Enterprise DNS Policy:")
|
|
print(json.dumps(config, indent=2))
|
|
|
|
# Analyze sample DNS logs
|
|
analyzer = DNSLogAnalyzer()
|
|
sample_logs = [
|
|
DNSQueryLog("2024-01-15T10:00:00Z", "google.com", "A", "allowed", device="laptop-1"),
|
|
DNSQueryLog("2024-01-15T10:00:01Z", "malware.example.com", "A", "blocked",
|
|
"threat_intelligence", "laptop-2"),
|
|
DNSQueryLog("2024-01-15T10:00:02Z", "aHR0cHM6Ly9leGFtcGxlLmNvbQ.tunnel.evil.com",
|
|
"TXT", "allowed", device="server-1"),
|
|
DNSQueryLog("2024-01-15T10:00:03Z", "x8k3m9p2q5.botnet.com", "A", "blocked",
|
|
"dga_protection", "laptop-3"),
|
|
DNSQueryLog("2024-01-15T10:00:04Z", "office.com", "A", "allowed", device="laptop-1"),
|
|
DNSQueryLog("2024-01-15T10:00:05Z", "ads.tracker.com", "A", "blocked",
|
|
"ad_blocker", "laptop-1"),
|
|
]
|
|
|
|
for log in sample_logs:
|
|
analyzer.add_log(log)
|
|
|
|
analyzer.detect_dns_tunneling()
|
|
analyzer.detect_dga_domains()
|
|
|
|
report = analyzer.generate_report()
|
|
print("\n" + "=" * 60)
|
|
print("DNS Security Analysis Report")
|
|
print("=" * 60)
|
|
print(json.dumps(report, indent=2))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|