Giter VIP home page Giter VIP logo

ppldump_bof's Introduction

PPLDump BOF

Who worked on this?

  • Justin Lucas (@the_bit_diddler)
  • Brad Campbell (@hackersoup)

What is this?

Jokingly, an exercise of my own personal sanity maintenance. In reality, this is a faithful porting of @itm4n's PPLDump project.

As one may imagine, this is a fully-fledged BOF to dump an arbitrary protected process.

But, why?

The goal isn't the destination, but the journey. Or that's what I told myself to make the endless suffering of this endeavor a bit less acute. :)

Cool, but what are the requirements?

  • An administrative session of some kind
  • Knowledge of the PPL process ID (PID) you wish to dump
  • Currently residing in a 64-bit process
  • Currently residing on a Windows 10 or greater endpoint

What is this massive fileheader.h header, why so sus?

This is a one-to-one dump of the original resource file created during building the PPLDump project DLL, and you're more than welcome and encouraged to fact-check this. As the original resource file was embedded (and therefore not usable due to a lack of linking for Beacon Object Files). This was a way around that. In the future, I may implement this ability to bring them arbitrarily, but use at your own risk.

What do I need to know before doing anything?

  • You MUST change the wcPID varaible, found in main.c to be the same as your desired process ID. Seriously.
  • As a result, you MUST build this project from source per endpoint you wish to do this on. There's a Makefile, just run it.
  • Optionally, you may change the location/name of the dmp file. This is DEFAULT_DUMP_FILE in src/headers/exploit.h

How do I run it?

  1. Build the project via the Makefile in the src directory, ensuring again, that you have ABSOLUTELY changed the variable mentioned above.
  2. Load the Aggressor CNA file in the dist directory.
  3. Within your Beacon of choice (and one that meets the criteria): ppldump YOUR_PROTECTED_PROCESS_PID

To-Do Items (if I have the time)

  • Port more function calls to syscalls, but this is a very time-consuming process.
  • Fix the unfortunate fail-pile of casting the desired process identifier to a wchar_t*. Nothing I tried worked.
  • Add support for a user-supplied DLL for other shenanigans.

ppldump_bof's People

Contributors

espressocake avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

ppldump_bof's Issues

Compile error

There were some errors when I compiled it.
image

i hope u can help me.thanks

Some code correctness and hygiene issues

Some code correctness issues in exploit.h

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

An OUT param is written to before the function succeeds leading to an edge case where memory is leaked if the function fails.

BOOL TokenGetSid(HANDLE hToken, PSID* ppSid) {
    BOOL bReturnValue = TRUE;
    DWORD dwSize = 0;
    PTOKEN_USER pTokenUser = NULL;

    if ( !sFunctionPointerStruct.StructGetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize) ) {
        if ( sFunctionPointerStruct.StructGetLastError() != ERROR_INSUFFICIENT_BUFFER ) {
            BeaconPrintf(CALLBACK_ERROR, "We received an unexpected value from TokenGetSid's GetTokenInformation in utils.h.\n");
            goto end;
        }
    }

    // Second call to populate
    pTokenUser = (PTOKEN_USER)sFunctionPointerStruct.StructLocalAlloc(LPTR, dwSize);
    if (!pTokenUser) {
        goto end;
    }

    if ( !sFunctionPointerStruct.StructGetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &dwSize) ) {
        BeaconPrintf(CALLBACK_ERROR, "We received an unexpected value from TokenGetSid's GetTokenInformation in utils.h.\n");
        goto end;
    }

    *ppSid = (PSID)sFunctionPointerStruct.StructLocalAlloc(LPTR, SECURITY_MAX_SID_SIZE);
    if (!*ppSid) {
        BeaconPrintf(CALLBACK_ERROR, "Error in setting dereferenced value in utils.h TokenGetSid ppsid.\n");
        goto end;
    }

    if ( !sFunctionPointerStruct.StructCopySid(SECURITY_MAX_SID_SIZE, *ppSid, pTokenUser->User.Sid) ) {
        BeaconPrintf(CALLBACK_ERROR, "Error in setting copying SID in utils.h TokenGetSid ppsid.\n");
        goto end;
! bReturnValue is FALSE but OUT param *ppSid contains allocated memory which will be leaked in this case because the caller won't free it since the function failed
    }

See

Edge case leak if allocation fails

BOOL TokenCompareSids(PSID pSidA, PSID pSidB) {
    BOOL bReturnValue = FALSE;
    LPWSTR pwszSidA   = NULL;
    LPWSTR pwszSidB   = NULL;

    if ( sFunctionPointerStruct.StructConvertSidToStringSidW(pSidA, &pwszSidA) && sFunctionPointerStruct.StructConvertSidToStringSidW(pSidB, &pwszSidB) ) {
        bReturnValue = MSVCRT$_wcsicmp(pwszSidA, pwszSidB) == 0;
        sFunctionPointerStruct.StructLocalFree(pwszSidA);
        sFunctionPointerStruct.StructLocalFree(pwszSidB);
    } else {
! it's possible one of the calls to sFunctionPointerStruct.StructConvertSidToStringSidW failed and this branch will leak the Sid for the success case
        BeaconPrintf(CALLBACK_ERROR, "We have encountered an error in TokenCompareSids within utils.h: 0x%08x\n", sFunctionPointerStruct.StructGetLastError());
    }

    return bReturnValue;
}

See:

if ( sFunctionPointerStruct.StructConvertSidToStringSidW(pSidA, &pwszSidA) && sFunctionPointerStruct.StructConvertSidToStringSidW(pSidB, &pwszSidB) ) {

There is another case here:

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

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

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

BOOL TokenIsNotRestricted(HANDLE hToken, PBOOL pbIsNotRestricted) {

...

See

BOOL TokenIsNotRestricted(HANDLE hToken, PBOOL pbIsNotRestricted) {

Fail to check if memory was successfully allocated for guid

Check for failed allocation from MiscGenerateGuidString

    MiscGenerateGuidString(&pwszGuid);

MiscGenerateGuidString(&pwszGuid);

Leak of token

  if (bCurrentUserIsSystem) {
        if ( !sFunctionPointerStruct.StructOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ADJUST_PRIVILEGES, &hCurrentToken) ) {
            BeaconPrintf(CALLBACK_ERROR, "Failed to open process token in stage 6. Exiting.\n");
            goto end;
        }
    } else {
        if ( !sFunctionPointerStruct.StructOpenThreadToken(sFunctionPointerStruct.StructGetCurrentThread(), TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ADJUST_PRIVILEGES, FALSE, &hCurrentToken) ) {
            BeaconPrintf(CALLBACK_ERROR, "Failed to open thread token in stage 6. Exiting.\n");
            goto end;
        }
    }

    if ( !TokenCheckPrivilege(hCurrentToken, L"SeAssignPrimaryTokenPrivilege", TRUE) ) {
        BeaconPrintf(CALLBACK_ERROR, "Failed to alter token (SeAssignPrimaryTokenPrivilege) in stage 6. Exiting.\n");
        goto end;
    } else {
        BeaconPrintf(CALLBACK_OUTPUT, "Successfully assigned SeAssignPrimaryTokenPrivilege.\n");
    }

    if ( !sFunctionPointerStruct.StructDuplicateTokenEx(hCurrentToken, MAXIMUM_ALLOWED, NULL, SecurityAnonymous, TokenPrimary, &hNewProcessToken) ) {
        BeaconPrintf(CALLBACK_ERROR, "Failed DuplicateTokenEx call in stage 6. Exiting.\n");
        goto end;
    } else {
        BeaconPrintf(CALLBACK_OUTPUT, "Successfully duplicated token.\n");
    }
! No call to CloseHandle on hCurrentToken

if ( !sFunctionPointerStruct.StructOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ADJUST_PRIVILEGES, &hCurrentToken) ) {

possible wild NtClose call on hProcessToken in EnableRequisitePrivileges

BOOL EnableRequisitePrivileges(void) {
    NTSTATUS judgement;   
	DWORD dwFailCount = 0;
	HANDLE hProcessToken; <<<<<<<<<<<<<<<<< not initialized to NULL
	HANDLE hTargetProcess = NULL;
	BOOL bIsSystem = FALSE;
	DWORD dwProcessId = 0;
	DWORD dwProcessProtectionLevel = 0;
	LPWSTR pwszProcessProtectionName = NULL;
	DWORD dwProcessIntegrityLevel = 0;
	LPCWSTR ppwszRequiredPrivileges[2] = { L"SeDebugPrivilege", L"SeImpersonatePrivilege" };

    judgement = NtOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hProcessToken);
    if (judgement != STATUS_SUCCESS) {
        dwFailCount++;
        BeaconPrintf(CALLBACK_OUTPUT, "Error in ascertaining current user token.\n");
!        NtClose(hProcessToken);    <<<<<< if NtOpenProcessToken fails, hProcessToken won't be written to. This results in a wild close on hProcessToken because it was not initialized

        return FALSE;

NtClose(hProcessToken);

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);

FindFileForTransaction leaks memory for pSidTarget

Need a call to sFunctionPointerStruct.StructLocalFree(pTargetSid); at cleanup in FindFileForTransaction

sFunctionPointerStruct.StructConvertStringSidToSidW(L"S-1-5-18", &pSidTarget);

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.