I recommend to start contributing code by using the plugin system. But beyond that there is much more you can do.
Code code
=========
Several core module create the system. They are in the *app* folder
* experimentcontrol: Control experiments. This is the central control for everything
* calderacontrol: remote control for Caldera using the Caldera REST API
* calderaapi_2: Direct REST Api to caldera 2.* (deprecated)
* calderaapi_4: Direct REST Api to caldera 4.* (Caldera 4 is alpha)
* calderacontrol: Remote control for Caldera with convenience methods
* metasploit: Metasploit control. Simplifies the basic attack step so they can be used from plugins
* machinecontrol: Create/start and stop VMs. Will call the machinery plugin
* pluginmanager: Plugin manager tasks. Has methods to verify plugin quality as well
* config: Reading and processing configuration files
* attacklog: Logging attack steps and output to stdio
* config_verifier: Verifyies the configuration
* attack_log: Logging attack steps and output to stdio
* doc_generator: Generates human readable documents from attack logs
@ -24,7 +30,9 @@ CalderaControl
Class for Caldera communication
..autoclass:: app.calderacontrol.CalderaControl
:members:
:members:
:member-order:bysource
:show-inheritance:
----------
Metasploit
@ -33,7 +41,9 @@ Metasploit
Class for Metasploit automation
..autoclass:: app.metasploit.Metasploit
:members:
:members:
:member-order:bysource
:show-inheritance:
-----------------
MetasploitInstant
@ -42,7 +52,9 @@ MetasploitInstant
Extends. In addition to the communication features from the superclass Metasploit it simplifies basic commands.
..autoclass:: app.metasploit.MetasploitInstant
:members:
:members:
:member-order:bysource
:show-inheritance:
--------
MSFVenom
@ -51,7 +63,9 @@ MSFVenom
Class for MSFVenom automation
..autoclass:: app.metasploit.MSFVenom
:members:
:members:
:member-order:bysource
:show-inheritance:
--------------
MachineControl
@ -60,7 +74,9 @@ MachineControl
Class controlling a machine
..autoclass:: app.machinecontrol.Machine
:members:
:members:
:member-order:bysource
:show-inheritance:
-----------------
ExperimentControl
@ -69,7 +85,9 @@ ExperimentControl
Class controlling the experiment
..autoclass:: app.experimentcontrol.Experiment
:members:
:members:
:member-order:bysource
:show-inheritance:
------
Config
@ -78,10 +96,14 @@ Config
Internal configuration handling. Currently there are two classes. One for the whole experiment configuration. The second one for machine specific configuration.
To experiment with different sensors installed on the targets there is the sensor plugin. It contains a plugin class that **MUST** be based on the *SensorPlugin* class.
The main goal of PurpleDome is to study sensor technology, which data they can collect and how to create an accurate picture of what happens during an attack. So this can be one of the most important plugin classes to extend.
The main goal of PurpleDome is to study sensor technology: what data can be collected and how to create an accurate picture of what happens during an attack. So this can be one of the most important plugin classes to extend.
Usage
=====
To create a new plugin, start a sub-folder in plugins. The python file in there must contain a class that inherits from *SensorPlugin*.
If the plugin is activated for a specific machine specific methods will be called to interact with the target:
If the plugin is activated for a specific machine specific methods will be called to interact with the target. Especially:
* prime: Easly installation steps, can trigger a reboot of the machine by returning True
* install: Normal, simple installation. No reboot
* start: Start the sensor
* stop: Stop the sensor
* collect: Collect results
@ -30,9 +28,26 @@ The boilerplate contains some basics:
Additionally you can set *self.debugit* to True. This will run the sensor on execution in gdb and make the call blocking. So you can debug your sensor.
Method: collect
---------------
This is the essential method you will have to implement. It will collect the data produced by the sensor and make it available to be stored in the zip-results
Method: start
-------------
Also an important method. Will be called before the attack to start the sensor. You will have to implement this. *But* if your collect method just collects log files from the system that are already generated you can also skip that.
Method: stop
------------
Will stop the sensor just prior to calling collect. There could be scenarios where you do not need it.
The experiment being run handles the machines. Those machines can be targets or attacker machines. Different types of machine controllers are covered by those plugins.
The experiment being run handles the machines. Those machines can be targets or attacker machines. Different types of machine controllers are covered by plugins of the type "MachineryPlugin".
A VM plugin handles several things:
@ -32,42 +32,44 @@ The boilerplate contains some basics:
* description. A human readable description for this plugin.
* required_files: A list. If you ship files with your plugin, listing them here will cause them to be installed on plugin init.
Some relevant methods that must be implemented (even if they will not contain code) are:
up
--
There are two sets of commands to implement for machines
Starts the machine
Basic handling:
create
------
* up
* create
* halt
* destroy
* get_state
* get_ip
Creates the machine. Vagrant for example can create machines based on config files.
Communication:
halt
----
* connect
* remote_run
* disconnect
* put
* get
Stop the machine
The communication commands are already implemented in *ssh_features.py* and you can use them they way the vagrant_plugin.py is doing. At least as long as you want to use SSH to communicate (recommended !).
destroy
-------
Destroy the machine
The machinery plugin
====================
get_state
---------
Get the machines state. The class MachineStates contains potential return values
get_ip
------
For a full list of methods read on:
Get the ip of the machine. If the machine is registered at the system resolver (/etc/hosts, dns, ...) a machine name would also be a valid response. As long as the network layer can reach it, everything is fine.
For an attack leave attack traces on a machine it should be vulnerable. Services should run. Old application be installed, users with weak passwords added to the system. You get the idea.
For an attack to leave attack traces the target machie machine should be vulnerable. This means:
For you as a user to be flexible there is a vulnerability plugin type that (surprise !) adds vulnerabilities to targets.
* Services run
* Old and unpatched application are installed
* Users with weak passwords are added to the system
You get the idea.
To get your systems vulnerable there is a vulnerability plugin type that adds vulnerabilities to targets.
This plugin type allows you to punch some holes into the protection of a machine. Which vulnerability plugins are loaded for a specific target is defined in the configuration file. Feel free to weaken the defenses.
@ -24,25 +30,23 @@ The boilerplate contains some basics:
* description: A human readable description for this plugin.
* ttp: The TTP number linked to this vulnerability. See https://attack.mitre.org/ as a hint which TTP this vulnerability could be related to. If you do not know the TTP, use "???"
* references: A list of urls to blog posts or similar describing the vulnerability
* required_files: If you ship files with your plugin, listing them here will cause them to be installed on plugin init.
Method: install (optional)
--------------------------
* required_files: If you ship files with your plugin: listing them here will cause them to be installed on plugin init.
*start* starts the vulnerability on the target. *install* is called before that. If you have to setup anything in the plugin space (and not on the target) do it here.
Method: start
-------------
Starts the vulnerability on the machine. The most important method you can use here is "self.run_cmd" and execute a shell command.
Starts the vulnerability on the machine. The most important method you can use here is "self.run_cmd" and execute a shell command. This must be implemented in your plugin.
Method: stop
------------
Undo the changes after the attacks ran. If the machine is re-used (and not re-built or run from a snapshot) this will make it simpler for the user to run more experiments on slightly modified systems.
Undo the changes after the attacks ran. If the machine is re-used (and not re-built or run from a snapshot) this will make it simpler for the user to run more experiments on slightly modified systems. This must be implemented in your plugin. Even if is just an empty method that does nothing.
# If metasploit requirements are not set, self.metasploit stay None and using metasploit from a plugin not having the requirements will trigger an exception
defcopy_to_attacker_and_defender(self):
""" Copy attacker/defender specific files to the machines. Called by setup, do not call it yourself. template processing happens before """
""" Copy attacker/defender specific files to the machines. Called by setup, do not call it yourself. template processing happens before
@ -96,12 +109,16 @@ class MachineryPlugin(BasePlugin):
""" Returns if the machine is running """
returnself.get_state()==MachineStates.RUNNING
defget_state(self):
defget_state(self)->MachineStates:
""" Get detailed state of a machine """
raiseNotImplementedError
defget_ip(self):
""" Return the IP of the machine. If there are several it should be the one accepting ssh or similar. If a resolver is running, a domain is also ok. """