mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-26 03:34:37 +03:00
Add folder anatomy (scripts/agent.py + references/api-reference.md) for 648 cybersecurity skills
Complete skill folder anatomy across all cybersecurity skills: - scripts/agent.py: 80-150 line Python agents using real libraries (impacket, boto3, azure-mgmt-*, kubernetes, pefile, yara, scapy, shodan, stix2, etc.) - references/api-reference.md: real API documentation with method signatures - LICENSE: MIT license for all skill folders
This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Log Integrity Chain Agent - Implements SHA-256 hash-chained append-only log for tamper detection."""
|
||||
|
||||
import json
|
||||
import hashlib
|
||||
import logging
|
||||
import argparse
|
||||
from datetime import datetime
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
GENESIS_HASH = "0" * 64
|
||||
|
||||
|
||||
def compute_hash(data):
|
||||
"""Compute SHA-256 hash of a string."""
|
||||
return hashlib.sha256(data.encode("utf-8")).hexdigest()
|
||||
|
||||
|
||||
def create_chain_entry(index, timestamp, content, prev_hash):
|
||||
"""Create a single chain entry with hash linking."""
|
||||
content_hash = compute_hash(content)
|
||||
chain_input = f"{prev_hash}{timestamp}{content_hash}"
|
||||
chain_hash = compute_hash(chain_input)
|
||||
return {
|
||||
"index": index,
|
||||
"timestamp": timestamp,
|
||||
"content_hash": content_hash,
|
||||
"prev_hash": prev_hash,
|
||||
"chain_hash": chain_hash,
|
||||
"content_preview": content[:200],
|
||||
}
|
||||
|
||||
|
||||
def load_chain(chain_file):
|
||||
"""Load an existing hash chain from a JSON file."""
|
||||
try:
|
||||
with open(chain_file, "r") as f:
|
||||
chain = json.load(f)
|
||||
logger.info("Loaded chain with %d entries from %s", len(chain), chain_file)
|
||||
return chain
|
||||
except FileNotFoundError:
|
||||
logger.info("No existing chain found, starting new chain")
|
||||
return []
|
||||
|
||||
|
||||
def save_chain(chain, chain_file):
|
||||
"""Save the hash chain to a JSON file."""
|
||||
with open(chain_file, "w") as f:
|
||||
json.dump(chain, f, indent=2)
|
||||
logger.info("Saved chain with %d entries to %s", len(chain), chain_file)
|
||||
|
||||
|
||||
def ingest_log_file(log_file):
|
||||
"""Read log entries from a file (one entry per line)."""
|
||||
entries = []
|
||||
with open(log_file, "r", errors="ignore") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line:
|
||||
entries.append(line)
|
||||
logger.info("Read %d log entries from %s", len(entries), log_file)
|
||||
return entries
|
||||
|
||||
|
||||
def ingest_json_log(json_file):
|
||||
"""Read structured log entries from a JSON array file."""
|
||||
with open(json_file, "r") as f:
|
||||
data = json.load(f)
|
||||
entries = []
|
||||
if isinstance(data, list):
|
||||
for item in data:
|
||||
entries.append(json.dumps(item, sort_keys=True))
|
||||
logger.info("Read %d JSON log entries from %s", len(entries), json_file)
|
||||
return entries
|
||||
|
||||
|
||||
def append_entries(chain, log_entries):
|
||||
"""Append new log entries to the hash chain."""
|
||||
prev_hash = chain[-1]["chain_hash"] if chain else GENESIS_HASH
|
||||
start_index = len(chain)
|
||||
new_entries = []
|
||||
for i, content in enumerate(log_entries):
|
||||
timestamp = datetime.utcnow().isoformat() + "Z"
|
||||
entry = create_chain_entry(start_index + i, timestamp, content, prev_hash)
|
||||
chain.append(entry)
|
||||
new_entries.append(entry)
|
||||
prev_hash = entry["chain_hash"]
|
||||
logger.info("Appended %d entries to chain (total: %d)", len(new_entries), len(chain))
|
||||
return new_entries
|
||||
|
||||
|
||||
def verify_chain(chain):
|
||||
"""Verify the integrity of the entire hash chain."""
|
||||
if not chain:
|
||||
return {"valid": True, "entries_checked": 0, "breaks": []}
|
||||
breaks = []
|
||||
prev_hash = GENESIS_HASH
|
||||
for entry in chain:
|
||||
expected_input = f"{prev_hash}{entry['timestamp']}{entry['content_hash']}"
|
||||
expected_hash = compute_hash(expected_input)
|
||||
if entry["chain_hash"] != expected_hash:
|
||||
breaks.append({
|
||||
"index": entry["index"],
|
||||
"expected_hash": expected_hash,
|
||||
"actual_hash": entry["chain_hash"],
|
||||
"prev_hash_match": entry["prev_hash"] == prev_hash,
|
||||
})
|
||||
if entry["prev_hash"] != prev_hash:
|
||||
breaks.append({
|
||||
"index": entry["index"],
|
||||
"issue": "prev_hash mismatch",
|
||||
"expected_prev": prev_hash,
|
||||
"actual_prev": entry["prev_hash"],
|
||||
})
|
||||
prev_hash = entry["chain_hash"]
|
||||
valid = len(breaks) == 0
|
||||
logger.info("Chain verification: %d entries checked, %d breaks found", len(chain), len(breaks))
|
||||
return {"valid": valid, "entries_checked": len(chain), "breaks": breaks}
|
||||
|
||||
|
||||
def find_tampered_range(breaks):
|
||||
"""Identify the range of entries affected by tampering."""
|
||||
if not breaks:
|
||||
return None
|
||||
first_break = min(b["index"] for b in breaks)
|
||||
return {
|
||||
"first_tampered_entry": first_break,
|
||||
"total_affected": len(breaks),
|
||||
"tamper_start_index": first_break,
|
||||
"note": f"All entries from index {first_break} onward may be compromised",
|
||||
}
|
||||
|
||||
|
||||
def create_checkpoint(chain, checkpoint_file):
|
||||
"""Create an integrity checkpoint with the current chain head hash."""
|
||||
if not chain:
|
||||
return None
|
||||
checkpoint = {
|
||||
"timestamp": datetime.utcnow().isoformat() + "Z",
|
||||
"chain_length": len(chain),
|
||||
"head_hash": chain[-1]["chain_hash"],
|
||||
"head_index": chain[-1]["index"],
|
||||
"genesis_hash": GENESIS_HASH,
|
||||
"checkpoint_hash": compute_hash(f"{len(chain)}{chain[-1]['chain_hash']}"),
|
||||
}
|
||||
with open(checkpoint_file, "w") as f:
|
||||
json.dump(checkpoint, f, indent=2)
|
||||
logger.info("Created checkpoint at index %d: %s", checkpoint["head_index"], checkpoint["checkpoint_hash"][:16])
|
||||
return checkpoint
|
||||
|
||||
|
||||
def verify_checkpoint(chain, checkpoint_file):
|
||||
"""Verify chain against a previously saved checkpoint."""
|
||||
with open(checkpoint_file, "r") as f:
|
||||
checkpoint = json.load(f)
|
||||
cp_index = checkpoint["head_index"]
|
||||
if cp_index >= len(chain):
|
||||
return {"valid": False, "error": "Chain shorter than checkpoint"}
|
||||
actual_hash = chain[cp_index]["chain_hash"]
|
||||
valid = actual_hash == checkpoint["head_hash"]
|
||||
return {
|
||||
"valid": valid,
|
||||
"checkpoint_index": cp_index,
|
||||
"expected_hash": checkpoint["head_hash"],
|
||||
"actual_hash": actual_hash,
|
||||
}
|
||||
|
||||
|
||||
def generate_report(verification, checkpoint, chain_length):
|
||||
"""Generate log integrity verification report."""
|
||||
report = {
|
||||
"timestamp": datetime.utcnow().isoformat(),
|
||||
"chain_length": chain_length,
|
||||
"integrity_valid": verification["valid"],
|
||||
"entries_checked": verification["entries_checked"],
|
||||
"breaks_found": len(verification["breaks"]),
|
||||
"break_details": verification["breaks"][:20],
|
||||
"checkpoint": checkpoint,
|
||||
}
|
||||
status = "INTACT" if verification["valid"] else "TAMPERED"
|
||||
print(f"LOG INTEGRITY: {status} - {chain_length} entries, {len(verification['breaks'])} breaks")
|
||||
return report
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Log Integrity Chain Agent")
|
||||
parser.add_argument("--log-file", help="Log file to ingest")
|
||||
parser.add_argument("--chain-file", default="log_chain.json", help="Hash chain storage file")
|
||||
parser.add_argument("--verify", action="store_true", help="Verify chain integrity")
|
||||
parser.add_argument("--checkpoint", help="Create/verify checkpoint file")
|
||||
parser.add_argument("--output", default="integrity_report.json")
|
||||
args = parser.parse_args()
|
||||
|
||||
chain = load_chain(args.chain_file)
|
||||
|
||||
if args.log_file:
|
||||
entries = ingest_log_file(args.log_file)
|
||||
append_entries(chain, entries)
|
||||
save_chain(chain, args.chain_file)
|
||||
|
||||
verification = {"valid": True, "entries_checked": 0, "breaks": []}
|
||||
if args.verify:
|
||||
verification = verify_chain(chain)
|
||||
|
||||
checkpoint = None
|
||||
if args.checkpoint:
|
||||
if args.verify:
|
||||
checkpoint = verify_checkpoint(chain, args.checkpoint)
|
||||
else:
|
||||
checkpoint = create_checkpoint(chain, args.checkpoint)
|
||||
|
||||
report = generate_report(verification, checkpoint, len(chain))
|
||||
with open(args.output, "w") as f:
|
||||
json.dump(report, f, indent=2)
|
||||
logger.info("Report saved to %s", args.output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user