mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-16 04:35:18 +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,52 @@
|
||||
# API Reference: IDOR Vulnerability Testing Agent
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Library | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| requests | >=2.28 | HTTP client for API endpoint testing |
|
||||
|
||||
## CLI Usage
|
||||
|
||||
```bash
|
||||
python scripts/agent.py \
|
||||
--url https://target.example.com \
|
||||
--token-a "eyJ..." --token-b "eyJ..." \
|
||||
--endpoints "/api/v1/users/{id}/profile" "/api/v1/orders/{id}" \
|
||||
--own-id 101 --other-id 102 \
|
||||
--output idor_report.json
|
||||
```
|
||||
|
||||
## IDORTester Class
|
||||
|
||||
### `__init__(base_url, user_a_token, user_b_token, verify_ssl)`
|
||||
Creates two `requests.Session` objects with different Bearer tokens for cross-user testing.
|
||||
|
||||
### `test_horizontal_idor(endpoint_template, own_id, other_id, method) -> dict`
|
||||
Accesses own resource then another user's resource with the same token. IDOR confirmed when both return 200 with different content.
|
||||
|
||||
### `test_vertical_idor(endpoint, method) -> dict`
|
||||
Accesses admin-only endpoints with a regular user token. Status 200 indicates missing authorization.
|
||||
|
||||
### `test_id_enumeration(endpoint_template, id_range, method) -> dict`
|
||||
Iterates over an ID range to discover valid objects. Returns count and sample IDs.
|
||||
|
||||
### `test_write_idor(endpoint_template, other_id, payload) -> dict`
|
||||
Sends PUT with another user's ID to test write-based IDOR. Status 200/201/204 indicates vulnerability.
|
||||
|
||||
### `test_cross_session(endpoint_template, resource_id) -> dict`
|
||||
Compares response hashes between two sessions for the same resource to detect missing authorization checks.
|
||||
|
||||
### `generate_report() -> dict`
|
||||
Returns all accumulated findings with severity assessment.
|
||||
|
||||
## Output Schema
|
||||
|
||||
```json
|
||||
{
|
||||
"target": "https://target.example.com",
|
||||
"total_findings": 2,
|
||||
"findings": [{"type": "horizontal", "endpoint": "/api/v1/users/{id}/profile", "vulnerable": true}],
|
||||
"severity": "High"
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,178 @@
|
||||
#!/usr/bin/env python3
|
||||
# For authorized testing in lab/CTF environments only
|
||||
"""IDOR vulnerability detection agent using requests with multi-session comparison."""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
import hashlib
|
||||
from typing import List, Optional
|
||||
|
||||
try:
|
||||
import requests
|
||||
except ImportError:
|
||||
sys.exit("requests is required: pip install requests")
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class IDORTester:
|
||||
"""Tests for Insecure Direct Object Reference vulnerabilities."""
|
||||
|
||||
def __init__(self, base_url: str, user_a_token: str, user_b_token: str,
|
||||
verify_ssl: bool = False):
|
||||
self.base_url = base_url.rstrip("/")
|
||||
self.verify = verify_ssl
|
||||
self.session_a = requests.Session()
|
||||
self.session_a.headers.update({"Authorization": f"Bearer {user_a_token}"})
|
||||
self.session_a.verify = verify_ssl
|
||||
self.session_b = requests.Session()
|
||||
self.session_b.headers.update({"Authorization": f"Bearer {user_b_token}"})
|
||||
self.session_b.verify = verify_ssl
|
||||
self.findings = []
|
||||
|
||||
def _response_hash(self, resp: requests.Response) -> str:
|
||||
return hashlib.md5(resp.content).hexdigest()
|
||||
|
||||
def test_horizontal_idor(self, endpoint_template: str, own_id: str,
|
||||
other_id: str, method: str = "GET") -> dict:
|
||||
"""Test horizontal IDOR by accessing another user's resource."""
|
||||
own_url = f"{self.base_url}{endpoint_template.replace('{id}', own_id)}"
|
||||
other_url = f"{self.base_url}{endpoint_template.replace('{id}', other_id)}"
|
||||
|
||||
own_resp = self.session_a.request(method, own_url, timeout=10)
|
||||
other_resp = self.session_a.request(method, other_url, timeout=10)
|
||||
|
||||
vulnerable = (
|
||||
other_resp.status_code == 200
|
||||
and own_resp.status_code == 200
|
||||
and self._response_hash(other_resp) != self._response_hash(own_resp)
|
||||
)
|
||||
result = {
|
||||
"type": "horizontal",
|
||||
"endpoint": endpoint_template,
|
||||
"method": method,
|
||||
"own_status": own_resp.status_code,
|
||||
"other_status": other_resp.status_code,
|
||||
"vulnerable": vulnerable,
|
||||
"own_content_length": len(own_resp.content),
|
||||
"other_content_length": len(other_resp.content),
|
||||
}
|
||||
if vulnerable:
|
||||
self.findings.append(result)
|
||||
logger.warning("IDOR FOUND: %s %s", method, endpoint_template)
|
||||
return result
|
||||
|
||||
def test_vertical_idor(self, endpoint: str, method: str = "GET") -> dict:
|
||||
"""Test vertical IDOR by accessing admin endpoints with regular user token."""
|
||||
url = f"{self.base_url}{endpoint}"
|
||||
resp = self.session_a.request(method, url, timeout=10)
|
||||
vulnerable = resp.status_code == 200
|
||||
result = {
|
||||
"type": "vertical",
|
||||
"endpoint": endpoint,
|
||||
"method": method,
|
||||
"status_code": resp.status_code,
|
||||
"vulnerable": vulnerable,
|
||||
"content_length": len(resp.content),
|
||||
}
|
||||
if vulnerable:
|
||||
self.findings.append(result)
|
||||
logger.warning("Vertical IDOR: %s %s (status=%d)", method, endpoint, resp.status_code)
|
||||
return result
|
||||
|
||||
def test_id_enumeration(self, endpoint_template: str, id_range: range,
|
||||
method: str = "GET") -> dict:
|
||||
"""Enumerate valid object IDs via response code analysis."""
|
||||
valid_ids = []
|
||||
for obj_id in id_range:
|
||||
url = f"{self.base_url}{endpoint_template.replace('{id}', str(obj_id))}"
|
||||
try:
|
||||
resp = self.session_a.request(method, url, timeout=5)
|
||||
if resp.status_code == 200:
|
||||
valid_ids.append(obj_id)
|
||||
except requests.RequestException:
|
||||
continue
|
||||
logger.info("Enumerated %d valid IDs in range %d-%d", len(valid_ids),
|
||||
id_range.start, id_range.stop)
|
||||
return {
|
||||
"endpoint": endpoint_template,
|
||||
"range_tested": f"{id_range.start}-{id_range.stop}",
|
||||
"valid_ids_found": len(valid_ids),
|
||||
"sample_ids": valid_ids[:10],
|
||||
}
|
||||
|
||||
def test_write_idor(self, endpoint_template: str, other_id: str,
|
||||
payload: dict) -> dict:
|
||||
"""Test write-based IDOR via PUT/PATCH with another user's ID."""
|
||||
url = f"{self.base_url}{endpoint_template.replace('{id}', other_id)}"
|
||||
resp = self.session_a.put(url, json=payload, timeout=10)
|
||||
vulnerable = resp.status_code in (200, 201, 204)
|
||||
result = {
|
||||
"type": "write_idor",
|
||||
"endpoint": endpoint_template,
|
||||
"method": "PUT",
|
||||
"target_id": other_id,
|
||||
"status_code": resp.status_code,
|
||||
"vulnerable": vulnerable,
|
||||
}
|
||||
if vulnerable:
|
||||
self.findings.append(result)
|
||||
logger.warning("Write IDOR: PUT %s (status=%d)", endpoint_template, resp.status_code)
|
||||
return result
|
||||
|
||||
def test_cross_session(self, endpoint_template: str, resource_id: str) -> dict:
|
||||
"""Compare responses between two authenticated sessions for the same resource."""
|
||||
url = f"{self.base_url}{endpoint_template.replace('{id}', resource_id)}"
|
||||
resp_a = self.session_a.get(url, timeout=10)
|
||||
resp_b = self.session_b.get(url, timeout=10)
|
||||
same_response = self._response_hash(resp_a) == self._response_hash(resp_b)
|
||||
result = {
|
||||
"endpoint": endpoint_template,
|
||||
"resource_id": resource_id,
|
||||
"user_a_status": resp_a.status_code,
|
||||
"user_b_status": resp_b.status_code,
|
||||
"same_response": same_response,
|
||||
"missing_authz": resp_a.status_code == 200 and resp_b.status_code == 200 and same_response,
|
||||
}
|
||||
return result
|
||||
|
||||
def generate_report(self) -> dict:
|
||||
"""Compile IDOR assessment results."""
|
||||
return {
|
||||
"target": self.base_url,
|
||||
"total_findings": len(self.findings),
|
||||
"findings": self.findings,
|
||||
"severity": "High" if self.findings else "None",
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="IDOR Vulnerability Testing Agent")
|
||||
parser.add_argument("--url", required=True, help="Base URL of the target API")
|
||||
parser.add_argument("--token-a", required=True, help="JWT token for User A")
|
||||
parser.add_argument("--token-b", required=True, help="JWT token for User B")
|
||||
parser.add_argument("--endpoints", nargs="+", default=["/api/v1/users/{id}/profile"])
|
||||
parser.add_argument("--own-id", default="101", help="User A's resource ID")
|
||||
parser.add_argument("--other-id", default="102", help="User B's resource ID")
|
||||
parser.add_argument("--output", default="idor_report.json")
|
||||
args = parser.parse_args()
|
||||
|
||||
tester = IDORTester(args.url, args.token_a, args.token_b)
|
||||
all_results = []
|
||||
for ep in args.endpoints:
|
||||
result = tester.test_horizontal_idor(ep, args.own_id, args.other_id)
|
||||
all_results.append(result)
|
||||
report = tester.generate_report()
|
||||
report["test_details"] = all_results
|
||||
|
||||
with open(args.output, "w") as f:
|
||||
json.dump(report, f, indent=2)
|
||||
logger.info("Report saved to %s", args.output)
|
||||
print(json.dumps(report, indent=2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user