2010-03-17 3 views
2

우리는 많은 시스템 관련 작업을 수행하는 DLL을 유지 관리합니다. 파일 시스템, 레지스트리 등을 순회하는 것입니다.이 DLL의 호출자는 가장을 사용하거나 사용하지 않을 수 있습니다. 가능한 모든 시나리오를보다 잘 지원하기 위해 나는 더 똑똑 해 지도록 수정하려고합니다. 파일을 삭제하는 예제를 사용하겠습니다. 현재 우리는 단지 DeleteFile()을 호출하고 이것이 실패하면 그 것이 끝납니다. 나는 다음을 생각해 냈다 :일시적으로 권한을 가장하여 권한을 부여 하시겠습니까?

BOOL TryReallyHardToDeleteFile(LPCTSTR lpFileName) 
{ 
    // 1. caller without privilege 
    BOOL bSuccess = DeleteFile(lpFileName); 
    DWORD dwError = GetLastError(); 
    if(!bSuccess && dwError == ERROR_ACCESS_DENIED) 
    { 
     // failed with access denied; try with privilege 
     DWORD dwOldRestorePrivilege = 0; 
     BOOL bHasRestorePrivilege = SetPrivilege(SE_RESTORE_NAME, SE_PRIVILEGE_ENABLED, &dwOldRestorePrivilege); 
     if(bHasRestorePrivilege) 
     { 
      // 2. caller with privilege 
      bSuccess = DeleteFile(lpFileName); 
      dwError = GetLastError(); 
      SetPrivilege(SE_RESTORE_NAME, dwOldRestorePrivilege, NULL); 
     } 
     if(!bSuccess && dwError == ERROR_ACCESS_DENIED) 
     { 
      // failed with access denied; if caller is impersonating then try as process 
      HANDLE hToken = NULL; 
      if(OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_IMPERSONATE, TRUE, &hToken)) 
      { 
       if(RevertToSelf()) 
       { 
        // 3. process without privilege 
        bSuccess = DeleteFile(lpFileName); 
        dwError = GetLastError(); 
        if(!bSuccess && dwError == ERROR_ACCESS_DENIED) 
        { 
         // failed with access denied; try with privilege 
         bHasRestorePrivilege = SetPrivilege(SE_RESTORE_NAME, SE_PRIVILEGE_ENABLED, &dwOldRestorePrivilege); 
         if(bHasRestorePrivilege) 
         { 
          // 4. process with privilege 
          bSuccess = DeleteFile(lpFileName); 
          dwError = GetLastError(); 
          SetPrivilege(SE_RESTORE_NAME, dwOldRestorePrivilege, NULL); 
         } 
        } 
        SetThreadToken(NULL, hToken); 
       } 
       CloseHandle(hToken); 
       hToken = NULL; 
      } 
     } 
    } 
    if(!bSuccess) 
    { 
     SetLastError(dwError); 
    } 
    return bSuccess; 
} 

그래서 먼저 호출자로 시도한다. 액세스가 거부되어 실패하면 일시적으로 호출자의 토큰에서 권한을 활성화하고 다시 시도합니다. 액세스가 거부되어 호출자가 가장하는 경우 실패하고 일시적으로 거부하고 다시 시도합니다. 액세스가 거부되어 실패하면 일시적으로 프로세스 토큰에서 특권을 사용 가능하게하고 다시 시도합니다. 이것은 거의 모든 상황을 처리해야한다고 생각하지만, 이것을 달성하기위한 더 좋은 방법이 있는지 궁금합니다. 이 메소드를 사용할 가능성이있는 작업이 많이 있습니다 (예 : 보안 개체에 액세스하는 모든 작업).

+0

바로 마지막 옵션으로 이동하지 않겠습니까? 예외 처리가 필요하지 않습니다. 올바르게 설명을 읽으면 제대로 작동합니다. – ChrisF

+0

프로세스가 LocalSystem (즉 서비스)으로 실행되고 네트워크 위치의 파일을 읽어야하는 경우 (즉, 가장 된 사용자 계정 만 파일에 액세스 할 수 있음) 처리하지 못합니다. – Luke

+0

@Chris : 그것은 또한 최소한 특권의 사고 방식에 반대합니다. 그 행동을 위해 필요한만큼의 권한 만 있으면됩니다. 그것은 일을하는 것이 더 힘든 방법이지만,보다 이상적인 방법입니다. – Ioan

답변

0

이렇게 할 수있는 유일한 방법은 서비스로 실행하고 서비스 내에서 사용자를 가장하는 것입니다. 서비스 에 모든 서비스 계정이 기본적으로 부여되는 가장 인증 권한을 부여 받아야합니다. 호출자를 가장 할 때 위임에 가장해야하므로 시스템을 쉽게 벗어날 수 있습니다.

+0

예, 이것이 우리 서비스의 구조입니다. 그러나 타사에서 DLL을 사용하는 방식을 제어 할 수 없으므로이를 일반적인 방식으로 처리하려고합니다. 내 테스트에서 지금까지 잘 작동하는 것처럼 보입니다. 비록 가장 된 사용자가 표준 사용자 인 경우 토큰에 유용한 권한이 없어도 낭비되는 단계입니다. 우리가 가장해야하는 유일한 이유는 네트워크 경로에 액세스하는 것입니다. 로컬 경로에 액세스하려고 시도하면서 네트워크 경로에 액세스하려고 시도하는 동안 내가 가장 할 수없는 어쩌면. – Luke

0

이 모든 것이 DLL에 대해 정말 재미있을 것 같습니다. DLL이 아닌 서비스의 작업처럼 들리거나 사용자 계정이 권한있는 계정으로 들어오는 데이터를 제거하도록 허용하려는 경우 해당 개체에 대해 ACL을 설정하지 않는 것이 좋습니다. 작업을 삭제 하시겠습니까?

그렇게 말하면 실제로 무엇을하려고합니까? 사용자 계정은 일반적으로 관리자 계정으로 입력 된 데이터를 제거 할 수 없습니다.

+0

나는 당신이 말한 것에 대부분 동의하지만, 그건 내 통제를 벗어났다. 이 DLL은 바이러스 백신과 비슷한 개념의 검사 구성 요소입니다. 우리 제품에서는 LocalSystem 컨텍스트에서 서비스로 실행됩니다. 그러나 사용자는 스캔 할 위치를 지정할 수 있습니다. 여기에는 액세스에 가장을 요구하는 네트워크 경로가 포함될 수 있습니다. 따라서 시작시 사용자를 가장하여 검색을 실행합니다. 사용자가 시스템 경로 (액세스 권한이없는 경우도 있음)를 검색하려는 경우 액세스를 일시적으로 거부해야합니다. DeleteFile()은 한 가지 예일뿐입니다. 대신 FindFirstFile()을 사용할 수있었습니다. – Luke

1

백업 및 복원 권한을 함께 사용하면 모든 파일에 대한 전체 액세스 권한을 얻을 수 있습니다. 이것들은 LocalSystem에서 사용할 수 있습니다. 이것을 사용하려면 FILE_FLAG_BACKUP_SEMANTICS로 파일을 열어야합니다. 일부 Win32 API는이 기능과 함께 사용하도록 설계되지 않았으므로 플래그를 커널에 전달하지 않습니다. 일부 경우에는 CreateFile을 사용하여 디렉토리를 열 수 있습니다. (커널의 경우, 디렉토리는 단지 또 다른 종류의 파일입니다).

정말로 모든 것을 액세스 할 수 있어야하는 경우 이러한 권한을 사용하도록 설정하고 호출자의 보안에 관계없이 성공해야하는 검색 작업을 수행해야합니다.

하나의 중요한 문제는 파일을 잠궈 놓거나 열 수 있지만 액세스 권한을 공유하지 않는 것입니다. 사용자 모드에서이 문제를 해결할 방법이 없습니다 (자원을 소유하고있는 프로세스를 죽이지 않고, 아마도 과도 함으로 죽일 필요는 없습니다). 이것이 내가 아는 주류 스캐너가 커널 모드 파일 시스템 필터 드라이버로이 기능을 구현 한 이유입니다.

또한 감사에 대해 생각해보십시오. LocalSystem 또는 호출 프로세스와 관련된 사용자에 대해 감사 항목을 표시 하시겠습니까?

+0

문제는 네트워크 위치에 대한 액세스가 필요하다는 것입니다. LocalSystem에는 해당 액세스 권한이 없습니다. 가장은 또한 사용자의 암호화 된 파일에 대한 액세스 권한을 부여합니다.이 파일은 LocalSystem도 액세스 할 수 없습니다 (적어도 해독 된 내용은 제외). – Luke

관련 문제