September, October, November, December, and most of January passed by silently without any RustRAT updates. There are many reasons for this, the two main ones being that I sort of lost the spark after completing a sort-of usable tech demo, and that work mostly fulfilled my programming needs with a few interesting assignments. Now I am back in action, however, and first up is making it more ergonomic to write code that is intended to run in the WASM “sandbox” (which is not much of a sandbox at all with all the holes I am punching in it).
I spent most of my summer vacation doing other things than programming malware, but now I am back in full force. First on the agenda is “releasing” version 0.1, and the release date is fast(-ish) approaching as the list of things I want done before version “0.1” keeps shrinking. Today I pushed the first code for the largest remaining part, the server’s user interface, which I have decided to name badtui.
It is now one year since I wrote the first blog post about RustRAT. Even though I did not start writing any actual code until this year, I still consider this some kind of anniversary. On this anniversary, few of the goals I set for version 0.1 remain. However, as I have worked on RustRAT, I have come to realise that quite a lot remains until RustRAT is something I would consider using in an engagement.
The rat is almost fully functional (for certain values of fully functional), and communication between rats and the server is operational. It is not quite ready, but a new update with a new git commit should hopefully be coming this or next week. While I think everything has proceeded surprisingly smoothly, I have spent many hours debugging stupid mistakes, and this post is about yet another mistake.
May is almost upon us, and it is time for another quick post on Rustrat progress. Implementing the random seed “generators” from last post went smoothly as soon as I realized that inline assembly is only available in nightly, and figured I needed to do something else. I decided to go for separate files containing the assembly for the required functionality, adding a custom build script to build the assembly file using CC. This post is not about my adventures with MASM, however, although I might revisit that later on. As you may have guessed from the title, this post is another cautionary tale about what can go wrong when you play with unsafe rust and pointers.
A couple of weeks ago I accidentally installed Civ 6 again, which reduced the time I have had available for other non-essential activity. Fortunately, I have just about had enough Civ for this round, which means that I should shortly have more time for things like RustRAT again. Progress has not halted to a complete stop, however, and rustrat-server is now more or less ready to receive incoming connections over HTTP. The server is not very usable at the moment, and before I have something even remotely ready for testing, basic logging and some interface to actually interact with the rats is needed.
Progress has not been as fast as I hoped lately. There are several reasons for this, but most of it is probably due to a lack of planning. When I finally started programming RustRAT I had a very specific idea of what I wanted to start with. After I finished that specific, little part of RustRAT, progressed seemed to halt to a grind.
While I have slowed down some, progress seems slower than it is because my plan is less detailed for this part of the development. My initial plan looked something like this:
Glue together wasm3 and libffi so that wasm blobs can call arbitrary functions.
When deciding on the architecture for RustRAT’s C2 server, I went for something asynchronous. There are no very good reasons for this, but I have never really written anything major in an asynchronous manner before. Besides, a lot of nice looking Rust crates are also written using asynchronous code, so this lets me play with them.
As I am doing something I have never done before, progress is slow as I play with tokio, figure out what to put in my .env file to get sqlx to compile, and attempt to handle HTTP requests with warp. All in all it is an enjoyable experience, mostly.
The libffi bindings are now working, which means that RustRAT is now able to execute WebAssembly binaries, and those binaries can call arbitrary functions from dlls. I have also uploaded the code to github, so it is possible to follow the progress at https://github.com/rustrat/rustrat
. In this post I will briefly mention what has been done so far, the next step on the way to a full-fledged RAT, and finally a little guide on how to call MessageBoxA from a WebAssembly binary.
The present Currently RustRAT is not very exciting, but it is possible to demonstrate the libffi capabilities. The “rustrat-client” executables can be used to execute WebAssembly binaries, for example from the “demo-messagebox” crate, which will call MessageBoxA.
RustRAT uses libffi (more specifically the libffi-rs bindings) to call arbitrary functions at run-time. This works by putting the function’s argument and return types into a struct and providing libffi with a function pointer. Libffi then makes sure that all the arguments are placed in the correct registers or on the stack and calls the function pointer. I am not that proficient with Rust yet, but if anything is unsafe, I am pretty sure this is it.
While developing RustRAT, my tests would initially contain calls to libffi-rs’s own call function and everything was proceeding smoothly. The call function is essentially something like this: