Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일

특정 EXE 파일의 실행을 Internet Explorer처럼 "Protected Mode"로 실행하는 방법

예전에, MIC(Mandatory Integrity Control)에 대해서 소개해 드렸는데요.

보호 모드와 필수 무결성 제어(신뢰도 등급)(MIC: Mandatory Integrity Control)
; https://www.sysnet.pe.kr/2/0/433

이에 따르면, Internet Explorer가 "보호 모드"로 실행된다는 것은 곧, MIC 등급이 "Low"에 해당하는 프로세스로 실행된다는 것과 같은 말입니다.

보통 여러분들이 Vista/7에서 로그인 한 후 실행하는 대부분의 프로그램들이 "Medium" 등급에서 동작됩니다. 일반적으로 "Medium" 등급은 '관리자 권한'으로 실행되지 않는 프로세스들에 부여되는데, "Internet Explorer"는 웹 상에서 가져오는 모든 데이터들에 대해서 기본적으로 신뢰를 하지 않기 때문에 자신의 프로세스 자체를 "Low" 레벨로 낮춰서 실행해 줌으로써 보안성을 높인 것입니다.

일단, 마이크로소프트가 만든 프로그램은 그렇다 치고... 그럼 우리가 만드는 프로그램은 어떻게 해야 할까요?

예를 들어, 여러분들이 '메일 클라이언트'를 만들었다고 가정해 보겠습니다. 거기에는 온갖 스팸 메일과 출처를 알 수 없는 exe 파일들이 첨부되어 올 텐데... 이에 대한 보안을 어떻게 높일 수 있을까요?

우선, 해당 '메일 클라이언트'를 IE처럼 "Low" 레벨로 실행하는 것을 예로 들 수 있겠지요. 하지만... 해보신 분은 아시겠지만 Low 레벨로는 할 수 있는 일이 거의 없습니다. (순수 UI 용이나, 계산 정도만 가능하다고 봐야 할 것입니다.)

자... 그럼 이건 어떨까요? '메일 클라이언트'는 그냥 그대로 실행하고 메일로 첨부된 파일들을 로컬에 저장할 때 모두 "Low" 등급이라는 딱지를 붙여두는 것입니다. 그렇게 되면 사용자가 실수로 그 첨부 파일을 실행한다고 해도 시스템에 위해를 가하는 것이 불가능합니다.

이번 글에서는 이에 대해 알아보겠습니다.




우선, 해당 파일에 대해 "Low" MIC 권한을 부여할 수 있는 코드가 필요한데, 이는 C/C++ 코드로 이미 다음과 같이 공개되어 있습니다.

Understanding and Working in Protected Mode Internet Explorer
; https://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/

#include <sddl.h>
#include <AccCtrl.h>
#include <Aclapi.h>

void SetLowLabelToFile()
{
  // The LABEL_SECURITY_INFORMATION SDDL SACL to be set for low integrity 
  #define LOW_INTEGRITY_SDDL_SACL_W L"S:(ML;;NW;;;LW)"
  DWORD dwErr = ERROR_SUCCESS;
  PSECURITY_DESCRIPTOR pSD = NULL;    

  PACL pSacl = NULL; // not allocated
  BOOL fSaclPresent = FALSE;
  BOOL fSaclDefaulted = FALSE;
  LPCWSTR pwszFileName = L"Sample.txt";

  if (ConvertStringSecurityDescriptorToSecurityDescriptorW(
         LOW_INTEGRITY_SDDL_SACL_W, SDDL_REVISION_1, &pSD, NULL)) 
  {
    if (GetSecurityDescriptorSacl(pSD, &fSaclPresent, &pSacl, 
         &fSaclDefaulted))
    {
      // Note that psidOwner, psidGroup, and pDacl are 
      // all NULL and set the new LABEL_SECURITY_INFORMATION
      dwErr = SetNamedSecurityInfoW((LPWSTR) pwszFileName, 
                 SE_FILE_OBJECT, LABEL_SECURITY_INFORMATION, 
                 NULL, NULL, NULL, pSacl);
    }
    LocalFree(pSD);
  }
}

그런데, 실제로 위의 코드를 Windows 7에서 실행시켜 보면 SetNamedSecurityInfoW 함수 실행에서 오류가 발생합니다. dwErr == 5라고 하니 "Access is denied"일 텐데... 가만 보니, 위의 기능을 하는 프로세스를 "Run as administrator"로 실행시키면 정상적으로 동작을 했습니다.

^^; 아니... 보안을 높이려고 했는데, 오히려 우리가 만들 프로그램 자체의 실행 권한을 높여야 하다니 말이 안됩니다.

그래서, 조금 더 살펴보았는데 해당 파일의 "Users" 접근 권한이 "Full Control"을 가지고 있으면 정상적으로 동작한다는 것을 알았습니다.

mic_process_start_1.png

산 넘어 산이군요. ^^; "Low" 등급을 지정하는 코드는 간단한데 이를 위해 파일 권한에서 "Users"의 DACL 권한을 조정해야 하는 코드를 넣어야 합니다.

하지만 ^^ 너무 걱정하지 마십시오. 다행히 윈도우의 기본 명령행에서 ACL 권한을 조정하는 유틸리티를 제공하고 있으니 이를 이용해서 처리를 해주면 됩니다. 바로 cacls.exe가 그것입니다.

==== USERS 그룹에 "Full Control" 부여
D:\Debug>cacls test.exe /E /P USERS:F
processed file: D:\Debug\test.exe

==== USERS 그룹에 다시 "Read" 권한만 부여
D:\Debug>cacls test.exe /E /P USERS:R
processed file: D:\Debug\test.exe

자... 그럼 테스트를 해볼까요? 간단하게 C#으로 만들어 보았습니다.
(물론, 소스 코드는 첨부해 두었으니 참고하십시오. ^^)

mic_process_start_2.png

위의 이미지에서 "Download" 버튼을 누르면 지정된 "File URL"로부터 파일을 다운로드 받습니다. 받자마자 다음과 같이 Low 등급을 부여하는 코드를 실행해 줍니다.

Uri uri = new Uri(txtUri.Text);

string fileName = Path.GetFileName(uri.LocalPath);
WebClient wc = new WebClient();

Directory.CreateDirectory(txtSaveFolder.Text);

Directory.Exists(txtSaveFolder.Text);

filePath = Path.Combine(txtSaveFolder.Text, fileName);

// URL로부터 파일 다운로드
wc.DownloadFile(uri, filePath);

// Low 등급 부여
SetAccessControl(filePath, "F");
SetLowLevelSecurity(filePath);
SetAccessControl(filePath, "R");

위의 예제에서 다운로드 받도록 한 ConsoleApplication1.exe 프로그램은 내부에 다음과 같은 코드만을 포함하고 있습니다.

class Program
{
    static void Main(string[] args)
    {
        File.WriteAllText(@"C:\temp\test.txt", "test");
        Console.WriteLine("TEST, press any key to exit...");
        Console.ReadLine();
    }
}

보시는 것처럼, "C:\temp\test.txt" 파일을 생성하는데 보통의 과정을 통해서 이 파일을 다운로드 받았다면 정상적으로 실행이 될텐데요. 자, 그럼 프로그램에서 "Run" 버튼을 눌러서 확인을 해보도록 하겠습니다.

우선, Windows 7은 해당 프로그램을 실행하려고 하면 다음과 같이 한번 더 묻게 됩니다.

mic_process_start_3.png

저 창이 떠야 확실하게 "Low" 등급으로 MIC 설정이 된 것입니다. 이 상태에서 사용자가 계속해서 Run 버튼을 누르면 어떻게 될까요?

Low 등급의 프로세스는 "C:\temp" 폴더에서조차 파일을 생성할 수 있는 권한이 없으므로 다음과 같은 예외를 발생하게 됩니다.

mic_process_start_4.png

어떠세요? 마음에 드시나요? ^^

이처럼, 조금만 신경을 더 써준다면... 여러분들의 프로그램을 안전하게 만드실 수 있습니다.

참고로, Low 등급으로 실행되는 프로세스 구조는 Internet Explorer뿐만 아니라 Google Chrome도 채택하고 있습니다. (아쉽게도 Firefox는 여전히 Medium 등급으로 실행됩니다.)

mic_process_start_5.png

마지막으로, 여러분들이 웹 상에서 혹시 exe 파일을 다운로드 해야 할 때 안전하게 실행할 수 있도록 위의 기능을 한 ClickOnce 프로그램을 작성해 두었으니 생각날 때 활용하시기 바랍니다. ^^

SafetyDownloader
; https://www.sysnet.pe.kr/temp/app/safetydownloader/SafetyDownloader.application




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 1/9/2023]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2016-11-18 01시29분
특정 폴더의 Integrity 수준을 Low로 설정하는 방법

icacls "...path..." /setintegritylevel(oi)(ci) low /t
정성태

1  2  3  4  5  6  7  8  [9]  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13413정성태9/14/20233775닷넷: 2143. C# - 시스템 Time Zone 변경 시 이벤트 알림을 받는 방법
13412정성태9/14/20237083닷넷: 2142. C# 12 - 인라인 배열(Inline Arrays) [1]
13411정성태9/12/20233573Windows: 252. 권한 상승 전/후 따로 관리되는 공유 네트워크 드라이브 정보
13410정성태9/11/20235111닷넷: 2141. C# 12 - Interceptor (컴파일 시에 메서드 호출 재작성) [1]
13409정성태9/8/20233937닷넷: 2140. C# - Win32 API를 이용한 모니터 전원 끄기
13408정성태9/5/20233916Windows: 251. 임의로 만든 EXE 파일을 포함한 ZIP 파일의 압축을 해제할 때 Windows Defender에 의해 삭제되는 경우
13407정성태9/4/20233631닷넷: 2139. C# - ParallelEnumerable을 이용한 IEnumerable에 대한 병렬 처리
13406정성태9/4/20233617VS.NET IDE: 186. Visual Studio Community 버전의 라이선스
13405정성태9/3/20234024닷넷: 2138. C# - async 메서드 호출 원칙
13404정성태8/29/20233599오류 유형: 876. Windows - 키보드의 등호(=, Equals sign) 키가 눌리지 않는 경우
13403정성태8/21/20233401오류 유형: 875. The following signatures couldn't be verified because the public key is not available: NO_PUBKEY EB3E94ADBE1229CF
13402정성태8/20/20233503닷넷: 2137. ILSpy의 nuget 라이브러리 버전 - ICSharpCode.Decompiler
13401정성태8/19/20233754닷넷: 2136. .NET 5+ 환경에서 P/Invoke의 성능을 높이기 위한 SuppressGCTransition 특성 [1]
13400정성태8/10/20233592오류 유형: 874. 파이썬 - pymssql을 윈도우 환경에서 설치 불가
13399정성태8/9/20233514닷넷: 2135. C# - 지역 변수로 이해하는 메서드 매개변수의 값/참조 전달
13398정성태8/3/20234363스크립트: 55. 파이썬 - pyodbc를 이용한 SQL Server 연결 사용법
13397정성태7/23/20233850닷넷: 2134. C# - 문자열 연결 시 string.Create를 이용한 GC 할당 최소화
13396정성태7/22/20233627스크립트: 54. 파이썬 pystack 소개 - 메모리 덤프로부터 콜 스택 열거
13395정성태7/20/20233500개발 환경 구성: 685. 로컬에서 개발 중인 ASP.NET Core/5+ 웹 사이트에 대해 localhost 이외의 호스트 이름으로 접근하는 방법
13394정성태7/16/20233475오류 유형: 873. Oracle.ManagedDataAccess.Client - 쿼리 수행 시 System.InvalidOperationException
13393정성태7/16/20233653닷넷: 2133. C# - Oracle 데이터베이스의 Sleep 쿼리 실행하는 방법
13392정성태7/16/20233547오류 유형: 872. Oracle - ORA-01031: insufficient privileges
13391정성태7/14/20233565닷넷: 2132. C# - sealed 클래스의 메서드를 callback 호출했을 때 인라인 처리가 될까요?
13390정성태7/12/20233504스크립트: 53. 파이썬 - localhost 호출 시의 hang 현상
13389정성태7/5/20233551개발 환경 구성: 684. IIS Express로 호스팅하는 웹을 WSL 환경에서 접근하는 방법
13388정성태7/3/20233693오류 유형: 871. 윈도우 탐색기에서 열리지 않는 zip 파일 - The Compressed (zipped) Folder '[...].zip' is invalid. [1]파일 다운로드1
1  2  3  4  5  6  7  8  [9]  10  11  12  13  14  15  ...