How to emulate LOW IL ?

Forum for discussion about user-mode development.
Post Reply
zer0cat
Posts: 6
Joined: Wed Aug 01, 2018 4:49 am

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
User avatar
EP_X0FF
Global Moderator
Posts: 4886
Joined: Sun Mar 07, 2010 5:35 am
Location: Russian Federation
Contact:

Wed Jan 23, 2019 7:50 am

Ring0 - the source of inspiration
zer0cat
Posts: 6
Joined: Wed Aug 01, 2018 4:49 am

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;
}
User avatar
EP_X0FF
Global Moderator
Posts: 4886
Joined: Sun Mar 07, 2010 5:35 am
Location: Russian Federation
Contact:

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
You do not have the required permissions to view the files attached to this post.
Ring0 - the source of inspiration
zer0cat
Posts: 6
Joined: Wed Aug 01, 2018 4:49 am

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?
User avatar
EP_X0FF
Global Moderator
Posts: 4886
Joined: Sun Mar 07, 2010 5:35 am
Location: Russian Federation
Contact:

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 :)
Ring0 - the source of inspiration
User avatar
Vrtule
Posts: 465
Joined: Sat Mar 13, 2010 9:14 pm
Location: Czech Republic
Contact:

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).
Post Reply