mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-08-08 03:20:19 +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,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Anthropic Agent Skills Contributors
|
||||
|
||||
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,58 @@
|
||||
# API Reference: Implementing Network Access Control
|
||||
|
||||
## Libraries
|
||||
|
||||
### pyrad (RADIUS Client)
|
||||
- **Install**: `pip install pyrad`
|
||||
- **Docs**: https://pypi.org/project/pyrad/
|
||||
- `Client(server, secret, dict)` -- Create RADIUS client
|
||||
- `CreateAuthPacket()` -- Build Access-Request
|
||||
- `SendPacket(req)` -- Send and receive RADIUS reply
|
||||
- Response codes: `AccessAccept`, `AccessReject`, `AccessChallenge`
|
||||
|
||||
### pysnmp (SNMP for Switch Queries)
|
||||
- **Install**: `pip install pysnmp`
|
||||
- **Docs**: https://pysnmp.readthedocs.io/
|
||||
- `getCmd()` -- SNMP GET request
|
||||
- `nextCmd()` -- SNMP GETNEXT/walk
|
||||
- `CommunityData()` -- SNMPv2c community string
|
||||
- `UsmUserData()` -- SNMPv3 authentication
|
||||
|
||||
## 802.1X SNMP OIDs
|
||||
|
||||
| OID | Description |
|
||||
|-----|-------------|
|
||||
| `1.3.6.1.2.1.8802.1.1.1.1.2.1.1.1` | dot1xAuthAuthControlledPortStatus |
|
||||
| `1.3.6.1.2.1.8802.1.1.1.1.2.1.1.2` | dot1xAuthAuthControlledPortControl |
|
||||
| `1.3.6.1.2.1.8802.1.1.1.1.2.4.1.1` | dot1xAuthSessionAuthenticMethod |
|
||||
|
||||
## RADIUS Attributes
|
||||
|
||||
| Attribute | Use |
|
||||
|-----------|-----|
|
||||
| `User-Name` | Client identity |
|
||||
| `User-Password` | PAP password |
|
||||
| `NAS-IP-Address` | Switch/AP IP |
|
||||
| `NAS-Port-Type` | Port type (Ethernet, Wireless) |
|
||||
| `Tunnel-Type` | VLAN assignment (13 = VLAN) |
|
||||
| `Tunnel-Medium-Type` | Medium (6 = 802) |
|
||||
| `Tunnel-Private-Group-Id` | VLAN ID for dynamic assignment |
|
||||
| `Filter-Id` | ACL name to apply |
|
||||
|
||||
## EAP Methods
|
||||
- **EAP-TLS**: Certificate-based (strongest, requires PKI)
|
||||
- **PEAP**: Password with TLS tunnel
|
||||
- **EAP-TTLS**: Tunneled TLS (flexible inner auth)
|
||||
- **MAB**: MAC Authentication Bypass (fallback, no supplicant)
|
||||
|
||||
## PacketFence NAC API
|
||||
- REST API at `https://packetfence:9999/api/v1/`
|
||||
- `GET /nodes` -- List known devices
|
||||
- `POST /nodes/{mac}/register` -- Register device
|
||||
- `GET /violations` -- Active violations
|
||||
|
||||
## External References
|
||||
- FreeRADIUS: https://freeradius.org/documentation/
|
||||
- PacketFence NAC: https://www.packetfence.org/doc/
|
||||
- Cisco ISE: https://developer.cisco.com/docs/identity-services-engine/
|
||||
- 802.1X RFC 3748: https://datatracker.ietf.org/doc/html/rfc3748
|
||||
@@ -0,0 +1,217 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Network Access Control (802.1X/NAC) monitoring agent using RADIUS and SNMP."""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import argparse
|
||||
import socket
|
||||
import struct
|
||||
from datetime import datetime
|
||||
from collections import Counter
|
||||
|
||||
try:
|
||||
from pyrad.client import Client
|
||||
from pyrad.dictionary import Dictionary
|
||||
from pyrad import packet
|
||||
except ImportError:
|
||||
print("Install pyrad: pip install pyrad")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
from pysnmp.hlapi import (getCmd, nextCmd, SnmpEngine, CommunityData,
|
||||
UdpTransportTarget, ContextData, ObjectType, ObjectIdentity)
|
||||
HAS_SNMP = True
|
||||
except ImportError:
|
||||
HAS_SNMP = False
|
||||
|
||||
|
||||
def test_radius_auth(server, secret, username, password, port=1812):
|
||||
"""Test RADIUS authentication for a user credential pair."""
|
||||
srv = Client(server=server, secret=secret.encode(),
|
||||
dict=Dictionary(dict_file=None))
|
||||
srv.AuthPort = port
|
||||
req = srv.CreateAuthPacket(code=packet.AccessRequest, User_Name=username)
|
||||
req["User-Password"] = req.PwCrypt(password)
|
||||
req["NAS-IP-Address"] = "192.168.1.1"
|
||||
req["NAS-Port-Type"] = "Ethernet"
|
||||
req["NAS-Port"] = 1
|
||||
try:
|
||||
reply = srv.SendPacket(req)
|
||||
if reply.code == packet.AccessAccept:
|
||||
attrs = {}
|
||||
for key in reply.keys():
|
||||
attrs[key] = reply[key]
|
||||
return {"status": "ACCEPT", "user": username, "attributes": str(attrs)}
|
||||
elif reply.code == packet.AccessReject:
|
||||
return {"status": "REJECT", "user": username, "reason": "Invalid credentials"}
|
||||
elif reply.code == packet.AccessChallenge:
|
||||
return {"status": "CHALLENGE", "user": username, "reason": "Additional auth required"}
|
||||
except Exception as e:
|
||||
return {"status": "ERROR", "user": username, "error": str(e)}
|
||||
|
||||
|
||||
def parse_radius_log(log_file, max_lines=1000):
|
||||
"""Parse FreeRADIUS log file for authentication events."""
|
||||
events = []
|
||||
try:
|
||||
with open(log_file, "r") as f:
|
||||
for i, line in enumerate(f):
|
||||
if i >= max_lines:
|
||||
break
|
||||
if "Auth:" in line or "Login" in line:
|
||||
parts = line.strip().split()
|
||||
event = {"raw": line.strip(), "timestamp": " ".join(parts[:3]) if len(parts) > 3 else ""}
|
||||
if "Login OK" in line:
|
||||
event["result"] = "SUCCESS"
|
||||
elif "Login incorrect" in line:
|
||||
event["result"] = "FAILURE"
|
||||
elif "Invalid user" in line:
|
||||
event["result"] = "INVALID_USER"
|
||||
else:
|
||||
event["result"] = "OTHER"
|
||||
events.append(event)
|
||||
except FileNotFoundError:
|
||||
events.append({"error": f"Log file not found: {log_file}"})
|
||||
return events
|
||||
|
||||
|
||||
def check_switch_port_status(switch_ip, community="public"):
|
||||
"""Query switch via SNMP for 802.1X port authentication status."""
|
||||
if not HAS_SNMP:
|
||||
return [{"error": "pysnmp not installed. Run: pip install pysnmp"}]
|
||||
|
||||
dot1x_auth_oid = "1.3.6.1.2.1.8802.1.1.1.1.2.1.1.1"
|
||||
results = []
|
||||
iterator = nextCmd(
|
||||
SnmpEngine(), CommunityData(community),
|
||||
UdpTransportTarget((switch_ip, 161)),
|
||||
ContextData(),
|
||||
ObjectType(ObjectIdentity(dot1x_auth_oid)),
|
||||
maxRows=100)
|
||||
|
||||
for errorIndication, errorStatus, errorIndex, varBinds in iterator:
|
||||
if errorIndication or errorStatus:
|
||||
results.append({"error": str(errorIndication or errorStatus)})
|
||||
break
|
||||
for varBind in varBinds:
|
||||
oid, value = varBind
|
||||
port_index = str(oid).split(".")[-1]
|
||||
auth_states = {1: "initialize", 2: "disconnected", 3: "connecting",
|
||||
4: "authenticating", 5: "authenticated",
|
||||
6: "aborting", 7: "held", 8: "forceAuth", 9: "forceUnauth"}
|
||||
results.append({
|
||||
"port": port_index,
|
||||
"state": auth_states.get(int(value), f"unknown({value})"),
|
||||
"state_code": int(value)
|
||||
})
|
||||
return results
|
||||
|
||||
|
||||
def analyze_auth_events(events):
|
||||
"""Analyze authentication events for security issues."""
|
||||
result_counts = Counter(e.get("result", "UNKNOWN") for e in events)
|
||||
total = len(events)
|
||||
failures = result_counts.get("FAILURE", 0) + result_counts.get("INVALID_USER", 0)
|
||||
success_rate = round((result_counts.get("SUCCESS", 0) / max(total, 1)) * 100, 1)
|
||||
|
||||
analysis = {
|
||||
"total_events": total,
|
||||
"successes": result_counts.get("SUCCESS", 0),
|
||||
"failures": failures,
|
||||
"invalid_users": result_counts.get("INVALID_USER", 0),
|
||||
"success_rate": success_rate,
|
||||
"risk_level": "HIGH" if failures > total * 0.3 else "MEDIUM" if failures > total * 0.1 else "LOW",
|
||||
}
|
||||
|
||||
if failures > 20:
|
||||
analysis["alert"] = "High number of authentication failures - possible brute force attack"
|
||||
|
||||
return analysis
|
||||
|
||||
|
||||
def generate_nac_policy_check():
|
||||
"""Generate a NAC compliance policy checklist."""
|
||||
policies = [
|
||||
{"check": "802.1X enforcement", "requirement": "All access ports configured for dot1x",
|
||||
"standard": "PCI-DSS 1.2"},
|
||||
{"check": "Guest VLAN isolation", "requirement": "Unauthenticated devices on restricted VLAN",
|
||||
"standard": "NIST 800-53 AC-4"},
|
||||
{"check": "MAB fallback", "requirement": "MAC Authentication Bypass for non-supplicant devices",
|
||||
"standard": "Best Practice"},
|
||||
{"check": "EAP-TLS certificates", "requirement": "Certificate-based auth for managed devices",
|
||||
"standard": "NIST 800-53 IA-5"},
|
||||
{"check": "Posture assessment", "requirement": "Endpoint compliance check before full access",
|
||||
"standard": "PCI-DSS 5.3"},
|
||||
{"check": "Dynamic VLAN assignment", "requirement": "Role-based VLAN via RADIUS attributes",
|
||||
"standard": "NIST 800-53 AC-6"},
|
||||
{"check": "Re-authentication timer", "requirement": "Periodic re-auth every 3600 seconds",
|
||||
"standard": "Best Practice"},
|
||||
{"check": "RADIUS accounting", "requirement": "Accounting enabled for audit trail",
|
||||
"standard": "SOC 2 CC6.1"},
|
||||
]
|
||||
return policies
|
||||
|
||||
|
||||
def run_nac_audit(radius_log=None, switch_ip=None, community="public"):
|
||||
"""Run NAC security audit."""
|
||||
print(f"\n{'='*60}")
|
||||
print(f" NETWORK ACCESS CONTROL AUDIT")
|
||||
print(f" Generated: {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')} UTC")
|
||||
print(f"{'='*60}\n")
|
||||
|
||||
policies = generate_nac_policy_check()
|
||||
print(f"--- NAC POLICY CHECKLIST ---")
|
||||
for p in policies:
|
||||
print(f" [ ] {p['check']}: {p['requirement']} ({p['standard']})")
|
||||
|
||||
if radius_log:
|
||||
events = parse_radius_log(radius_log)
|
||||
analysis = analyze_auth_events(events)
|
||||
print(f"\n--- RADIUS AUTH ANALYSIS ---")
|
||||
print(f" Total Events: {analysis['total_events']}")
|
||||
print(f" Successes: {analysis['successes']}")
|
||||
print(f" Failures: {analysis['failures']}")
|
||||
print(f" Success Rate: {analysis['success_rate']}%")
|
||||
print(f" Risk Level: {analysis['risk_level']}")
|
||||
if analysis.get("alert"):
|
||||
print(f" ALERT: {analysis['alert']}")
|
||||
|
||||
if switch_ip:
|
||||
ports = check_switch_port_status(switch_ip, community)
|
||||
print(f"\n--- SWITCH PORT STATUS ({switch_ip}) ---")
|
||||
for p in ports[:20]:
|
||||
if "error" in p:
|
||||
print(f" Error: {p['error']}")
|
||||
else:
|
||||
icon = "[OK]" if p["state"] == "authenticated" else "[!!]"
|
||||
print(f" {icon} Port {p['port']}: {p['state']}")
|
||||
|
||||
print(f"\n{'='*60}\n")
|
||||
return {"policies": policies}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Network Access Control Agent")
|
||||
parser.add_argument("--audit", action="store_true", help="Run NAC audit")
|
||||
parser.add_argument("--radius-log", help="Path to FreeRADIUS log file")
|
||||
parser.add_argument("--switch", help="Switch IP for SNMP 802.1X status check")
|
||||
parser.add_argument("--community", default="public", help="SNMP community string")
|
||||
parser.add_argument("--test-auth", nargs=4, metavar=("SERVER", "SECRET", "USER", "PASS"),
|
||||
help="Test RADIUS authentication")
|
||||
parser.add_argument("--output", help="Save report to JSON")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.test_auth:
|
||||
result = test_radius_auth(*args.test_auth)
|
||||
print(json.dumps(result, indent=2))
|
||||
elif args.audit:
|
||||
report = run_nac_audit(args.radius_log, args.switch, args.community)
|
||||
if args.output:
|
||||
with open(args.output, "w") as f:
|
||||
json.dump(report, f, indent=2, default=str)
|
||||
else:
|
||||
parser.print_help()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user