ConsulThink ConsulThink ConsulThink
  • Home
  • Chi siamo
  • Solutions & Services ►
    • e-CyberMesh
    • e-CyberDev
    • Consulenza Specialistica
    • Consulthink Academy
    • e-CyLabs
  • News
  • ExperThinkers Room
  • Lavora con noi
  • Contatti
  • Policy
  • Privacy
CyberSecurity ExperThinkers Offensive Security Red Team

Rustware Part 1: Shellcode Process Injection Development

27 Ottobre 2023

Introduction

Malware development is essential when performing activities like Red Teaming, Adversary Emulation and Network Penetration Testing, the operator can use custom malwares to perform various tasks based on the specific situation. At the same time, analyzing Malwares is useful to learn how malwares work and how to detect them, in order to defend our companies from threat actors. For these reasons we studied several books and courses about Windows Internals, Malware Development and Malware Analysis.

Several threat actors like ALPHV, Hive and Qilin started to develop malware using the Rust programming languages because of its great memory management, speed, and complexity during reverse engineering.

In the last months we started to study and develop custom tools using Rust program language. This first blog post is about the development of a binary that performs an injection of a MessageBox into a target process.

The Shellcode Process Injection we are going to use relies on the use of several WinAPIs: OpenProcess is used to open a handle to the target process, in our case Notepad.exe. We will use this handle to interact with Nodepad.exe, after that, using VirtualAllocEx we can allocate a new region of memory in Notepad.exe with Readable and Writable protection; this region will contain our shellcode written by WriteProcessMemory. Using VirtualProtectEx we can change the memory protection to Readable and Executable to allow CreateRemoteThread to run the shellcode contained in the new allocated memory in Notepad.exe.

The information contained in this blog post is for educational purposes only.

 

Process Injection

The process injection we are going to develop is a simple Shellcode Injection using the following WinAPIs:

  • OpenProcess: gets a handle to the target process
  • VirtualAllocEx: allocates memory in the remote target process
  • WriteProcessMemory: writes our payload into the allocated memory
  • VirtualProtectEx: changes the remote memory protection
  • CreateRemoteThread: runs our payload

 

The payload we are going to use is a message box showing the string “Process Injection”; it was generated using the following msfvenom command.

msfvenom

 

Rustware Setup

Everything we need to develop a Rust program that leverages on WinAPI, is well described in the Microsoft “Developing with Rust on Windows”. In our case, we used the following software, plugins and crate:

  • Visual Studio Code 1.83.0
  • Rust-analyzer 0.3.1689
  • CodeLLDB 1.10.0
  • Crates 0.6.3
  • Windows Crate 0.51.1

 

Rustware Development

First of all, it is necessary to add the Windows Crate to the Cargo.toml file to use the WinAPIs, as shown below.

Cargo.toml

Each WinAPI requires a feature that must be written in the Cargo.toml file; we can see the features in the Windows Crate documentation.

Below, a list of the WinAPIs we are going to use and the features they require:

  • OpenProcess: “Win32_System_Threading” and “Win32_Foundation”
  • VirtualAllocEx: “Win32_System_Memory”, and “Win32_Foundation”
  • WriteProcessMemory: “Win32_System_Diagnostics_Debug” and “Win32_Foundation”
  • VirtualProtectEx:”Win32_System_Memory”, and “Win32_Foundation”
  • CreateRemoteThread : “Win32_System_Threading”, “Win32_Foundation” and “Win32_Security”.

 

After adding all the features, the Cargo.toml file will look like this.

 Cargo

Each feature must also be imported in the code; we can achieve this with the use declaration as shown in the image below.

In order to get the PID of the target process as argument, we can use the std::env::args. The code below checks if the user has specified the PID as argument, if not, it prints the usage string, otherwise it saves the value in the pid variable.

imports

The payload is contained in an array of 272 unsigned 8-bit integers. The payload length is calculated using the len() function, and the payload_ptr variable (use std::ffi::c_void) contains a pointer to the payload, we get it by using the as_ptr() to get a raw pointer to the payload and then casting the raw pointer to a *const c_void.

Payload

The Inject function takes three parameters: the PID of the target process, a pointer to the payload, and the payload length.

Inject Function

The WinAPIs we are going to use are defined as unsafe function, because Rust can’t guarantee the memory safety, so it’s our responsibility. In the image below we can see OpenProcess implementation, it is declared as an unsafe function.

OpenProcess Implementation

In order to use an unsafe function, we need to add an unsafe block; we are going to use this block for all the WinAPIs. Let’s use OpenProcess to get a handle to the target process. It returns a Result enum containing the Handle to the opened process, or the error if it fails. Using the match construct we can use the variants Ok() and Err() to define what to do if the function succeeds or fails.

OpenProcess

If the function succeeds the program performs VirtualAllocEx to allocate a region of memory that is readable and writable into a remote target process and print the allocated memory address, otherwise it prints an error message. We don’t specify the lpaddress because we want the WinAPI to determinate where to allocate the region of memory.

VirtualAllocEx

After that, we have to write our payload in the new allocated memory. To do that we use WriteProcessMemory.

WriteProcessMemory

Using VirtualProtectEx, it is possible to change the memory protection to PAGE_EXECUTE_READ to make the payload executable.

VirtualProtectEx

At this point we can execute our payload using. The transmute function allows us to convert the pointer to our payload into a pointer to a function to be executed by the new created Thread as required by the WinAPI.

CreateRemoteThread

To compile the program into a 32bit binary we can use the target flag specifying the i686 architecture.

Cargo

Running the binary we successfully inject our MessageBox into Notepad.exe.

PI

 

Debugging

Using Process Hacker and x32dbg we can debug our binary to understand how it works under the hood. In x32dbg we can change the command line to specify the target process PID and set the breakpoints on the WinAPIs that our binary is going to use.

 

Change Command Line

Breakpoints

 

OpenProcess

OpenProcess

Running the debugger, we can see that OpenProcess is correctly getting the tree parameters:

  • 0x1FFFFF is PROCESS_ALL_ACCESS
  • 0 is false
  • 0x1F80 is the Notepad.exe PID in hex

OpenProcess Debug

 

We can see the Notepad.exe handle in our binary handles list.

Process Hacker

 

VirtualAllocEx

VirtualAllocEx

VirtualAllocEx stack contains the following parameters:

  • 0x160 is the Notepad.exe handle
  • 0x0 is None
  • 0x110 is the payload length
  • 0x1000 is MEM_COMMIT value
  • 0x4 is the PAGE_READWRITE value

 

VirtualAllocEx Debug

 

We can confirm it by using Process Hacker and inspecting the Notepad.exe memory, as we can see a new allocated memory with RW protection exists at address 0x4D20000.

Process Hacker

 

WriteProcessMemory

VirtualProcessMemory

Following the WriteProcessMemory arguments:

  • 0x160 is the Notepad.exe handle
  • 0x4D20000 is the remote memory address
  • 0xD8FC78 is the payload address
  • 0x110 is the payload len
  • 0x0 is None

 

WriteProcessMemory Debug

 

We can confirm it in ProcessHacker by inspecting the memory at address 0x4D20000.

Process Hacker

 

VirtualProtectEx

VirtualProtectEx

VirtualProtectEx is correctly getting the arguments:

  • 0x160 is the Notepad.exe handle
  • 0x4D20000 is the remote memory address
  • 0x110 is the payload length
  • 0x20 is the PAGE_EXECUTE_READ value
  • 0xD8FD98 is the old_protect variable address

VirtualProtectEx Debug

 

In ProcessHacker we can see the protection flag changed to RX.

Process Hacker

CreateRemoteThread

CreateRemoteThread

Lastly, the CreateRemoteThread arguments are:

  • 0x160 is the Notepad.exe handle
  • 0x0 is None
  • 0x0 is 0
  • 0x4D20000 is the remote memory address to be executed
  • 0x0 is None
  • 0x0 is 0
  • 0x0 is None

 

CreateRemoteThread

 

By continuing the execution, our MessageBox wil popup.  Process Injection Debug

 

Conclusion

Rust is a very powerful language; in the last years it found its way into the malware development, especially for ransomware because of its speed. The interaction with WinAPI is not very easy because of the datatype mismatch.

Rust performs security checks at compile and runtime that prevent some of the infamous bugs, since unsafe blocks lack of security checks, we need to be careful when developing malwares because WinAPIs we saw are defined as unsafe function.

In the next blog post we would like to show how to implement other techniques and how to reverse engineering Rust malwares.

Because we are new to Rust, any feedback will be appreciated.

References

  • https://learn.microsoft.com/en-us/windows/dev-environment/rust/
  • https://microsoft.github.io/windows-docs-rs/doc/windows/
  • https://socradar.io/why-ransomware-groups-switch-to-rust-programming-language/
  • https://crates.io/crates/windows
  • https://doc.rust-lang.org/book/
  • https://www.ired.team/offensive-security/code-injection-process-injection/process-injection
  • https://institute.sektor7.net
  • https://maldevacademy.com

 

By Raffaele Sabato
Team Leader – Cyber Offensive Solutions and Services

Consulthink S.p.A.
info@consulthink.it

Like
Recent posts
Cyber Insurance: pro e contro di un fenomeno in continua evoluzione
Approccio storico alla Progettazione del Software e alla Sicurezza Informatica
Previous post Fenomeno Qishing: la truffa tramite QR Code
Next post Rustware Part 2: Process Enumeration Development
Categorie
  • AI (2)
  • ASSINTEL (1)
  • Awareness (2)
  • Big Data (1)
  • Blockchain (1)
  • Casi di successo (1)
  • Cloud (2)
  • Cyberattack (2)
  • CyberSecurity (9)
  • Data Protection (9)
  • Enterprise Architecture (3)
  • Eventi (1)
  • ExperThinkers (26)
  • Formazione (2)
  • GDPR (11)
  • GRC (8)
  • ICT (2)
  • Information Security (8)
  • IoT (1)
  • Marketing (3)
  • Mobile (1)
  • News (8)
  • Normative (9)
  • Offensive (3)
  • Offensive Security (4)
  • People Management (1)
  • Phishing (2)
  • Premi (1)
  • Privacy (8)
  • R&D (1)
  • Red Team (4)
  • Security (5)
  • Smart Working (1)
  • Software (1)
  • Soluzioni (4)
  • Trend (4)
  • Uncategorized (1)
Ultime News
Cyber Insurance: pro e contro di un fenomeno in continua evoluzione
27 Ottobre 2023
Approccio storico alla Progettazione del Software e alla Sicurezza Informatica
27 Ottobre 2023
L’utilizzo dei dati nell’era dei social media: tra opportunità e rischi
27 Ottobre 2023
Equilibrio tra Innovazione e Sicurezza: la Sfida della Regolamentazione AI
27 Ottobre 2023
Consulthink e Lutech insieme
27 Ottobre 2023

P.Iva 07855131004 - Via Cristoforo Colombo, 163 - 00147 Roma

© Consulthink. All Right Reserved 2019


Privacy PolicyCookie