Orchestration script to simulate user activity on multiple machines thanks to the GHOSTS framework

May 12, 2022 by Basile Ameeuw | 2425 views

Offensive Security Cyber Range


The GHOSTS Framework is an open-source project created by Dustin Updyke, a cybersecurity researcher from the Carnegie Mellon University. It's a framework which offers a way to simulate user activity, usually for cyber awareness trainings or research in the field of cyber defense.

This tool consists of two parts:

  1. The first one is a server that gathers and displays all the information.
  2. The second part is composed of the clients which are going to simulate user activities.

Fundamentally, it's also possible to run the clients only but then it's not possible anymore to debug, test and control your simulation. In this article, the main points are not how to set up the server and the clients, because it's already explained in the two following articles which are written by Georgi Nikolov:

  1. Simulate user activity with the GHOSTS framework : Introduction
  2. Simulate user activity with the GHOSTS framework: Client set-up and Timelines

It can also be relevant to browse the Ghost Framework User Manual that I've written to help you deploying GHOSTS Framework thanks to my orchestration script. You can also read my How to Use Pypsexec manual if you encounter difficulties to use Pypsexec.

Server centralization

When the Linux server is created, it's important to run it with a bridged connection. Afterwards, we deploy and run the three dockers:

  • the API server to manage the clients
  • the PostgreSQL database to save and store the information
  • the Grafana server to display the information

Remark: The easiest way to do it is to run it thanks to the docker-compose

Clients initialization

Referential client (Windows) machine.

The easiest way to initialize a lot of Windows machines, ready to run GHOSTS, is to create an image of a referential machine with the right settings and prerequisites. The most important prerequisites are:

When this machine is set up, we just have to open X machines from this image and we then just have to know their IP address.

Clients' configuration

To make this image of a referential client, it asks not so much time and resources. To deploy this image a lot of time to create as many clients as you want, it's also quite easy but what is difficult is to configure these one after another. Indeed, if you want to only use the Framework GHOSTS, you have to configure each configuration file one after the other. Then, when you are going to run the executable ghosts you have to go manually on each client to run it. Afterwards, if you want to manage your different machines you are going to first find which client you want to manage, then you have to find the right JSON configuration file and finally you can modify it. It's also the same if you want to see the state of each machine, you have to go manually on each one.

We notice that for two or three clients it can still be possible to use it alone. Although, if you want to deploy a lot of client machines, it becomes very difficult, even impossible. Therefore, I implemented an orchestration script, containing some scripts with different function, in the Server where the three dockers already run. The main advantages of this script are:

  • More easy and more quick to configure and run the clients
  • Easier to make groups of clients with the same activities
  • Centralized control
  • Centralized management in real-time
  • Easier to stop GHOSTS on each or on some machines

Orchestration script

The orchestration script can be found here. It's divided into several scripts and each one has a specific task. As you can see on the following picture, one of them is for the configuration, one is for the management of the timeline in real-time, two others are to run and stop GHOSTS and the last one is to configure and then run GHOSTS.


As we can see, there is a single script, on the client, but you don't have to add it yourself or to change something in it. Indeed, when you run the configuration of all the clients, the first thing that the server will do is to check if there is already the right script and if it's not the case, it will be added.

Configuration ServerInit.py

All the client's configurations are made from the server, so the configuration is very centralized and you don't have to make several times the same configuration for all the machines. The server contains two important JSON files called IPaddress.json and configServer.json.

  1. The first one is to collect the IP address of each machine you want to run. As you will see in Future Work, this would normally be done automatically if you give only a range in which the IP addresses are.
  2. The second one is to configure all the different clients.

You have different settings and some of them will be browsed here after:

On the following picture, we can see the file configServer.json, for readability, the different parts have been numbered.

  1. Number one shows the general settings, these settings are available for all the different clients.

    • nbMachinesTotal: It's the total amount of machines
    • newMachines: defines if it's the first time we use these clients (typically to send the clientConfig.py)
    • pathGhostsOnClient: defines the path where ghosts is situated in the clients
    • groupsMachines: Collect the info for a group of clients which is going to have the same configurations
  2. Nuber two is the first group of machines

    • nbMachines: number of machines that should have the configurations of this group
    • applicationSettings: set the application JSON file in the client (IPaddress should not be added here, it's automatically done from the IPaddress JSON file)
    • timelineSettings: set the timeline JSON file in the clients
    • In the optionTimeline, you have to write the path of the JSON file you want to use in your timeline. The best way to do it, is to create a new file for each activity you want to run from a special type of machines.
    • time: a code to tell the clients machines to run the executable file ghosts.exe at a specific moment.
  3. Number three is the second group of machines Exactly the same as point 2 and it's possible to have as many groups as total amount of machines.


If you want more information about the different settings, don't hesitate to go check this in the User Manual that I've written ( Ghost Framework user manual. )

Real-time management InRealTimeUpdate.py

To manage the activities of the clients in real-time, the first thing to do is to configure the JSON file changeTimeline.json. You can see it in the following picture


nbOfComputersToBeChanged is for how many machines you want to update, newTimeline is to chose if the new timeline should be done from a template or from the timeline already on the client. idMachinesConcerned is to change the right machines. The boolean replace is just to say if you want to replace the timelines or to add it. TimeLineHandlersToAddOrReplace is the update itself so you have to respect the structure of the normal timeline.json

Run GHOSTS and stop it GhostRunner.py & StopGhost.py

For these two scripts you don't have to modify a JSON file, but you can still choose for some options. For example, if you want to stop only 2 machines you just have to run

python Ghostrunner.py -n 2

Indeed, you have 4 different modes that you can choose: (X is a number and Y is a json file)

  1. -a is to run or stop all the machines (for these you have the IP address)
  2. -n X is to run or stop X machines (the first one in IPaddress.json)
  3. -r X is to run or stop X machines but randomly
  4. -s Y is to run specific machines and you have to give a JSON file where all their IPaddresses are listed


This one is simply running first ServerInit.py and is going to follow with runningGhostRunner.py -a

Future Work

  • Script to collect the IP addresses in a specific range
  • Add more supported applications to the GHOSTS Framework
  • Manage the Postgres database to know which machines are running and which are not
  • Expand Linux support

This blog post is licensed under CC BY-SA 4.0

This website uses cookies. More information about the use of cookies is available in the cookies policy.