모두의 dream

윈도우 권한 (Windows privilege) 본문

분야/Reversing

윈도우 권한 (Windows privilege)

오리꽥이로 2022. 4. 1. 14:21
Contents 접기

공부를 하며 정리한 내용으로 잘못된 내용이 있을 수 있습니다.

 

이번에 우크라이나·러시아 전쟁에서 사용된 HermeticWiper 악성코드를 분석하다가 윈도우 권한과 관련된 코드가 있어서 공부겸 정리해봤다.

 

아래 코드는 윈도우 전원을 종료 시키는 코드다.

#include<stdio.h>
#include<windows.h>

char* GetLastErrorAsString()
{
	DWORD dwLastError = GetLastError();
	if (0 == dwLastError)
		return NULL;

	char* szMessageBuffer = NULL;
	size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
		| FORMAT_MESSAGE_FROM_SYSTEM
		| FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL, dwLastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		(LPSTR)&szMessageBuffer, 0, NULL);

	// NOTE : szMessageBuffer must be freed after use
	return szMessageBuffer;
}

void PrintLastErrorString()
{
	LPSTR lpMessageBuffer = NULL;
	lpMessageBuffer = GetLastErrorAsString();
	if (NULL == lpMessageBuffer)
		return;

	printf("%s", lpMessageBuffer);
	LocalFree(lpMessageBuffer);
}

int main(void)
{
	if (!InitiateSystemShutdownExA(NULL, NULL, 5, TRUE, FALSE, 0))
	{
		printf("FALSE\n");
		PrintLastErrorString();
	}
	else {
		printf("5 second\n");
	}

	return 0;
}

PrintLastErrorString() 함수는 에러가 발생한 이유를 문자열로 보여주는 코드이며, 윈도우 전원 종료에 성공하면 5 second 문자열 출력과 함께 5초 뒤에 윈도우가 종료되고, 실패하면 FALSE 문자열 출력과 함께 실패한 이유가 출력된다.

 

실행 결과

위 코드로 만들어진 파일을 실행해본 결과 FALSE와 함께 액세스가 거부되었다고 출력되었다.
(관리자 권한으로 해봐도 결과는 같다.)

 

액세스가 거부된 이유는 이 프로그램에게는 윈도우를 종료할 권한이 없기 때문이다.
(윈도우 종료를 수행하는 주체인 윈도우가 이 프로그램의 종료 요청을 거부함)

 

그럼 내용이 추가된 아래 코드를 보자.

#include<stdio.h>
#include<windows.h>

char* GetLastErrorAsString()
{
	DWORD dwLastError = GetLastError();
	if (0 == dwLastError)
		return NULL;

	char* szMessageBuffer = NULL;
	size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
		| FORMAT_MESSAGE_FROM_SYSTEM
		| FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL, dwLastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		(LPSTR)&szMessageBuffer, 0, NULL);

	// NOTE : szMessageBuffer must be freed after use
	return szMessageBuffer;
}

void PrintLastErrorString()
{
	LPSTR lpMessageBuffer = NULL;
	lpMessageBuffer = GetLastErrorAsString();
	if (NULL == lpMessageBuffer)
		return;

	printf("%s", lpMessageBuffer);
	LocalFree(lpMessageBuffer);
}

int main(void)
{
	HANDLE hToken;
	TOKEN_PRIVILEGES tkp;

	// Get a token for this process. 

	if (!OpenProcessToken(GetCurrentProcess(),
		TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
		return(FALSE);

	// Get the LUID for the shutdown privilege. 

	LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
		&tkp.Privileges[0].Luid);

	tkp.PrivilegeCount = 1;  // one privilege to set    
	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

	// Get the shutdown privilege for this process. 

	AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
		(PTOKEN_PRIVILEGES)NULL, 0);

	if (GetLastError() != ERROR_SUCCESS)
		return FALSE;

	// Shut down the system and force all applications to close. 

	if (!InitiateSystemShutdownExA(NULL, NULL, 5, TRUE, FALSE, 0))
	{
		printf("FALSE\n");
		PrintLastErrorString();
	}
	else {
		printf("5초 뒤 종료됩니다.\n");
	}

	return 0;
}

 

위 코드로 만들어진 파일을 실행해본 결과 5 second 문자열이 출력되고, 5초 뒤에 윈도우가 종료된다.
(관리자 권한으로 실행하지 않았다.)

 

두 코드의 차이는 윈도우를 종료할 수 있는 권한이 있는가, 없는가의 차이다.

즉, 관리자 권한이 있고 없고의 문제가 아니다.

 

- 윈도우의 권한 -

1. ACL (Access Control List)
- 파일을 삭제하는 코드가 있을 때, 파일은 "작업할 대상"이다.
- 그 작업할 대상의 접근 권한을 관리하는 것이 ACL이다.
(각각의 사용자들이 파일에 접근할 수 있는 권한들이 설정되어 있음)

2. Access Token
- 내 프로그램은 작업을 지시하는 "지시자". (윈도우를 종료시키는 프로그램)

- Access Token은 그 "지시자"의 신원이다.

- Access Token 에는 Privilege(권한) 목록을 가지고 있으며, 필요에 따라 목록에 있는 Privilege(권한)을 활성화 또는 비활성화 할 수 있다.

3. Privilege
- Access Token -> 신원, Privilege -> 신원에 부여된 권한

- 컴퓨터 종료 권한 등등..

 

윈도우 종료까지의 과정

OpenProcessToken(): 현재 프로세스에 Access Token이 있는지 확인하고 가져옴. (신원 확인)

LookupPrivilegeValue(): Access Token이 있다면 그 안에 내가 상승시키고자 하는 권한이 있는지 확인한다.

AdjustTokenPrivileges(): 내가 상승시키고자 하는 권한을 찾았다면 그 권한을 활성화 시킨다.

 

(이 과정에서 선행되야 할 내용은 핸들값을 가져오는 것이다.)

참고: 프로세스와 스레드, 핸들(Windows)과 커널 (tistory.com)

 

위 사진에서 상승시키고자 하는 권한은 윈도우 종료 권한인 "SE_SHUTDOWN_NAME" 이다.

 

위 내용을 통해 관리자 권한으로 실행해도 실행이 안 된 이유를 알 수 있었다.

관리자 권한의 Access Token에도 수많은 privilege(권한)들이 존재하고, 그 권한을 사용하려면 활성화를 시킨 후에 사용해야 된다는 사실을 알 수 있다.

단순히 관리자 권한이라고 실행시킬 수 있는 개념이 아니다.

 

참고한 내용

Windows 권한 이해하기 : 네이버 블로그 (naver.com)

실행권한 이해하기 : 네이버 블로그 (naver.com)

GetLastError 문자열로 출력하기 (tistory.com)

시스템을 종료 하는 방법 - Win32 apps | Microsoft Docs

'분야 > Reversing' 카테고리의 다른 글

프로세스와 스레드, 핸들(Windows)과 커널  (0) 2022.04.02
DLL Injection & Ejection  (0) 2022.03.21
Comments