In the last post, Judas got SOCKS proxy and SSL support to make the proxy sneakier, but all the proxy can do is dump the requests and responses to the console. What if the red teamer wants to send the requests to a logging REST API? Luckily, Go can help with its plugin standard library package.
Designing the plugin architecture and lifecycle
To make plugins work, we first need to define a contract for plugins to implement. Plugins may need to do some kind of setup, like reading configuration from command line flags, and they will need to process each HTTP request-response transaction.
Plugins simply have to implement the Plugin interface, found in github.com/joncooperworks/judas/plugins, and Judas will cast it to a Plugin before returning it to the rest of the program.
When Judas starts, it will call every installed plugin’s Initialize function before any command line arguments are passed, or servers are created. Initialize can be used to define command line arguments, or read configuration data from a file.
When the listener starts, Judas creates a channel and passes each request-response pair to it. This channel is shared between the intercepting proxy and plugins. Every plugin’s ProcessTransaction method will be run in a separate goroutine to prevent slow plugins from blocking others.
This function returns the name of the plugin. It is used for debugging purposes.
Finding and running the plugins
Judas looks for .so files in the same directory as the judas executable. Plugins are stored in memory as a mapping of plugins to their arguments.
This map is later used to pass each plugin the HTTPTransaction channel, and the arguments returned from Initialize.
Creating a plugin
Creating plugins is pretty straightforward. A Judas plugin must expose a variable named “Plugin” that implements Plugin.
Go plugins must have package main, but do not require a main method. The plugin below logs every request and response received to the console, but could send data to another service for logging or further processing.
To create a plugin, simply pass the -buildmode=plugin flag to go build.
go build -buildmode=plugin -o loggingplugin.so bundled/loggingplugin.go
This will produce a binary, loggingplugin.so in the current working directory.
Machine:judas user$ file loggingplugin.so
loggingplugin.so: Mach-O 64-bit dynamically linked shared library x86_64
- As of Go 1.10, plugins are only supported on Mac OS X and Linux. It is not clear when Windows will be supported.
- Plugin code is run in the same process, meaning if a plugin panics, it will crash the entire program.
- There is no support for cryptographically signed plugins. Since the plugin API accepts a filename, it will be difficult to add signed plugins without creating TOCTOU vulnerabilities.
Liked this post and want to leave a tip?