mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-11 05:34:55 +03:00
c47eed6a64
- Fix 25 shell=True subprocess calls with list-based commands - Fix 49 verify=False in defensive skills (env-var override) - Add timeout to 231 HTTP/subprocess/socket calls - Fix 6 SQL injection patterns with whitelist validation - Replace 8 __import__() with standard imports - Remove 701 unused imports across 442 files - Add authorized-testing disclaimers to all offensive skills - Complete 11 incomplete skill directories - Expand 10 stub SKILL.md files with full content - Fix 2 YAML parse errors in frontmatter - Fix 5 pre-existing syntax errors - Convert 22 hardcoded paths/ports to environment variables - Back up 21 redundant skill pairs to .bak - Fix 2 global declaration errors - 724/724 skills with full folder anatomy (SKILL.md + agent.py + api-reference.md + LICENSE) - 0 compile errors across all 724 agent.py files
245 lines
8.7 KiB
Python
245 lines
8.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Web application penetration test agent using requests and subprocess."""
|
|
|
|
import subprocess
|
|
import sys
|
|
import json
|
|
import os
|
|
from urllib.parse import urlparse
|
|
|
|
try:
|
|
import requests
|
|
from requests.exceptions import RequestException
|
|
except ImportError:
|
|
print("Install: pip install requests")
|
|
sys.exit(1)
|
|
|
|
|
|
def fingerprint_technology(target_url):
|
|
"""Identify technology stack from response headers and cookies."""
|
|
try:
|
|
resp = requests.get(target_url, timeout=10, verify=False, allow_redirects=True)
|
|
except RequestException as e:
|
|
return {"error": str(e)}
|
|
headers = dict(resp.headers)
|
|
tech = {"server": headers.get("Server", "Unknown"), "technologies": []}
|
|
if "X-Powered-By" in headers:
|
|
tech["technologies"].append(headers["X-Powered-By"])
|
|
cookies = resp.cookies.get_dict()
|
|
cookie_tech = {
|
|
"JSESSIONID": "Java", "PHPSESSID": "PHP",
|
|
"ASP.NET_SessionId": "ASP.NET", "csrftoken": "Django",
|
|
"laravel_session": "Laravel", "_rails_session": "Ruby on Rails",
|
|
}
|
|
for cookie_name, framework in cookie_tech.items():
|
|
if cookie_name in cookies:
|
|
tech["technologies"].append(framework)
|
|
return tech
|
|
|
|
|
|
def check_security_headers(target_url):
|
|
"""Check for presence of security headers."""
|
|
try:
|
|
resp = requests.get(target_url, timeout=10, verify=False)
|
|
except RequestException as e:
|
|
return {"error": str(e)}
|
|
required_headers = {
|
|
"Strict-Transport-Security": "HSTS",
|
|
"Content-Security-Policy": "CSP",
|
|
"X-Content-Type-Options": "nosniff",
|
|
"X-Frame-Options": "Clickjacking protection",
|
|
"X-XSS-Protection": "XSS filter",
|
|
"Referrer-Policy": "Referrer control",
|
|
"Permissions-Policy": "Feature policy",
|
|
}
|
|
results = {}
|
|
for header, desc in required_headers.items():
|
|
value = resp.headers.get(header)
|
|
results[header] = {
|
|
"present": value is not None,
|
|
"value": value,
|
|
"description": desc,
|
|
}
|
|
return results
|
|
|
|
|
|
def test_http_methods(target_url):
|
|
"""Test for dangerous HTTP methods."""
|
|
dangerous = ["PUT", "DELETE", "TRACE", "CONNECT"]
|
|
results = []
|
|
for method in dangerous:
|
|
try:
|
|
resp = requests.request(method, target_url, timeout=5, verify=False)
|
|
if resp.status_code not in (405, 501):
|
|
results.append({
|
|
"method": method, "status": resp.status_code,
|
|
"risk": "HIGH" if method in ("PUT", "DELETE") else "MEDIUM",
|
|
})
|
|
except RequestException:
|
|
pass
|
|
try:
|
|
resp = requests.options(target_url, timeout=5, verify=False)
|
|
allow = resp.headers.get("Allow", "")
|
|
results.append({"method": "OPTIONS", "allow_header": allow})
|
|
except RequestException:
|
|
pass
|
|
return results
|
|
|
|
|
|
def test_cors_config(target_url):
|
|
"""Test CORS configuration for misconfigurations."""
|
|
tests = []
|
|
origins = [
|
|
"https://evil.com",
|
|
"null",
|
|
urlparse(target_url).scheme + "://" + urlparse(target_url).hostname + ".evil.com",
|
|
]
|
|
for origin in origins:
|
|
try:
|
|
resp = requests.get(
|
|
target_url, headers={"Origin": origin},
|
|
timeout=5, verify=False
|
|
)
|
|
acao = resp.headers.get("Access-Control-Allow-Origin", "")
|
|
acac = resp.headers.get("Access-Control-Allow-Credentials", "")
|
|
if acao == origin or acao == "*":
|
|
tests.append({
|
|
"origin": origin, "reflected": True,
|
|
"allow_credentials": acac.lower() == "true",
|
|
"risk": "HIGH" if acac.lower() == "true" else "MEDIUM",
|
|
})
|
|
except RequestException:
|
|
pass
|
|
return tests
|
|
|
|
|
|
def run_directory_bruteforce(target_url, wordlist=None):
|
|
"""Run directory enumeration using ffuf if available."""
|
|
if wordlist is None:
|
|
wordlist = "/usr/share/seclists/Discovery/Web-Content/common.txt"
|
|
if not os.path.exists(wordlist):
|
|
return {"error": f"Wordlist not found: {wordlist}"}
|
|
try:
|
|
result = subprocess.run(
|
|
["ffuf", "-w", wordlist, "-u", f"{target_url}/FUZZ",
|
|
"-mc", "200,301,302,403", "-t", "20", "-o", "/tmp/ffuf_output.json",
|
|
"-of", "json", "-s"],
|
|
capture_output=True, text=True, timeout=120
|
|
)
|
|
if os.path.exists("/tmp/ffuf_output.json"):
|
|
with open("/tmp/ffuf_output.json") as f:
|
|
return json.load(f)
|
|
return {"stdout": result.stdout[:1000]}
|
|
except FileNotFoundError:
|
|
return {"error": "ffuf not installed"}
|
|
except subprocess.TimeoutExpired:
|
|
return {"error": "ffuf timeout"}
|
|
|
|
|
|
def test_sql_injection_basic(target_url, params):
|
|
"""Test for basic SQL injection indicators."""
|
|
payloads = ["'", "' OR '1'='1", "1 OR 1=1--", "'; DROP TABLE--"]
|
|
sql_errors = [
|
|
"sql syntax", "mysql", "sqlite", "postgresql", "ora-",
|
|
"microsoft ole db", "unclosed quotation", "syntax error",
|
|
]
|
|
findings = []
|
|
for param_name in params:
|
|
for payload in payloads:
|
|
test_params = {param_name: payload}
|
|
try:
|
|
resp = requests.get(target_url, params=test_params, timeout=10, verify=False)
|
|
body_lower = resp.text.lower()
|
|
for err in sql_errors:
|
|
if err in body_lower:
|
|
findings.append({
|
|
"parameter": param_name, "payload": payload,
|
|
"error_pattern": err, "status": resp.status_code,
|
|
"risk": "CRITICAL",
|
|
})
|
|
break
|
|
except RequestException:
|
|
pass
|
|
return findings
|
|
|
|
|
|
def test_xss_basic(target_url, params):
|
|
"""Test for basic reflected XSS."""
|
|
payloads = [
|
|
'<script>alert(1)</script>',
|
|
'"><img src=x onerror=alert(1)>',
|
|
"'-alert(1)-'",
|
|
]
|
|
findings = []
|
|
for param_name in params:
|
|
for payload in payloads:
|
|
try:
|
|
resp = requests.get(
|
|
target_url, params={param_name: payload},
|
|
timeout=10, verify=False
|
|
)
|
|
if payload in resp.text:
|
|
findings.append({
|
|
"parameter": param_name, "payload": payload,
|
|
"reflected": True, "risk": "HIGH",
|
|
})
|
|
except RequestException:
|
|
pass
|
|
return findings
|
|
|
|
|
|
def run_assessment(target_url, test_params=None):
|
|
"""Run web application security assessment."""
|
|
if test_params is None:
|
|
test_params = ["id", "q", "search", "page", "user"]
|
|
report = {
|
|
"target": target_url,
|
|
"technology": fingerprint_technology(target_url),
|
|
"security_headers": check_security_headers(target_url),
|
|
"http_methods": test_http_methods(target_url),
|
|
"cors": test_cors_config(target_url),
|
|
"sqli_findings": test_sql_injection_basic(target_url, test_params),
|
|
"xss_findings": test_xss_basic(target_url, test_params),
|
|
}
|
|
missing_headers = [
|
|
h for h, v in report["security_headers"].items()
|
|
if isinstance(v, dict) and not v.get("present", True)
|
|
]
|
|
report["summary"] = {
|
|
"missing_security_headers": len(missing_headers),
|
|
"dangerous_methods": len(report["http_methods"]),
|
|
"cors_issues": len(report["cors"]),
|
|
"sqli_findings": len(report["sqli_findings"]),
|
|
"xss_findings": len(report["xss_findings"]),
|
|
}
|
|
return report
|
|
|
|
|
|
def print_report(report):
|
|
print("Web Application Penetration Test Report")
|
|
print("=" * 50)
|
|
print(f"Target: {report['target']}")
|
|
tech = report["technology"]
|
|
print(f"Server: {tech.get('server', 'Unknown')}")
|
|
if tech.get("technologies"):
|
|
print(f"Stack: {', '.join(tech['technologies'])}")
|
|
print("\nSecurity Headers:")
|
|
for h, v in report["security_headers"].items():
|
|
if isinstance(v, dict):
|
|
status = "PRESENT" if v.get("present") else "MISSING"
|
|
print(f" {h}: {status}")
|
|
if report["sqli_findings"]:
|
|
print(f"\nSQL Injection: {len(report['sqli_findings'])} finding(s)")
|
|
for f in report["sqli_findings"]:
|
|
print(f" [{f['risk']}] {f['parameter']}: {f['error_pattern']}")
|
|
if report["xss_findings"]:
|
|
print(f"\nXSS: {len(report['xss_findings'])} finding(s)")
|
|
for f in report["xss_findings"]:
|
|
print(f" [{f['risk']}] {f['parameter']}: reflected")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
target = sys.argv[1] if len(sys.argv) > 1 else "http://example.com"
|
|
result = run_assessment(target)
|
|
print_report(result)
|