#!/usr/bin/env python3 """Agent for testing Broken Function Level Authorization (BFLA) in APIs.""" import argparse import json from datetime import datetime, timezone try: import requests HAS_REQUESTS = True except ImportError: HAS_REQUESTS = False ADMIN_ENDPOINTS = [ "/admin", "/admin/users", "/admin/settings", "/admin/config", "/api/admin/users", "/api/v1/admin", "/api/internal", "/manage", "/management", "/dashboard/admin", "/api/users/all", "/api/config", "/api/debug", ] HTTP_METHODS = ["GET", "POST", "PUT", "DELETE", "PATCH"] def test_endpoint_access(base_url, endpoint, token, method="GET"): """Test if an endpoint is accessible with given credentials.""" if not HAS_REQUESTS: return None url = f"{base_url.rstrip('/')}{endpoint}" headers = {"Authorization": f"Bearer {token}"} if token else {} try: resp = requests.request(method, url, headers=headers, timeout=10, verify=False) return { "endpoint": endpoint, "method": method, "status_code": resp.status_code, "response_size": len(resp.content), "accessible": resp.status_code < 400, } except requests.RequestException: return None def test_method_switching(base_url, endpoint, token): """Test if changing HTTP method bypasses authorization.""" results = [] for method in HTTP_METHODS: result = test_endpoint_access(base_url, endpoint, token, method) if result and result["accessible"]: results.append(result) return results def test_privilege_escalation(base_url, low_priv_token, endpoints=None): """Test if low-privilege user can access admin endpoints.""" findings = [] test_endpoints = endpoints or ADMIN_ENDPOINTS for ep in test_endpoints: result = test_endpoint_access(base_url, ep, low_priv_token) if result and result["accessible"]: findings.append({ "vulnerability": "BFLA", "endpoint": ep, "status_code": result["status_code"], "response_size": result["response_size"], "severity": "HIGH", }) return findings def test_idor_via_function(base_url, token, user_id, target_user_id): """Test function-level auth by accessing another user's admin functions.""" findings = [] endpoints = [ f"/api/users/{target_user_id}", f"/api/users/{target_user_id}/settings", f"/api/users/{target_user_id}/role", ] for ep in endpoints: for method in ["GET", "PUT", "DELETE"]: result = test_endpoint_access(base_url, ep, token, method) if result and result["accessible"]: findings.append({ "vulnerability": "BFLA+IDOR", "endpoint": ep, "method": method, "own_user_id": user_id, "target_user_id": target_user_id, }) return findings def main(): parser = argparse.ArgumentParser( description="Test Broken Function Level Authorization (authorized testing only)" ) parser.add_argument("--url", required=True, help="Base API URL") parser.add_argument("--token", help="Low-privilege user JWT token") parser.add_argument("--endpoints", nargs="*", help="Custom admin endpoints to test") parser.add_argument("--user-id", help="Current user ID") parser.add_argument("--target-id", help="Target user ID for IDOR test") parser.add_argument("--output", "-o", help="Output JSON report") args = parser.parse_args() print("[*] BFLA Testing Agent") print("[!] For authorized security testing only") report = {"timestamp": datetime.now(timezone.utc).isoformat(), "target": args.url, "findings": []} escalation = test_privilege_escalation(args.url, args.token, args.endpoints) report["findings"].extend(escalation) print(f"[*] Privilege escalation findings: {len(escalation)}") if args.user_id and args.target_id: idor = test_idor_via_function(args.url, args.token, args.user_id, args.target_id) report["findings"].extend(idor) print(f"[*] IDOR findings: {len(idor)}") report["risk_level"] = "CRITICAL" if report["findings"] else "LOW" if args.output: with open(args.output, "w") as f: json.dump(report, f, indent=2) print(f"[*] Report saved to {args.output}") else: print(json.dumps(report, indent=2)) if __name__ == "__main__": main()