Skip to content

Best practices for Tuoni Plugin development

Foreword

Before starting, please keep in mind that Tuoni C2 is a complex product that requires its plugins to be very diverse. Due to this, the plugin SDK is quite flexible in terms of the types of plugins that can be created. While this flexibility encourages creativity and avoids constraints, it also creates a steep learning curve that can make writing your first plugin more complex than it initially seems.

So, when starting, please be patient and read both these docs and the Java documentation thoroughly. In case of questions or confusion, don’t hesitate to reach out to the ShellDot team. We’re happy to help!

As mentioned earlier, most Tuoni plugins consist of the server-side plugin and the shellcode it generates for agents. This means one needs to write both the plugin code in Java (or another JVM language) for the server and separate code for the shellcode. In this example, we’re writing the server-side plugin code in Java 21, built with Gradle, and the shellcode in C# and .NET, built with Visual Studio.

To ease the first steps of creating your own plugin, you can use our example plugin repository as a starting point, copying the build logic and configuration validation/parsing from there: https://github.com/shell-dot/tuoni-example-plugins

Logging

Use the SLF4J logging facade for logging. This makes sure that the log statements end up in the Tuoni server log file. Do not use System.out or System.err for logging. During early development, it is recommended to log all the things until you are sure that the plugin works as expected. After that, it is recommended to log only the necessary information.

Error handling

Always handle exceptions and errors that are received when calling SDK methods. Never silently fail and ignore exceptions. If the exception is not recoverable, then it is recommended to throw a new exception with a more descriptive message. While most SDK methods have particular checked exceptions for throwing, it is also possible to throw RuntimeException in case of unexpected errors.

Keep in mind, that errors from background threads will not automatically be propagated to the main thread, so it is recommended to log all exceptions that are thrown in background threads.

Performance

Keep in mind that the Tuoni server is a JVM application and that the plugin code is executed in the same JVM as the rest of the server. Therefore, it is recommended to keep the plugin code as fast as possible. Avoid busy loops and similar pitfalls which would not only affect your plugin, but the performance of the whole server.

JSON parsing and configuration validation

Tuoni server does not enforce use of any particular JSON library for parsing and validating configurations. It is up to the plugin developer to choose the library that suits their needs the best.

For ShellDot own plugins, we use: