| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
parent directory.. | ||||
A REST API for building and managing Attack Range infrastructure with automated OpenAPI documentation powered by flask-openapi3.
All dependencies (including API dependencies) are now in the main requirements file:
# From project root
pip install -r requirements.txtOr from the API directory:
cd api
pip install -r ../requirements.txtcd api
python app.pyThe API will be available at http://localhost:4000
For production deployment, use a production WSGI server like Gunicorn:
cd api
pip install gunicorn
gunicorn -w 4 -b 0.0.0.0:4000 app:appOnce the API is running, you can access the interactive OpenAPI documentation at:
Check if the API is running and healthy.
Response:
{
"status": "healthy",
"version": "1.0.0"
}Build a new attack range infrastructure OR continue an existing build after VPN connection. This is an asynchronous two-phase operation.
Two-Phase Build Process:
Request Body (Phase 1 - Start new build):
{
"template": "aws/splunk_minimal_aws"
}Request Body (Phase 2 - Continue after VPN):
{
"attack_range_id": "550e8400-e29b-41d4-a716-446655440000"
}Template formats supported:
Response (202 Accepted):
{
"status": "accepted",
"message": "Build operation started (VPN phase). Attack Range ID: ...",
"attack_range_id": "550e8400-e29b-41d4-a716-446655440000",
"phase": "vpn"
}Destroy an existing attack range infrastructure.
Request Body:
{
"attack_range_id": "550e8400-e29b-41d4-a716-446655440000"
}Response (202 Accepted):
{
"status": "accepted",
"message": "Destroy operation started. Attack Range ID: 550e8400-e29b-41d4-a716-446655440000"
}Get the status of a build or destroy operation by attack_range_id.
Response (during VPN setup):
{
"type": "build",
"status": "build_vpn",
"created_time": "2026-01-13T10:30:00",
"start_time": "2026-01-13T10:30:01",
"attack_range_id": "550e8400-e29b-41d4-a716-446655440000"
}Response (waiting for VPN connection):
{
"type": "build",
"status": "wait_for_vpn",
"created_time": "2026-01-13T10:30:00",
"start_time": "2026-01-13T10:30:01",
"attack_range_id": "550e8400-e29b-41d4-a716-446655440000",
"router_public_ip": "1.2.3.4",
"wireguard_config": "[Interface]\nPrivateKey = ...\n[Peer]\n...",
"wireguard_config_path": "/path/to/wireguard_config/550e8400-e29b-41d4-a716-446655440000.conf"
}Note: WireGuard configs are automatically saved to the wireguard_config/ folder with the filename {attack_range_id}.conf.
Status values:
Stage and execute local Ansible roles against a target server in a running attack range. This is a synchronous operation. The attack range must be in running or completed status.
Each role is provided as a base64-encoded gzip tarball of the role root directory (tasks/, meta/, etc.). Package a role with:
tar czf my_role.tar.gz -C /path/to/parent my_role
ROLE_B64=$(base64 -i my_role.tar.gz | tr -d '\n')Request Body:
{
"attack_range_id": "550e8400-e29b-41d4-a716-446655440000",
"target": "splunk",
"roles": [
{
"content_base64": "<base64-encoded-role-tarball>",
"name": "optional.namespace.role_name",
"vars": {
"example_var": "value"
}
}
]
}Response (200 OK):
{
"status": "success",
"message": "Successfully applied 1 role(s) on splunk",
"attack_range_id": "550e8400-e29b-41d4-a716-446655440000",
"target": "splunk",
"roles_applied": ["custom.my_role"],
"execution_output": null
}List all available attack range templates.
Response:
{
"templates": [
{
"name": "splunk_minimal_aws.yml",
"provider": "aws",
"path": "/path/to/templates/aws/splunk_minimal_aws.yml"
},
{
"name": "splunk_full_azure.yml",
"provider": "azure",
"path": "/path/to/templates/azure/splunk_full_azure.yml"
}
]
}Get the content of a specific template.
Example: GET /templates/aws/splunk_minimal_aws
Response:
{
"name": "splunk_minimal_aws.yml",
"provider": "aws",
"content": {
"general": {
"attack_range_password": "changeme123!",
...
},
...
}
}List all saved attack range configurations.
Response:
{
"configs": [
{
"attack_range_id": "550e8400-e29b-41d4-a716-446655440000",
"path": "/path/to/config/550e8400-e29b-41d4-a716-446655440000.yml",
"modified_time": "2026-01-13T10:30:00"
}
]
}Get the content of a saved configuration.
Example: GET /configs/550e8400-e29b-41d4-a716-446655440000
Response:
{
"attack_range_id": "550e8400-e29b-41d4-a716-446655440000",
"content": {
"general": {
"attack_range_id": "550e8400-e29b-41d4-a716-446655440000",
...
},
...
}
}# Phase 1: Start build with template
RESPONSE=$(curl -X POST http://localhost:4000/attack-range/build \
-H "Content-Type: application/json" \
-d '{
"template": "aws/splunk_minimal_aws"
}')
# Extract attack_range_id from response
ATTACK_RANGE_ID=$(echo $RESPONSE | jq -r '.attack_range_id')
echo "Attack Range ID: $ATTACK_RANGE_ID"
# Check status until wait_for_vpn
while true; do
STATUS=$(curl -s http://localhost:4000/attack-range/status/$ATTACK_RANGE_ID | jq -r '.status')
echo "Status: $STATUS"
if [ "$STATUS" = "wait_for_vpn" ]; then
# Get WireGuard config (also automatically saved to wireguard_config/ folder)
curl -s http://localhost:4000/attack-range/status/$ATTACK_RANGE_ID | \
jq -r '.wireguard_config' > attack_range.conf
echo "WireGuard config saved to attack_range.conf"
echo "Note: Config also available at wireguard_config/$ATTACK_RANGE_ID.conf"
echo "Please activate the VPN connection, then press Enter to continue..."
read
break
fi
sleep 10
done
# Phase 2: Continue build after VPN connection
curl -X POST http://localhost:4000/attack-range/build \
-H "Content-Type: application/json" \
-d "{
\"attack_range_id\": \"$ATTACK_RANGE_ID\"
}"
# Monitor final build
while true; do
STATUS=$(curl -s http://localhost:4000/attack-range/status/$ATTACK_RANGE_ID | jq -r '.status')
echo "Status: $STATUS"
if [ "$STATUS" = "running" ] || [ "$STATUS" = "error" ]; then
break
fi
sleep 10
done# List saved configs
curl http://localhost:4000/configs
# Destroy by attack_range_id
curl -X POST http://localhost:4000/attack-range/destroy \
-H "Content-Type: application/json" \
-d '{"attack_range_id": "550e8400-e29b-41d4-a716-446655440000"}'import requests
import time
# API base URL
BASE_URL = "http://localhost:4000"
# Health check
response = requests.get(f"{BASE_URL}/health")
print(response.json())
# List templates
response = requests.get(f"{BASE_URL}/templates")
templates = response.json()["templates"]
print(f"Found {len(templates)} templates")
# Phase 1: Start build with template
build_payload = {"template": "aws/basic_splunk"}
response = requests.post(f"{BASE_URL}/attack-range/build", json=build_payload)
result = response.json()
attack_range_id = result["attack_range_id"]
print(f"Build started - Attack Range ID: {attack_range_id}")
# Poll until VPN is ready
print("\nPhase 1: Building VPN infrastructure...")
while True:
response = requests.get(f"{BASE_URL}/attack-range/status/{attack_range_id}")
status_data = response.json()
status = status_data['status']
print(f"Status: {status}")
if status == 'wait_for_vpn':
# Save WireGuard config
wireguard_config = status_data['wireguard_config']
with open('attack_range.conf', 'w') as f:
f.write(wireguard_config)
print("\nWireGuard config saved to attack_range.conf")
print("Please activate the VPN connection and press Enter to continue...")
input()
break
elif status == 'error':
print(f"Error: {status_data.get('error')}")
exit(1)
time.sleep(10)
# Phase 2: Continue build after VPN
print("\nPhase 2: Building lab infrastructure...")
continue_payload = {"attack_range_id": attack_range_id}
response = requests.post(f"{BASE_URL}/attack-range/build", json=continue_payload)
print(response.json())
# Poll until complete
while True:
response = requests.get(f"{BASE_URL}/attack-range/status/{attack_range_id}")
status_data = response.json()
status = status_data['status']
print(f"Status: {status}")
if status == 'running':
print("\n✓ Attack range is fully deployed!")
print(f"Attack Range ID: {attack_range_id}")
print(f"Router IP: {status_data.get('router_public_ip')}")
break
elif status == 'error':
print(f"Error: {status_data.get('error')}")
break
time.sleep(10)All error responses follow a standard format:
{
"status": "error",
"message": "Brief error description",
"details": "Detailed error information (optional)"
}Common HTTP status codes:
The API is built with:
attack_range_2/
├── api/ # API application code
├── config/ # Saved attack range configs ({attack_range_id}.yml)
├── wireguard_config/ # WireGuard VPN configs ({attack_range_id}.conf)
├── templates/ # Attack range templates
│ ├── aws/
│ ├── azure/
│ └── gcp/
└── terraform/ # Terraform infrastructure code
⚠️ Important: This API is designed for internal use and does not include authentication/authorization by default.
For production deployments, consider:
Contributions are welcome! Please follow the project's contribution guidelines.
See the main project LICENSE file.
| Back | FazBrowse Home | New Git URL |