-
Notifications
You must be signed in to change notification settings - Fork 15
Modules Overview
As said previously when presenting Payload modules, Wiregost gives a consequent part of its functionality through its Modules.
At the moment, two types of Modules are usable in Wiregost (Payload and Post), and one type allows you to easily write new ones (Post).
This page is an overview of the code through which Modules are implemented, and used.
In order to provide extensible module functionality through functions and properties, we leverage Go interfaces: this way, we can make many types of modules, or extend them easily, while retaining the capacity of the client to run them as well. If you know about Go, you will guess why the implicit interface implementation of Go is really useful in the present case.
The Module interface is the following:
type Module interface {
Init(int32) error
Run(string) (string, error)
SetOption(string, string)
ToProtobuf() *pb.Module
}
Init(int32) error
When a module is loaded onto a user's module stack, it inits itself by parsing its metadata file (metadata.json
) and by
registering the ModuleUserID (int32)
to the module. This ModuleUserID
is a unique number produced by each connected console.
When a module produces events (we'll see events below), it specifies the ModuleUserID. When all consoles receive the event, only
the console that ran the module will print the event.
Run(string) (string, error)
When the client console 'runs' the module, its sends its command to the module. Because payload modules have several commands for
either spawning listeners or compiling implants, they make use of the string
parameter for dispatching to the good function.
While your module must thus have this Run(command string) (result string, err error)
function, it is NOT obliged to make use of this parameter.
We'll see below how to use the return values string
and error
, in conjunction with Module Events.
SetOption(string, string)
When you set a module's option in the console, the server-side Module object uses this function to set the option to the given value.
ToProtobuf() *pb.Module
When you load a module onto the stack and after it has inited itself, the Server will use this function to send the Module to the console.
NOTE As you will see below and in the following pages, the only function that you will actually see when writing a module is the Run()
function.
If you already code in Go, you must know that Modules are also a struct with its fields and methods. Below is the Module struct type, and its Options struct type:
type Module struct {
Name string `json:"name"` // Name of the module
Type string `json:"type"` // Type of module (auxiliary, exploit, post, payload)
Path []string `json:"path"` // Path to the module (ie. post/windows/x64/powershell/gather/powerview)
Description string `json:"description"` // Description of the module
Notes string `json:"notes"` // Notes about the module
References []string `json:"references"` // A list of references to vulnerabilities/others (ie. CVEs)
Author []string `json:"author"` // A list of module authors
Credits []string `json:"credits"` // A list of people to credit for underlying tools/techniques
Platform string `json:"platform"` // Operating system the module can run on.
Targets []string `json:"targets"` // A list of operating system versions the modules works on
Arch string `json:"arch"` // CPU architecture for which the module works
Lang string `json:"lang"` // Programming language in which the module is written
Priviledged bool `json:"priviledged"` // Does the module requires administrator privileges
Options map[string]*Option
UserID int32
}
// Option - Module option
type Option struct {
Name string `json:"name"` // Name of the option
Value string `json:"value"` // Value of the option (default is filled here)
Required bool `json:"required"` // Is this a required option ?
Flag string `json:"flag"` // Flag value of the option, used for execution
Description string `json:"description"` // A description of the option
}
When the Module is loaded onto the stack, it calls his method Init()
and parses the following JSON metadata file:
{
"type": "post",
"name": "MimiPenguin",
"path": ["post", "linux", "x64", "bash", "credentials", "MimiPenguin"],
"author": ["Dan Borges (@ahhh"],
"credits": ["Hunter Gregal (@HunterGregal)"],
"platform": "linux",
"arch": "x64",
"lang": "bash",
"privileged": true,
"description": "mimipenguin is a bash script used to find plaintext credentials in memory during post-exploitation. Must be run as root. It automates the dumping of
memory and searches for Linux user credentials. The MimiPenguin script is downloaded from the C2 Server, executed and then deleted.",
"notes": "https://attack.mitre.org/wiki/Software/S0179",
"options": {
"Session": {"name": "Session", "value": "", "required": true, "flag": "", "description":"Implant session to run this module on"},
"TempDirectory": {"name": "TempDirectory", "value": "/tmp", "required": true, "flag": "", "description":"Directory in which to download the MimiPenguin script."}
}
}
Therefore, you can add any number of options to your module, all of them will be usable.
The Module type presented above is inherited (in Go, embedded) by all Modules that you can use in Wiregost.
Therefore, the Modules you can write will automatically implement the Module
interface, and you won't have
to deal with
Init()
, SetOption()
or ToProtobuf()
.
Below is an example of a Module template, that you can find (if you clone the repo) in the modules/templates/
directory:
package main
import (
"github.com/maxlandon/wiregost/server/log"
"github.com/maxlandon/wiregost/server/module"
)
// [ Base Methods ] ------------------------------------------------------------------------//
// Post - A Post Module (Change "Post")
type Post struct {
*module.Module
}
// New - Instantiates a Post Module, loading its metadata
func New() *Post {
mod := &Post{&module.Module{}}
mod.Path = []string{"post", "path/to/module/directory"}
return mod
}
var modLog = log.ServerLogger("path/to/module/directory", "module")
// [ Module Methods ] ------------------------------------------------------------------------//
// Run - Module entrypoint.
func (s *Post) Run(command string) (result string, err error) {
return "Module executed", nil
}
We will explain in detail how to modify and use this template in order to write a module in the following pages, but for now, you should notice:
type Post struct {
*module.Module
}
When you write a module, you declare a new type
instead of a variable, because it must declare the Run()
function, which will be
specific to this module. (In Go, you cannot declare type methods outside of the package where the type is declared).
The *module.Module
is the way, in Go, to make your Module to inherit the base Module's type properties and functions
func New() *Post {
mod := &Post{&module.Module{}}
mod.Path = []string{"post", "path/to/module/directory"}
return mod
}
This function instantiates the module, and embeds a module.Module{}
base module type in it, so that it inherits its methods.
It also specifies the path in which to find the metadata file, (this path will be overwritten when the module is inited)