### Leonidas API Authentication and Request Examples Source: https://context7.com/reverseclabs/leonidas/llms.txt Examples of how to interact with the Leonidas API, demonstrating authentication using API keys and various methods for executing test cases, including role assumption and using AWS access keys. ```bash # Execute a test case with API key authentication curl -X POST "https://[API-ID].execute-api.[REGION].amazonaws.com/dev/discovery/enumerate-cloudtrail" \ -H "x-api-key: YOUR_API_KEY" # Execute with role assumption (AWS) curl -X POST "https://[API-URL]/credential-access/access-secrets-manager-secrets" \ -H "x-api-key: YOUR_API_KEY" \ -d "role_arn=arn:aws:iam::123456789012:role/TestRole" # Execute with AWS access keys curl -X POST "https://[API-URL]/discovery/get-identity" \ -H "x-api-key: YOUR_API_KEY" \ -d "access_key_id=AKIAIOSFODNN7EXAMPLE" \ -d "secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" # Execute in specific AWS region curl -X POST "https://[API-URL]/discovery/enumerate-cloudtrail" \ -H "x-api-key: YOUR_API_KEY" \ -d "region=us-east-1" ``` -------------------------------- ### Kubernetes Empty Permissions Example (YAML) Source: https://github.com/reverseclabs/leonidas/blob/master/docs/writing-definitions.md Provides an example of an 'empty' permissions block for Kubernetes test cases that do not require any specific RBAC permissions. ```yaml permissions: - namespaced: true apiGroups: [""] resources: [""] verbs: [""] ``` -------------------------------- ### Example Leo Case Configuration (YAML) Source: https://context7.com/reverseclabs/leonidas/llms.txt An example YAML file (caseconfig.yml) demonstrating how to configure Leo for test case execution. It includes API endpoint, key, sleep time, and a list of test cases with their paths and arguments. ```yaml # Example caseconfig.yml url: "https://[API-ID].execute-api.[REGION].amazonaws.com/dev" apikey: "YOUR_API_KEY" sleeptime: 5 identity: role_arn: "arn:aws:iam::123456789012:role/TestRole" region: "us-east-1" cases: case1: name: "Enumerate Cloudtrails" path: "/discovery/enumerate-cloudtrail" args: null case2: name: "Access Secrets Manager Secret" path: "/credential-access/access-secrets-manager-secrets" args: secretid: "my-secret" ``` -------------------------------- ### Example Case Definition Template (YAML) Source: https://github.com/reverseclabs/leonidas/blob/master/docs/writing-definitions.md An example of a complete case definition in YAML format. It includes metadata, execution logic for different platforms (AWS CLI and Python SDK), and detection rules. ```yaml --- name: Access Secret in Secrets Manager author: Nick Jones description: | An adversary may attempt to access the secrets in secrets manager, to steal certificates, credentials or other sensitive material platform: aws category: Credential Access mitre_ids: - T1528 permissions: - secretsmanager:GetSecretValue - kms:Decrypt input_arguments: secretid: description: ID of secret to access, either ARN or friendly name type: str value: "leonidas_created_secret" executors: sh: code: | aws secretsmanager get-secret-value --secret-id {{ secretid }} leonidas_aws: implemented: True clients: - secretsmanager code: | result = clients["secretsmanager"].get_secret_value(SecretId=secretid) detection: sigma_id: cbeba6f0-019e-4782-8c7e-e21b10521eed status: experimental level: low sources: - name: "cloudtrail" attributes: eventName: "GetSecretValue" eventSource: "*.secretsmanager.amazonaws.com" ``` -------------------------------- ### Kubernetes Audit Log Source Example Source: https://github.com/reverseclabs/leonidas/blob/master/docs/writing-definitions.md Example YAML configuration for specifying Kubernetes audit logs as a data source for detection. This translates to the 'audit' logsource for the 'kubernetes' product in Sigma rules. ```yaml logsource: product: kubernetes service: audit ``` -------------------------------- ### Setup and Execute Leo Test Cases (bash) Source: https://context7.com/reverseclabs/leonidas/llms.txt Provides bash commands to set up the Leo framework, generate and configure a case configuration file (caseconfig.yml), and execute the configured test cases. ```bash # Setup Leo cd leo poetry install # Generate case configuration cd ../generator poetry run python generator.py leo cp ./output/caseconfig/caseconfig.yml ../leo/ # Edit caseconfig.yml to configure: # - url: API endpoint URL # - apikey: API gateway key # - sleeptime: seconds between test cases # - cases: test cases to execute with arguments # - identity: optional credentials for execution # Execute configured test cases cd ../leo poetry run ./leo.py caseconfig.yml ``` -------------------------------- ### Install Local Generator with Poetry Source: https://github.com/reverseclabs/leonidas/blob/master/README.md Installs the Leonidas generator locally using Poetry. This is a prerequisite for generating Sigma rules and documentation. ```bash cd generator poetry install ``` -------------------------------- ### Kubernetes Test Case Definition Example (YAML) Source: https://context7.com/reverseclabs/leonidas/llms.txt An example YAML definition for a Kubernetes test case. It includes the test case name, author, description, platform, MITRE ATT&CK IDs, required permissions, input arguments, and executor code for both shell commands and Leo's Kubernetes client. ```yaml # Kubernetes Test Case Definition Example --- name: Exec into Container author: Leo Tsaousis category: "Execution" description: | Execute into a Pod's container using kubectl exec command mitre_ids: - T1609 platform: kubernetes permissions: - namespaced: true apiGroups: [""] resources: - pods/exec verbs: - create - namespaced: true apiGroups: [""] resources: - pods verbs: - get input_arguments: podname: description: Name of the pod to exec into type: str value: "vulnerable-pod" command: description: The command to execute within the pod type: str value: "whoami" executors: sh: code: | kubectl exec {{ podname }} -- sh -c {{ command }} leonidas_kube: implemented: True detection: sigma_id: a1b0ca4e-7835-413e-8471-3ff2b8a66be6 status: experimental level: low sources: - name: audit attributes: verb: create resource: pods subresource: exec ``` -------------------------------- ### Run List GuardDuty Detectors Discovery Source: https://github.com/reverseclabs/leonidas/blob/master/jupyter/Leonidas JupyterDemo.ipynb Executes the 'list_guardduty_detectors' discovery case using the provided client. This function retrieves a list of GuardDuty detector IDs. The output includes detector IDs and response metadata. ```python client.run_case("discovery/list_guardduty_detectors") ``` -------------------------------- ### Persistence Operations Source: https://github.com/reverseclabs/leonidas/blob/master/jupyter/Leonidas JupyterDemo.ipynb Endpoints for adding, creating, or modifying persistent resources and user credentials. ```APIDOC ## POST /persistence/add_an_entity_to_an_iam_role_assumption_policy ### Description Adds an entity (user or role) to an IAM role's assumption policy. ### Method POST ### Endpoint /persistence/add_an_entity_to_an_iam_role_assumption_policy ### Parameters #### Request Body - **role** (string) - Required - The name of the IAM role. - **entityarn** (string) - Required - The ARN of the entity (user or role) to add. ### Response #### Success Response (200) - **message** (string) - Confirmation message of the update. #### Response Example { "message": "Entity 'arn:aws:iam::123456789012:user/example-user' added to assumption policy of role 'example-role'." } ``` ```APIDOC ## POST /persistence/add_an_iam_user ### Description Adds an IAM user. ### Method POST ### Endpoint /persistence/add_an_iam_user ### Parameters #### Request Body - **user** (string) - Required - The name of the IAM user to add. ### Response #### Success Response (200) - **message** (string) - Confirmation message of the user creation. #### Response Example { "message": "IAM user 'example-user' created successfully." } ``` ```APIDOC ## POST /persistence/add_api_key_to_existing_iam_user ### Description Adds an access key (API key) to an existing IAM user. ### Method POST ### Endpoint /persistence/add_api_key_to_existing_iam_user ### Parameters #### Request Body - **user** (string) - Required - The name of the IAM user. ### Response #### Success Response (200) - **access_key_id** (string) - The ID of the newly created access key. - **secret_access_key** (string) - The secret access key for the new access key. #### Response Example { "access_key_id": "AKIAIOSFODNN7EXAMPLE", "secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" } ``` ```APIDOC ## PUT /persistence/change_password_for_current_user ### Description Changes the password for the currently authenticated user. ### Method PUT ### Endpoint /persistence/change_password_for_current_user ### Parameters #### Request Body - **oldpassword** (string) - Required - The current password of the user. - **newpassword** (string) - Required - The new password for the user. ### Response #### Success Response (200) - **message** (string) - Confirmation message of the password change. #### Response Example { "message": "Password changed successfully for the current user." } ``` ```APIDOC ## POST /persistence/create_iam_group ### Description Creates a new IAM group. ### Method POST ### Endpoint /persistence/create_iam_group ### Parameters #### Request Body - **group** (string) - Required - The name of the new IAM group to create. ### Response #### Success Response (200) - **message** (string) - Confirmation message of the group creation. #### Response Example { "message": "IAM group 'example-group' created successfully." } ``` ```APIDOC ## POST /persistence/create_login_profile_for_existing_user ### Description Creates a login profile (including a password) for an existing IAM user. ### Method POST ### Endpoint /persistence/create_login_profile_for_existing_user ### Parameters #### Request Body - **user** (string) - Required - The name of the IAM user. - **password** (string) - Required - The initial password for the user's login profile. ### Response #### Success Response (200) - **message** (string) - Confirmation message of the login profile creation. #### Response Example { "message": "Login profile created successfully for user 'example-user'." } ``` ```APIDOC ## POST /persistence/create_secret_in_secrets_manager ### Description Creates a new secret in AWS Secrets Manager. ### Method POST ### Endpoint /persistence/create_secret_in_secrets_manager ### Parameters #### Request Body - **name** (string) - Required - The name of the secret to create. - **secretstring** (string) - Required - The secret value (e.g., a JSON string). ### Response #### Success Response (200) - **message** (string) - Confirmation message of the secret creation. - **arn** (string) - The ARN of the created secret. #### Response Example { "message": "Secret 'example-secret' created successfully in Secrets Manager.", "arn": "arn:aws:secretsmanager:us-east-1:123456789012:secret:example-secret-AbCdEf" } ``` ```APIDOC ## DELETE /persistence/delete_login_profile_for_existing_user ### Description Deletes the login profile for an existing IAM user. ### Method DELETE ### Endpoint /persistence/delete_login_profile_for_existing_user ### Parameters #### Query Parameters - **user** (string) - Required - The name of the IAM user whose login profile should be deleted. ### Response #### Success Response (200) - **message** (string) - Confirmation message of the deletion. #### Response Example { "message": "Login profile deleted successfully for user 'example-user'." } ``` ```APIDOC ## PUT /persistence/update_login_profile_for_existing_user ### Description Updates the login profile for an existing IAM user, typically to change the password. ### Method PUT ### Endpoint /persistence/update_login_profile_for_existing_user ### Parameters #### Request Body - **user** (string) - Required - The name of the IAM user. - **password** (string) - Required - The new password for the user's login profile. ### Response #### Success Response (200) - **message** (string) - Confirmation message of the update. #### Response Example { "message": "Login profile updated successfully for user 'example-user'." } ``` -------------------------------- ### Kubernetes Permissions Example (YAML) Source: https://github.com/reverseclabs/leonidas/blob/master/docs/writing-definitions.md Illustrates the structure for defining Kubernetes RBAC permissions within a case definition. It specifies namespace context, API groups, resources, and verbs. ```yaml permissions: - namespaced: true apiGroups: [""] resources: - serviceaccounts verbs: - create ``` -------------------------------- ### Input Argument with Default Behavior Description (YAML) Source: https://github.com/reverseclabs/leonidas/blob/master/docs/writing-definitions.md Demonstrates how to define input arguments for a test case, including a description that explains the default behavior when a value is not provided. This example uses a 'file' type for a custom YAML manifest. ```yaml name: Writeable hostPath Mount category: "Privilege Escalation" description: "Create a container with a writeable hostPath mount" platform: kubernetes input_arguments: custom_yaml: description: | YAML manifest for the pod - leave this empty to use the default spec that performs the TTP type: file value: apiVersion: v1 kind: Pod spec: volumes: - name: host-fs hostPath: path: / containers: - image: ubuntu name: attacker-pod command: ["/bin/sh", "-c", "sleep infinity"] volumeMounts: - name: host-fs mountPath: /host restartPolicy: Never ``` -------------------------------- ### Access API Key Details Source: https://github.com/reverseclabs/leonidas/blob/master/jupyter/Leonidas JupyterDemo.ipynb Retrieves the 'AccessKey' details from the 'apikey_data' dictionary. This allows for direct access to the newly generated Access Key ID, Secret Access Key, status, and creation date. ```python apikey_data["AccessKey"] ``` -------------------------------- ### Python Project Initialization and Imports Source: https://github.com/reverseclabs/leonidas/blob/master/jupyter/Leonidas JupyterDemo.ipynb This snippet shows the essential Python imports for the Leonidas project. It includes standard libraries like json, requests, and pandas, along with a custom library 'leoclientlib'. The code also sets up a casefile path and an API key variable, along with the base URL for the Leonidas API. ```python import importlib import json import requests import pandas from lib import leoclientlib importlib.reload(leoclientlib) casefile = "./caseconfig.yml" apikey = "" url = "https://BLAH.execute-api.us-east-1.amazonaws.com/dev/" # update according to your deployment # use the below if running the Leonidas API locally ``` -------------------------------- ### Run Leonidas API Locally for Development Source: https://github.com/reverseclabs/leonidas/blob/master/docs/deploying-leonidas.md Steps to build and run the Leonidas Python API locally for development purposes. This involves installing dependencies, generating API code, and running the main Python script. It utilizes default AWS and Kubernetes credentials but allows overriding them. ```bash cd generator poetry install poetry run ./generator.py generate-aws-api poetry run ./generator.py generate-kube-api cd ../output/leonidas poetry install poetry run python leonidas.py ``` -------------------------------- ### Run Enumerate CloudTrails Discovery Source: https://github.com/reverseclabs/leonidas/blob/master/jupyter/Leonidas JupyterDemo.ipynb Executes the 'enumerate_cloudtrails_for_a_given_region' discovery case using the provided client. This function is designed to list CloudTrail trails within a specified AWS region. ```python client.run_case("discovery/enumerate_cloudtrails_for_a_given_region") ``` -------------------------------- ### Running Leonidas API Locally Source: https://context7.com/reverseclabs/leonidas/llms.txt This section details how to run the Leonidas API locally for development and testing. It involves generating the API code and then starting the local API server, which uses default AWS and Kubernetes credentials. ```bash # Generate the API code cd generator poetry install poetry run ./generator.py generate-aws-api poetry run ./generator.py generate-kube-api # Run the local API server cd ../output/leonidas poetry install poetry run python leonidas.py # API available at http://127.0.0.1:5000 # Uses default AWS credentials from ~/.aws/config # Uses default Kubernetes credentials from kubeconfig ``` -------------------------------- ### AWS Test Case Definition Example (YAML) Source: https://context7.com/reverseclabs/leonidas/llms.txt An example YAML definition for an AWS test case. It specifies the test case name, author, description, platform, MITRE ATT&CK IDs, required permissions, input arguments, executor code (for both shell and Leo's AWS client), and detection rules. ```yaml # AWS Test Case Definition Example --- name: Access Secret in Secrets Manager author: Nick Jones description: | An adversary may attempt to access the secrets in secrets manager, to steal certificates, credentials or other sensitive material platform: aws category: Credential Access mitre_ids: - T1528 permissions: - secretsmanager:GetSecretValue - kms:Decrypt input_arguments: secretid: description: ID of secret to access, either ARN or friendly name type: str value: "leonidas_created_secret" executors: sh: code: | aws secretsmanager get-secret-value --secret-id {{ secretid }} leonidas_aws: implemented: True clients: - secretsmanager code: | result = clients["secretsmanager"].get_secret_value(SecretId=secretid) detection: sigma_id: cbeba6f0-019e-4782-8c7e-e21b10521eed status: experimental level: low sources: - name: "cloudtrail" attributes: eventName: "GetSecretValue" eventSource: "*.secretsmanager.amazonaws.com" ``` -------------------------------- ### Privilege Escalation Operations Source: https://github.com/reverseclabs/leonidas/blob/master/jupyter/Leonidas JupyterDemo.ipynb Endpoints designed to facilitate privilege escalation by modifying IAM policies and resource associations. ```APIDOC ## POST /privilege_escalation/add_a_policy_to_a_group ### Description Attaches an IAM policy to an IAM group. ### Method POST ### Endpoint /privilege_escalation/add_a_policy_to_a_group ### Parameters #### Request Body - **group** (string) - Required - The name of the IAM group. - **policyarn** (string) - Required - The ARN of the IAM policy to attach. ### Response #### Success Response (200) - **message** (string) - Confirmation message of the policy attachment. #### Response Example { "message": "Policy 'arn:aws:iam::aws:policy/AdministratorAccess' attached to group 'example-group'." } ``` ```APIDOC ## POST /privilege_escalation/add_a_policy_to_a_role ### Description Attaches an IAM policy to an IAM role. ### Method POST ### Endpoint /privilege_escalation/add_a_policy_to_a_role ### Parameters #### Request Body - **role** (string) - Required - The name of the IAM role. - **policyarn** (string) - Required - The ARN of the IAM policy to attach. ### Response #### Success Response (200) - **message** (string) - Confirmation message of the policy attachment. #### Response Example { "message": "Policy 'arn:aws:iam::aws:policy/PowerUserAccess' attached to role 'example-role'." } ``` ```APIDOC ## POST /privilege_escalation/add_a_policy_to_a_user ### Description Attaches an IAM policy to an IAM user. ### Method POST ### Endpoint /privilege_escalation/add_a_policy_to_a_user ### Parameters #### Request Body - **user** (string) - Required - The name of the IAM user. - **policyarn** (string) - Required - The ARN of the IAM policy to attach. ### Response #### Success Response (200) - **message** (string) - Confirmation message of the policy attachment. #### Response Example { "message": "Policy 'arn:aws:iam::aws:policy/ReadOnlyAccess' attached to user 'example-user'." } ``` ```APIDOC ## POST /privilege_escalation/add_an_existing_role_to_a_new_ec2_instance ### Description Associates an existing IAM role with a new EC2 instance. ### Method POST ### Endpoint /privilege_escalation/add_an_existing_role_to_a_new_ec2_instance ### Parameters #### Request Body - **role** (string) - Required - The name of the IAM role to associate. ### Response #### Success Response (200) - **message** (string) - Confirmation message of the association. - **instance_id** (string) - The ID of the newly created EC2 instance. #### Response Example { "message": "Role 'example-role' associated with a new EC2 instance.", "instance_id": "i-0123456789abcdef0" } ``` ```APIDOC ## POST /privilege_escalation/add_an_iam_user_to_a_group ### Description Adds an IAM user to an IAM group. ### Method POST ### Endpoint /privilege_escalation/add_an_iam_user_to_a_group ### Parameters #### Request Body - **user** (string) - Required - The name of the IAM user to add. - **group** (string) - Required - The name of the IAM group to add the user to. ### Response #### Success Response (200) - **message** (string) - Confirmation message of the user addition. #### Response Example { "message": "User 'example-user' added to group 'example-group'." } ``` ```APIDOC ## PUT /privilege_escalation/change_default_policy_version ### Description Changes the default version of an IAM policy. ### Method PUT ### Endpoint /privilege_escalation/change_default_policy_version ### Parameters #### Request Body - **policyarn** (string) - Required - The ARN of the IAM policy. - **versionid** (string) - Required - The ID of the policy version to set as default. ### Response #### Success Response (200) - **message** (string) - Confirmation message of the default version change. #### Response Example { "message": "Default version for policy 'arn:aws:iam::123456789012:policy/MyCustomPolicy' changed to 'v2'." } ``` ```APIDOC ## POST /privilege_escalation/create_new_policy_version ### Description Creates a new version for an existing IAM policy. ### Method POST ### Endpoint /privilege_escalation/create_new_policy_version ### Parameters #### Request Body - **policyarn** (string) - Required - The ARN of the IAM policy. - **policydocument** (object) - Required - The JSON document defining the new policy version. ### Response #### Success Response (200) - **message** (string) - Confirmation message of the new version creation. - **versionid** (string) - The ID of the newly created policy version. #### Response Example { "message": "New version created for policy 'arn:aws:iam::123456789012:policy/MyCustomPolicy'.", "versionid": "v3" } ``` ```APIDOC ## POST /privilege_escalation/create_policy ### Description Creates a new IAM policy. ### Method POST ### Endpoint /privilege_escalation/create_policy ### Parameters #### Request Body - **name** (string) - Required - The name of the new policy. - **description** (string) - Optional - A description for the policy. - **policydocument** (object) - Required - The JSON document defining the policy. ### Response #### Success Response (200) - **message** (string) - Confirmation message of the policy creation. - **arn** (string) - The ARN of the newly created policy. #### Response Example { "message": "IAM policy 'MyCustomPolicy' created successfully.", "arn": "arn:aws:iam::123456789012:policy/MyCustomPolicy" } ``` -------------------------------- ### Impact Operations Source: https://github.com/reverseclabs/leonidas/blob/master/jupyter/Leonidas JupyterDemo.ipynb Endpoints for impacting or deleting existing AWS resources. ```APIDOC ## DELETE /impact/delete_iam_group ### Description Deletes an IAM group. ### Method DELETE ### Endpoint /impact/delete_iam_group ### Parameters #### Query Parameters - **group** (string) - Required - The name of the IAM group to delete. ### Response #### Success Response (200) - **message** (string) - Confirmation message of the deletion. #### Response Example { "message": "IAM group 'example-group' deleted successfully." } ``` ```APIDOC ## DELETE /impact/delete_iam_policy ### Description Deletes an IAM policy. ### Method DELETE ### Endpoint /impact/delete_iam_policy ### Parameters #### Query Parameters - **policy** (string) - Required - The name or ARN of the IAM policy to delete. ### Response #### Success Response (200) - **message** (string) - Confirmation message of the deletion. #### Response Example { "message": "IAM policy 'example-policy' deleted successfully." } ``` ```APIDOC ## DELETE /impact/delete_iam_role ### Description Deletes an IAM role. ### Method DELETE ### Endpoint /impact/delete_iam_role ### Parameters #### Query Parameters - **role** (string) - Required - The name of the IAM role to delete. ### Response #### Success Response (200) - **message** (string) - Confirmation message of the deletion. #### Response Example { "message": "IAM role 'example-role' deleted successfully." } ``` ```APIDOC ## DELETE /impact/delete_iam_user ### Description Deletes an IAM user. ### Method DELETE ### Endpoint /impact/delete_iam_user ### Parameters #### Query Parameters - **user** (string) - Required - The name of the IAM user to delete. ### Response #### Success Response (200) - **message** (string) - Confirmation message of the deletion. #### Response Example { "message": "IAM user 'example-user' deleted successfully." } ``` ```APIDOC ## DELETE /impact/delete_secret_in_secrets_manager ### Description Deletes a secret from AWS Secrets Manager. ### Method DELETE ### Endpoint /impact/delete_secret_in_secrets_manager ### Parameters #### Query Parameters - **secretid** (string) - Required - The ARN or name of the secret to delete. ### Response #### Success Response (200) - **message** (string) - Confirmation message of the deletion. #### Response Example { "message": "Secret 'example-secret' deleted successfully from Secrets Manager." } ``` -------------------------------- ### Kubernetes Test Case Definition Source: https://context7.com/reverseclabs/leonidas/llms.txt Example of a YAML-based test case definition for the Kubernetes platform. ```APIDOC ## Kubernetes Test Case Definition Example ### Description Defines a test case for the Kubernetes platform, specifying execution details, permissions, and detection mechanisms. ### Structure ```yaml --- name: Exec into Container author: Leo Tsaousis category: "Execution" description: | Execute into a Pod's container using kubectl exec command mitre_ids: - T1609 platform: kubernetes permissions: - namespaced: true apiGroups: [""] resources: - pods/exec verbs: - create - namespaced: true apiGroups: [""] resources: - pods verbs: - get input_arguments: podname: description: Name of the pod to exec into type: str value: "vulnerable-pod" command: description: The command to execute within the pod type: str value: "whoami" executors: sh: code: | kubectl exec {{ podname }} -- sh -c {{ command }} leonidas_kube: implemented: True detection: sigma_id: a1b0ca4e-7835-413e-8471-3ff2b8a66be6 status: experimental level: low sources: - name: audit attributes: verb: create resource: pods subresource: exec ``` ``` -------------------------------- ### Leo Python Client Library Usage Source: https://context7.com/reverseclabs/leonidas/llms.txt Demonstrates how to use the Leo Python client library for programmatic execution of test cases. Includes examples for initializing the client, running cases with default or custom arguments, and using role assumption or access keys for credentials. ```python from jupyter.lib.leoclientlib import Client # Initialize client client = Client( url="https://[API-URL]", apikey="YOUR_API_KEY", casefile="./caseconfig.yml" ) # Run a test case with default arguments result = client.run_case("/discovery/enumerate-cloudtrail") print(result) # Run with custom arguments result = client.run_case( path="/credential-access/access-secrets-manager-secrets", args={"secretid": "my-secret"} ) # Run with role assumption result = client.run_case( path="/discovery/get-identity", creds={ "role_arn": "arn:aws:iam::123456789012:role/AttackerRole", "region": "eu-west-1" } ) # Run with access keys result = client.run_case( path="/persistence/add-iam-user", args={"username": "backdoor-user"}, creds={ "access_key_id": "AKIAIOSFODNN7EXAMPLE", "secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" } ) ``` -------------------------------- ### Process and Display Cloud Case Data with Python and Pandas Source: https://github.com/reverseclabs/leonidas/blob/master/jupyter/Leonidas JupyterDemo.ipynb This snippet processes case data obtained from a client object, sorts it by path, and displays it using Pandas DataFrames. It handles potential 'None' values for arguments and sets display options for maximum column width. ```python df_data = [[value["name"], value["path"], list(value["args"].keys()) if value["args"] is not None else None] for value in list(client.cases.values())] df_data = sorted(df_data, key = lambda x: x[1]) pandas.set_option('display.max_colwidth', 0) pandas.DataFrame(df_data) ``` -------------------------------- ### Add IAM Policy to User (Python) Source: https://github.com/reverseclabs/leonidas/blob/master/jupyter/Leonidas JupyterDemo.ipynb This snippet demonstrates how to add an AWS IAM policy to a user using the 'run_case' method. It defines the necessary arguments, including the user and the policy ARN, and then executes the privilege escalation case. ```python policy_args = { "user": user_args["user"], "policy_arn": "arn:aws:iam::aws:policy/SecretsManagerReadWrite" } client.run_case("privilege_escalation/add_a_policy_to_a_user", policy_args) ``` -------------------------------- ### AWS CloudTrail Discovery Example (YAML Definition) Source: https://github.com/reverseclabs/leonidas/blob/master/README.md A YAML definition for an AWS CloudTrail discovery technique. It specifies the author, description, MITRE ATT&CK IDs, required permissions, and execution methods for both shell and the Leonidas AWS client. ```yaml --- name: Enumerate Cloudtrails for a Given Region author: Nick Jones description: | An adversary may attempt to enumerate the configured trails, to identify what actions will be logged and where they will be logged to. In AWS, this may start with a single call to enumerate the trails applicable to the default region. category: Discovery mitre_ids: - T1526 platform: aws permissions: - cloudtrail:DescribeTrails input_arguments: executors: sh: code: | aws cloudtrail describe-trails leonidas_aws: implemented: True clients: - cloudtrail code: | result = clients["cloudtrail"].describe_trails() detection: sigma_id: 48653a63-085a-4a3b-88be-9680e9adb449 status: experimental level: low sources: - name: "cloudtrail" attributes: eventName: "DescribeTrails" eventSource: "*.cloudtrail.amazonaws.com" ``` -------------------------------- ### List Secrets in Secrets Manager (Python) Source: https://github.com/reverseclabs/leonidas/blob/master/jupyter/Leonidas JupyterDemo.ipynb This snippet demonstrates how to list all secrets stored in AWS Secrets Manager using the 'run_case' method. It utilizes previously configured user credentials and an empty arguments dictionary to perform the discovery. ```python client.run_case("discovery/list_secrets_in_secrets_manager", args={}, creds=newuser_creds) ``` -------------------------------- ### Add API Key to IAM User Persistence Source: https://github.com/reverseclabs/leonidas/blob/master/jupyter/Leonidas JupyterDemo.ipynb Adds an API key to an existing IAM user using the 'add_api_key_to_existing_iam_user' persistence case. This function requires user arguments, typically including the username. The output contains the new API key details, including Access Key ID and Secret Access Key. ```python apikey_data = client.run_case("persistence/add_api_key_to_existing_iam_user", user_args) apikey_data ``` -------------------------------- ### Add IAM User Persistence Source: https://github.com/reverseclabs/leonidas/blob/master/jupyter/Leonidas JupyterDemo.ipynb Adds an IAM user to the AWS environment using the 'add_an_iam_user' persistence case. It requires a dictionary of user arguments, such as the username. This operation may fail if the user already exists, returning an 'EntityAlreadyExists' error. ```python user_args = { "user": "cnsd-user" } client.run_case("persistence/add_an_iam_user", user_args) ``` -------------------------------- ### Attempt to Delete Kubernetes Deployment using Python Source: https://github.com/reverseclabs/leonidas/blob/master/jupyter/threat-actors/OF815.ipynb This Python code demonstrates an attacker's attempt to cause disruption by deleting a Kubernetes deployment. It uses the Leonidas client to execute the 'impact/delete_deployment' case, though the example notes this attempt may fail due to insufficient permissions. ```python # pods = ['hvac-controller', 'leonidas-deployment-848d4fccf-g9pbx', 'patient-db'] args = {"deploymentname":"hvac-controller"} delete = client.run_case("impact/delete_deployment", args) print(delete["stdout"]) print(delete["stderr"]) ``` -------------------------------- ### Run STS Get Caller Identity Discovery Source: https://github.com/reverseclabs/leonidas/blob/master/jupyter/Leonidas JupyterDemo.ipynb Executes the 'sts_get_caller_identity' discovery case using the provided client. This function is used to retrieve information about the caller's identity. It may return an 'ExpiredToken' error if the security token is invalid. ```python client.run_case("discovery/sts_get_caller_identity") ``` -------------------------------- ### Serve HTML Documentation Locally with MkDocs Source: https://github.com/reverseclabs/leonidas/blob/master/README.md Serves the generated HTML documentation locally for previewing. This command should be run from the './output' directory. ```bash mkdocs serve ``` -------------------------------- ### Get STS Caller Identity (Python) Source: https://github.com/reverseclabs/leonidas/blob/master/jupyter/Leonidas JupyterDemo.ipynb This code snippet shows how to retrieve the AWS STS (Security Token Service) caller identity using provided credentials. It constructs a dictionary for new user credentials and then calls the 'run_case' method for the 'sts_get_caller_identity' discovery. ```python newuser_creds = { "access_key_id": apikey_data["AccessKey"]["AccessKeyId"], "secret_access_key": apikey_data["AccessKey"]["SecretAccessKey"], "region": "us-east-1" } client.run_case("discovery/sts_get_caller_identity", args={}, creds=newuser_creds) ``` -------------------------------- ### Deploy Leonidas API to Kubernetes Cluster Source: https://github.com/reverseclabs/leonidas/blob/master/docs/deploying-leonidas.md Commands to build the Leonidas container image, generate Kubernetes manifests, and deploy the API to a cluster. Requires modifying `config.yml` for image URL and namespace. The deployment process includes applying manifests and port-forwarding the service. ```bash cd generator/ poetry install poetry run ./generator.py generate-kube-api poetry run ./generator.py build-image poetry run ./generator.py kube-resources > leonidas-manifests.yml kubectl -f leonidas-manifests.yml apply kubectl port-forward deployment/leonidas-deployment 5000:5000 ``` -------------------------------- ### Simulate Initial Access with Leaked Kubeconfig using Python Source: https://github.com/reverseclabs/leonidas/blob/master/jupyter/threat-actors/OF815.ipynb This Python code snippet demonstrates how to simulate initial access to a Kubernetes cluster by using a leaked Kubeconfig file. It instantiates a Leonidas KubeClient with a compromised ServiceAccount token to impersonate a legitimate user. ```python import os import sys module_path = os.path.abspath(os.path.join('..')) if module_path not in sys.path: sys.path.append(module_path) from lib import kubeclientlib compromised_token = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjJQNC1wOThvcTA0WXNtMFdmai1ocFRvYl81aWFVRFJBenFkTndVRFFCejgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkaGFybWEtcHJvZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJsYW1wcG9zdC1zYS1zZWNyZXQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoibGFtcHBvc3Qtc2EiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIxYTU0NDQ2MS1lMGFmLTRlZmUtODNiYS0wZDA2NDA4YzJmMjciLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGhhcm1hLXByb2Q6bGFtcHBvc3Qtc2EifQ.gW4er21RBDVJ0jUkgp7nEWNFwqGcvCLUT5p9Hk0z9I042ToOcN6CMn7ZR1FJ-XBnTwoaAQ2d0QdYNB3ZOXqcFZDQuqL1zPfa9DnjNFUY-VkqaEwhyXDf4I-e04ypGYM5Utj1nDxkc0KcBfMEk7XldgEE9q37TUcyLtAWVCDcU07QgRdb_P1ZsBbYSmca7NVL5QrZ-fI9aq2S2WbzwibqwyJEmMAgoaIcJCV8mgfhr_CdfMMSz36QgYP6k_cxuBYO4lRx__b5Qh2F1ftFqsBOaePHQK7acSN5Ly5cYvD1lCaJlH-LdX5pxwLfkoJnxuArlYtnw0PI3K4wz6diMG3M6w" client = kubeclientlib.Client("http://127.0.0.1:5000/", compromised_token) ``` -------------------------------- ### Build HTML Documentation with MkDocs Source: https://github.com/reverseclabs/leonidas/blob/master/README.md Builds a prettified HTML version of the generated documentation using MkDocs. The output is created in the './output/site' folder. ```bash cd ../output mkdocs build ``` -------------------------------- ### Get OpenAPI Specification Source: https://context7.com/reverseclabs/leonidas/llms.txt Retrieves the OpenAPI (Swagger) specification for the API. ```APIDOC ## GET /swagger.json ### Description Retrieves the OpenAPI specification for the Leonidas API in JSON format. ### Method GET ### Endpoint /swagger.json ### Response #### Success Response (200) - **OpenAPI Specification** (object) - The complete OpenAPI specification for the API. ``` -------------------------------- ### Execute Kubernetes Test Case with Kubectl Source: https://github.com/reverseclabs/leonidas/blob/master/docs/writing-api-executors.md This snippet shows how to execute a Kubernetes test case by invoking shell commands, specifically using `kubectl`. Input arguments are made available as local variables. The output of the shell command is implicitly handled by the framework. ```shell kubectl create serviceaccount {{ serviceaccount }} ``` -------------------------------- ### Deploying Leonidas to AWS using Terraform and Serverless Framework Source: https://context7.com/reverseclabs/leonidas/llms.txt This section outlines the process of deploying the Leonidas CI/CD pipeline and API to AWS. It involves initializing Terraform, planning and applying the infrastructure, and then pushing code to a CodeCommit repository to trigger the deployment. ```bash # Deploy the AWS pipeline cd aws-pipeline terraform init terraform plan terraform apply # Get the CodeCommit repository URL terraform output repo terraform output ssh_config # Push code to trigger deployment git remote add pipeline ssh://USER@git-codecommit.REGION.amazonaws.com/v1/repos/leonidas git push pipeline master # Get the deployed API URL aws apigateway get-rest-apis | jq -r .items[].id # URL format: https://[API-ID].execute-api.[REGION].amazonaws.com/dev/ # Get API keys for authentication aws apigateway get-api-keys aws apigateway get-api-key --include-value --api-key [KEY-ID] | jq -r .value ``` -------------------------------- ### AWS Test Case Definition Source: https://context7.com/reverseclabs/leonidas/llms.txt Example of a YAML-based test case definition for the AWS platform. ```APIDOC ## AWS Test Case Definition Example ### Description Defines a test case for the AWS platform, specifying execution details, permissions, and detection mechanisms. ### Structure ```yaml --- name: Access Secret in Secrets Manager author: Nick Jones description: | An adversary may attempt to access the secrets in secrets manager, to steal certificates, credentials or other sensitive material platform: aws category: Credential Access mitre_ids: - T1528 permissions: - secretsmanager:GetSecretValue - kms:Decrypt input_arguments: secretid: description: ID of secret to access, either ARN or friendly name type: str value: "leonidas_created_secret" executors: sh: code: | aws secretsmanager get-secret-value --secret-id {{ secretid }} leonidas_aws: implemented: True clients: - secretsmanager code: | result = clients["secretsmanager"].get_secret_value(SecretId=secretid) detection: sigma_id: cbeba6f0-019e-4782-8c7e-e21b10521eed status: experimental level: low sources: - name: "cloudtrail" attributes: eventName: "GetSecretValue" eventSource: "*.secretsmanager.amazonaws.com" ``` ``` -------------------------------- ### AWS IAM Client Initialization in Python Source: https://github.com/reverseclabs/leonidas/blob/master/docs/writing-definitions.md Demonstrates how to initialize an AWS IAM client using boto3 within a Python script. This is typically used within the 'leonidas_aws' executor for AWS-based test cases. ```python client = boto3.client('iam') ``` -------------------------------- ### Deploying Leonidas to Kubernetes Source: https://context7.com/reverseclabs/leonidas/llms.txt Instructions for deploying the containerized Leonidas API to a Kubernetes cluster. This involves configuring the generator, building the container image, generating Kubernetes manifests, and applying them to the cluster. ```bash # Configure deployment in generator/config.yml # Set image_url and namespace cd generator poetry install # Generate the Kubernetes API code poetry run ./generator.py generate-kube-api # Build and push the container image poetry run ./generator.py build-image # Generate Kubernetes manifests poetry run ./generator.py kube-resources > leonidas-manifests.yml # Deploy to cluster kubectl -f leonidas-manifests.yml apply # Expose the API locally kubectl port-forward deployment/leonidas-deployment 5000:5000 # Access API at http://localhost:5000 # Cleanup kubectl -f leonidas-manifests.yml delete ``` -------------------------------- ### Enumerate Pods in Kubernetes Namespace using Python Source: https://github.com/reverseclabs/leonidas/blob/master/jupyter/threat-actors/OF815.ipynb This Python code demonstrates how an attacker can list all the pods within a Kubernetes namespace. It leverages the Leonidas client to execute the 'discovery/enumerate_pods' case and then uses regular expressions to extract pod names from the output. ```python import re pods = client.run_case("discovery/enumerate_pods") print(pods["stdout"]) matches = re.finditer(r"\n([a-zA-Z0-9\-]+)", pods["stdout"], re.MULTILINE) pods = [m.group().strip() for m in matches] ``` -------------------------------- ### Execute Command in Kubernetes Pod using Python Source: https://github.com/reverseclabs/leonidas/blob/master/jupyter/threat-actors/OF815.ipynb This Python code shows how an attacker can execute arbitrary commands within a specific pod in a Kubernetes cluster, using obtained credentials. It utilizes the Leonidas client's 'execution/exec_into_container' case to run a `mysqldump` command. ```python # pods = ['hvac-controller', 'leonidas-deployment-848d4fccf-g9pbx', 'patient-db'] password = data args = { "podname":pods[2], "command":"mysqldump --password="+password+" patients" } execout = client.run_case("execution/exec_into_container", args) print(execout["stdout"]) ```