Administration Through SDK

To start developing with the ./havoc SDK import the ./havoc SDK package and create the connection:

import havoc

api_domain_name =  '<api_domain_name>'
api_region = '<api_region>'
api_key = '<api_key>'
secret = '<secret>'
h = havoc.Connect(api_region, api_domain_name, api_key, secret)

The ./havoc Python SDK supports the following methods:

Users

When the ./havoc platform is deployed, an initial admin user is created along with an API key and secret. The admin user can create additional admin and non-admin users that are allowed to interact with the Campaign API. Admin users have full administrative control of all Campaign resources, including the ability to create and delete users as well as reset users' API key and secret. Non-admin users have full control of all resources except for the users resource however, they can reset their own API key and secret.

Create a user

response = h.create_user(user_id, admin)
  • user_id - (Required) a uniquely recognizable identifier to associate with the user, i.e. the user's name or email address.
  • admin - (Optional) specify whether or not the new user has admin privileges. The valid values are yes and no. If not set, it defaults to no.

Delete a user

response = h.delete_user(user_id)
  • user_id - (Required) the user_id associated with the user you would like to delete.

Get a user's details

response = h.get_user(user_id)
  • user_id - (Required) the user_id associated with the user you want to retrieve details for.

List users

response = h.list_users()

Update a user

response = h.update_user(user_id, new_user_id, admin, reset_keys)
  • user_id - (Required) the user_id associated with the user you would like to make updates to.
  • new_user_id - (Optional) a new, uniquely recognizable identifier to associate with the user, i.e. the user's name or email address. If not set, no change is made.
  • admin - (Optional) add or remove admin privileges for the user. The valid values are yes and no. If not set, no change is made.
  • reset_keys - (Optional) forces a reset of the user's API key and secret. If not set, no change is made.

Users can use this method to reset their own API key and secret however, they will not be able to change their own user_id or admin status.

Portgroups

Portgroups are useful for container tasks that are expecting inbound connections from a victim machine, e.g. a Metasploit Framework container task that is running a reverse_tcp handler will need a port opened to allow inbound connections to whichever port the reverse_tcp handler is listening on. Portgroups must be managed in two steps. First, the portgroup must be created. Once it exists, rules permitting access to the container task can be added to the portgroup. A portgroup has to be assigned to a task at task launch. See the Launching Container Tasks section of the Usage Through SDK page for more information. A portgroup that is associated with a running task cannot be deleted. Terminating the task or using the kill_task method will ensure that the task is disassociated with the portgroup. Portgroups cannot be associated with remote container tasks. See Launching Remote Container Tasks for more information about exposing ports on remote container tasks.

Create a portgroup

response = h.create_portgroup(portgroup_name, portgroup_description)
  • portgroup_name - (Required) a unique name to assign to the portgroup.
  • portgroup_description - (Required) a description that describes the purpose of the portgroup.

Delete a portgroup

response = h.delete_portgroup(portgroup_name)
  • portgroup_name - (Required) the name associated with the portgroup you would like to delete.

Get a portgroup's details

response = h.get_portgroup(portgroup_name)
  • portgroup_name - (Required) the name associated with the portgroup you want to retrieve details for.

List portgroups

response = h.list_portgroups()

Update a portgroup to add or remove a portgroup rule

response = h.update_portgroup_rule(portgroup_name, portgroup_action, ip_ranges, port, ip_protocol)
  • portgroup_name - (Required) the name associated with the portgroup you would like to make updates to.
  • portgroup_action - (Required) an action indicating whether to add a rule to or remove a rule from the portgroup. The valid values are add and remove.
  • ip_ranges - (Required) the IP address range that is allowed access by the portgroup rule. If removing the rule, the IP address range must match the range that is currently present in the rule being removed.
  • port - (Required) the port number that external systems are allowed to access. If you're creating an ICMP rule as designated by the ip_protocol parameter, this port parameter will be ignored.
  • ip_protocol - (Required) the IP protocol that external systems are allowed to use. Valid values are udp, tcp and icmp.

Note that ICMP rules can currently only be used to open all ICMP traffic types.

Domains

Domains provide a way to make hosted zones in your AWS account available for use with container tasks. For instance, if you would like to run a listener on a PowerShell Empire task that accepts connections to a domain instead of an IP address, you can use the domain resource to manage the domains that are available for this purpose. Once the domain is present, you can use the run_task command to execute a container task with a host name and domain name. See the Launching Container Tasks section of the Usage Through SDK page for more details.

Note that this method does not register the domain or create the hosted zone for you. You must have an existing domain with a corresponding hosted zone present in the AWS account where your ./havoc deployment resides.
Domains cannot be associated with remote container tasks.

Create a domain

response = h.create_domain(domain_name, hosted_zone)
  • domain_name - (Required) provide the domain name.
  • hosted_zone - (Required) provide the zone ID of the hosted zone associated with the domain.

Delete a domain

response = h.delete_domain(domain_name)
  • domain_name - (Required) provide the domain name.

    If you specified a domain during deployment of your ./havoc campaign, that domain will be used as your Campaign API domain and cannot be deleted with this method.

Get a domain

response = h.get_domain(domain_name)
  • domain_name (Required) provide the name of the domain to get.

List domains

response = h.list_domains()

Task Types

Task types reflect the various container tasks that are supported by the ./havoc platform. Each container task has a unique set of commands that can be used to instruct the container to perform various activities. The get_task_type method will provide a list of supported commands for the specified task type.

Create a task type

response = h.create_task_type(task_type, source_image, capabilities, cpu, memory)
  • task_type - (Required) provide a name to be used when referring to the task type.
  • source_image - (Required) provide the public registry entry for the container (make sure to include the image version, e.g. ":latest".
  • capabilities - (Required) a Python list of commands that the container task supports.
  • cpu - (Required) an integer that represents the number of cpu units reserved for the container. This parameter maps to CpuShares in the Create a container section of the Docker Remote API and the --cpu-shares option to docker run. The number of CPU units is linked with the amount of memory allocated for the container. See the Task Size section of Amazon's Task definition parameters for more information about allocating CPU units and memory.
  • memory - (Required) an integer that represents the amount (in MiB) of memory to present to the container. If your container attempts to exceed the memory specified here, the container is killed. This parameter maps to Memory in the Create a container section of the Docker Remote API and the --memory option to docker run. The amount of memory allocated is linked with the number of CPU units for the container. See the Task Size section of Amazon's Task definition parameters documentation for more information about allocating CPU units and memory.

Delete a task type

response = h.delete_task_type(task_type)
  • task_type - (Required) the name of the task type to be deleted.

Get a task type

response = h.get_task_type(task_type)
  • task_type - (Required) the task_type you want to retrieve details for.

List task types

response = h.list_task_types()

Tasks

The currently running container tasks associated with your ./havoc deployment will be reflected as tasks. For more information about launching and interacting with tasks, see the Usage section of this documentation.

Get a task's details

response = h.get_task(task_name)
  • task_name - (Required) the name associated with the task you want to retrieve details for.

List tasks

response = h.list_tasks()

Kill a task

response = h.kill_task(task_name)
  • task_name - (Required) the name associated with the task you want to kill.

Note that the kill_task method should only be used on cloud container tasks that are unresponsive or on remote container tasks that have already been terminated but are still listed in the list_tasks output. When the kill_task method is invoked for a cloud task, an ECS API call is made that force kills the container in ECS and the container task's details are deleted from various tables in DynamoDB. In this case, the container does not go through its normal termination process so there won't be any container task confirmation that the task terminated. For remote container tasks that are killed this way, it is assumed that the actual container has already exited so the Campaign API simply deletes the container task's entry from the "tasks" table in DynamoDB. If a remote container task has already exited but still appears in the list_tasks output, that implies that the container did not go through its normal termination process meaning that there won't be any container task confirmation that the task terminated. See the Interacting with Container Tasks section of the Usage Through SDK page for more information about the recommended way to terminate a container.

Workspace

The workspace is a place to store files that are shared amongst all container tasks. This is useful for payloads that are generated by one container task and then distributed by another. When a container task starts up, it automatically downloads all of the files in the workspace to a local directory on the container task. If a payload is generated by a container task, you can instruct the container task to push the payload up to the workspace. See Interacting with Container Tasks for more information about using the workspace to share files between container tasks.

Create a file

response = h.create_file(file_name, raw_file)
  • file_name - (Required) the name of the file being added to the workspace.
  • raw_file - (Required) the binary encoded raw file contents.

Delete a file

response = h.delete_file(file_name)
  • file_name - (Required) the name associated with the file you would like to delete from the workspace.

Get a file

response = h.get_file(file_name)
  • file_name - (Required) the name associated with the file you want to retrieve from the workspace.

List files

response = h.list_files()