모두의 dream
윈도우 권한 (Windows privilege) 본문
공부를 하며 정리한 내용으로 잘못된 내용이 있을 수 있습니다.
이번에 우크라이나·러시아 전쟁에서 사용된 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)
'분야 > Reversing' 카테고리의 다른 글
프로세스와 스레드, 핸들(Windows)과 커널 (0) | 2022.04.02 |
---|---|
DLL Injection & Ejection (0) | 2022.03.21 |