A forum for reverse engineering, OS internals and malware analysis 

Forum for discussion about user-mode development.
 #32498  by zer0cat
 Tue Jan 22, 2019 7:25 pm
I am writing my program, and I want it to work correctly in a low integrity level. But, how can I emulate it? I have tried three ways, and always different options come out (for example, in 1 case the program can create processes, in the second it cannot). Why is that? What is the correct way?

1)- PSEXEC -L prog.exe
2)- ICACLS prog.exe /SETINTEGRITYLEVEL LOW
3) run PROCESS HACKER -> run as Limited User
 #32511  by zer0cat
 Thu Jan 24, 2019 4:58 pm
EP_X0FF
I tried to compile this code, but i have error: all programms (what I try to run in LOW) crashed on call CreateProcessAsUserW with code 0xc0000022.

This code, compiler is Pelles C:
Code: Select all
void WINAPI CreateLowProcess()
{
BOOL                  fRet;
HANDLE                hToken        = NULL;
HANDLE                hNewToken     = NULL;
PSID                  pIntegritySid = NULL;
TOKEN_MANDATORY_LABEL TIL           = {0};
PROCESS_INFORMATION   ProcInfo      = {0};
STARTUPINFOW           StartupInfo   = {0};

 // Notepad is used as an example
 WCHAR wszProcessName[MAX_PATH] = L"C:\\Windows\\System32\\Notepad.exe"; //Or another program, all crashes

 // Low integrity SID
 WCHAR wszIntegritySid[20] = L"S-1-16-1024";
 //PSID pIntegritySid = NULL;

    fRet = OpenProcessToken(GetCurrentProcess(),TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT | TOKEN_QUERY |  TOKEN_ASSIGN_PRIMARY,&hToken);

    if (!fRet)
    {
        goto CleanExit;
    }

    fRet = DuplicateTokenEx(hToken,0,NULL,SecurityImpersonation,TokenPrimary,&hNewToken);

    if (!fRet)
    {
        goto CleanExit;
    }

    fRet = ConvertStringSidToSidW(wszIntegritySid, &pIntegritySid);

    if (!fRet)
    {
        goto CleanExit;
    }

    TIL.Label.Attributes = SE_GROUP_INTEGRITY;
    TIL.Label.Sid        = pIntegritySid;

    //
    // Set the process integrity level
    //
	StartupInfo.cb = sizeof(STARTUPINFOW);

    fRet = SetTokenInformation(hNewToken,TokenIntegrityLevel,&TIL,sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(pIntegritySid));

    if (!fRet)
    {
        goto CleanExit;
    }

    //
    // Create the new process at Low integrity
    //

    fRet  = CreateProcessAsUserW(hNewToken,NULL,wszProcessName,NULL,NULL,FALSE,0,NULL,NULL,&StartupInfo,&ProcInfo);

CleanExit:

    if (ProcInfo.hProcess != NULL)
    {
        CloseHandle(ProcInfo.hProcess);
    }

    if (ProcInfo.hThread != NULL)
    {
        CloseHandle(ProcInfo.hThread);
    }

    LocalFree(pIntegritySid);

    if (hNewToken != NULL)
    {
        CloseHandle(hNewToken);
    }

    if (hToken != NULL)
    {
        CloseHandle(hToken);
    }

    return;
}
 #32513  by EP_X0FF
 Fri Jan 25, 2019 4:06 am
Heh, well pretty much what could you expect from MSDN Microsoft code, isn't it?

Try this instead.
Code: Select all
BOOL Exec(
	_In_ LPWSTR lpszCommandLine,
	_In_ LPWSTR lpszDirectory,
	_In_ DWORD  dwSubAuthority,
	_In_ BOOL	WaitForExit
)
{
	BOOL cond = FALSE;
	BOOL bResult = FALSE;
	HANDLE hToken = NULL, hNewToken = NULL;
	SID_IDENTIFIER_AUTHORITY MLAuthority = SECURITY_MANDATORY_LABEL_AUTHORITY;
	PSID pIntegritySid = NULL;
	TOKEN_MANDATORY_LABEL tml;
	PROCESS_INFORMATION pi;
	STARTUPINFO si;

	do {

		bResult = OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE | TOKEN_QUERY |
			TOKEN_ADJUST_DEFAULT | TOKEN_ASSIGN_PRIMARY, &hToken);
		if (bResult != TRUE) {
			break;
		}

		bResult = DuplicateTokenEx(hToken, 0, NULL, SecurityImpersonation,
			TokenPrimary, &hNewToken);
		if (bResult != TRUE) {
			break;
		}
		
		bResult = AllocateAndInitializeSid(&MLAuthority, 1, dwSubAuthority,
			0, 0, 0, 0, 0, 0, 0, &pIntegritySid);
		if (bResult != TRUE) {
			break;
		}

		RtlSecureZeroMemory(&tml, sizeof(tml));
		tml.Label.Attributes = SE_GROUP_INTEGRITY;
		tml.Label.Sid = pIntegritySid;

		bResult = SetTokenInformation(hNewToken, TokenIntegrityLevel, &tml,
			(sizeof(tml) + GetLengthSid(pIntegritySid)));
		if (bResult != TRUE) {
			break;
		}

		RtlSecureZeroMemory(&si, sizeof(si));
		si.cb = sizeof(si);

		bResult = CreateProcessAsUser(hNewToken, NULL, lpszCommandLine, NULL, NULL,
			FALSE, 0, NULL, lpszDirectory, &si, &pi);
		if (bResult) {
			if (WaitForExit) {
				WaitForSingleObject(pi.hProcess, INFINITE);
			}
			CloseHandle(pi.hProcess);
			CloseHandle(pi.hThread);
		}

	} while (cond);

	if (hToken) {
		CloseHandle(hToken);
	}
	if (hNewToken) {
		CloseHandle(hNewToken);
	}
	if (pIntegritySid) {
		FreeSid(pIntegritySid);
	}
	return bResult;
}
call it as shown, note string params must point to writable buffers.
Code: Select all
	WCHAR szParams[MAX_PATH + 1] = L"C:\\windows\\system32\\notepad.exe";
	WCHAR szDir[MAX_PATH + 1] = L"c:\\windows";

	Exec((LPWSTR)szParams, (LPWSTR)szDir, SECURITY_MANDATORY_LOW_RID, FALSE);
123.png
123.png (49.97 KiB) Viewed 469 times
 #32515  by zer0cat
 Fri Jan 25, 2019 11:39 am
EP_X0FF, thank you, your code works good.

I have one question, only for myself education. Microsoft tells, that Low Sid ID is - "S-1-16-1024";
But in book "Writing Secure Code for Windows Vista" (Howard,LeBlank) there is another string for low ID - "S-1-16-4096".

Why and where is it right?
 #32517  by EP_X0FF
 Fri Jan 25, 2019 2:41 pm
zer0cat wrote: Fri Jan 25, 2019 11:39 am EP_X0FF, thank you, your code works good.

I have one question, only for myself education. Microsoft tells, that Low Sid ID is - "S-1-16-1024";
But in book "Writing Secure Code for Windows Vista" (Howard,LeBlank) there is another string for low ID - "S-1-16-4096".

Why and where is it right?
That is the MS example error. It is 4096 (0x1000) and not 1024.
Well you can submit this as bug to MS via https://github.com/MicrosoftDocs/feedback/issues issues section, but it looks like this issues section is dead, well it is Microsoft you know :)
 #32522  by Vrtule
 Fri Jan 25, 2019 10:13 pm
I have one question, only for myself education. Microsoft tells, that Low Sid ID is - "S-1-16-1024";
Yes, it is S-1-16-4096. SIDs beginning with S-1-16- are used for mandatory integrity levels. The higher the third number, the higher the integrity level is.

Actually (and just for the skae of curiosity), you can assign also quite strange integrity levels, such as S-1-16-4096-200 and it quite works but that may possibly generate some extra fun for you (I experimented with this some years ago and remember only that the behavior was non-standard in certain cases).