Запуск программы под правами юзера из NT сервиса
От: Disappear  
Дата: 30.11.03 01:26
Оценка:
Сразу скажу, что я перечитал все похожие топики, — не нужно на них ссылаться.

Такова проблема:
Нужно запустить любую программу из моего системного севиса, да так, чтобы программа запустилась не в виде системного процесса, а как процесс текущего пользователя. Того, кто в настоящий момент залогинен в системе.
В статье http://www.microsoft.com/msj/0200/logon/logon.aspx я этого найти не смог, либо чего не понял.

Сейчас процессы запускается через CreateProcess, также реализована интерактивность через OpenWindowStation и OpenDesktop, но всеравно все процессы запускаются, как системные, поэтому им недоступен пользовательский реестр и т.д...

Как запустить процесс под текущим юзером, если я не знаю его username and pass????
Re: Запуск программы под правами юзера из NT сервиса
От: Alex Fedotov США  
Дата: 30.11.03 03:02
Оценка: 19 (2)
Здравствуйте, Disappear, Вы писали:

D>Сразу скажу, что я перечитал все похожие топики, — не нужно на них ссылаться.


Видимо, все-таки, не все, потому что года полтора-два назад это уже обсуждалось. Что-то вроде "Запуск Outlook Express из службы".

D>Такова проблема:

D>Нужно запустить любую программу из моего системного севиса, да так, чтобы программа запустилась не в виде системного процесса, а как процесс текущего пользователя. Того, кто в настоящий момент залогинен в системе.
D>В статье http://www.microsoft.com/msj/0200/logon/logon.aspx я этого найти не смог, либо чего не понял.

D>Сейчас процессы запускается через CreateProcess, также реализована интерактивность через OpenWindowStation и OpenDesktop, но всеравно все процессы запускаются, как системные, поэтому им недоступен пользовательский реестр и т.д...


D>Как запустить процесс под текущим юзером, если я не знаю его username and pass????


Очень просто. Надо вызвать СreateProcessAsUser, указав в качестве токена токен интерактивного пользователя. Прежде чем приступить к перечислению способов получения этого токена, напомню, что в системе может быть более одного интерактивного пользователя. Поэтому прежде всего предлагаю подумать о том, как узнать, в контексте какого из интерактивных пользователей нужно запустить процесс. Именно эта часть задачи представляется мне наиболее интересной.

А токен можно получить несколькими способами:

1) [простой и надежный способ, работает на всех системах] Делается небольшая программа, которая регистируется в HKLM\Software\Microsoft\Windows\CurrentVersion\Run. При запуске программа соединяется со службой используя COM, RPC или named pipes. C одной стороны, это позволяет узнать службе о факте входа интерактивного пользователя в систему, а с другой — служба может имперсонировать соединение (CoImpersonateClient, RpcImpersonateClient, ImpersonateNamedPipeClient) и получить токен пользователя (OpenThreadToken). Tаким образом получается так называемый impersonation token, который нужно преобразовать в primary token с помощью DuplicateTokenEx, прежде чем можно будет вызвать CreateProcessAsUser.

2) [очень простой и в тоже время надежный способ, WinXP and later] WTSEnumerateSessions и WTSQueryUserToken. Таким образом получаются токены для всех интерактивных сессий в системе.

3) [вариация первого способа, Win2K and later] Написать Winlogon notification package, в котором отследить вход пользователя в систему и получить его токен.

4) [не очень надежный способ, к которому у меня персональная антипатия] Перечислить все процессы, найти процесс оболочки и получить токен этого процесса с помощью OpenProcessToken. Очевидная проблема в том, что процесса оболочки может и не существовать. Кроме того, надо аккуратно обрабатывать ситуации когда таких процессов несколько, так как они могут принадлежать как одной интерактивной сессии, так и разным.
-- Alex Fedotov
Re[2]: Запуск программы под правами юзера из NT сервиса
От: Disappear  
Дата: 30.11.03 14:35
Оценка:
Здравствуйте, Alex Fedotov, Вы писали:

AF>Здравствуйте, Disappear, Вы писали:


D>>Сразу скажу, что я перечитал все похожие топики, — не нужно на них ссылаться.


AF>Видимо, все-таки, не все, потому что года полтора-два назад это уже обсуждалось. Что-то вроде "Запуск Outlook Express из службы".


D>>Такова проблема:

D>>Нужно запустить любую программу из моего системного севиса, да так, чтобы программа запустилась не в виде системного процесса, а как процесс текущего пользователя. Того, кто в настоящий момент залогинен в системе.
D>>В статье http://www.microsoft.com/msj/0200/logon/logon.aspx я этого найти не смог, либо чего не понял.

D>>Сейчас процессы запускается через CreateProcess, также реализована интерактивность через OpenWindowStation и OpenDesktop, но всеравно все процессы запускаются, как системные, поэтому им недоступен пользовательский реестр и т.д...


D>>Как запустить процесс под текущим юзером, если я не знаю его username and pass????


AF>Очень просто. Надо вызвать СreateProcessAsUser, указав в качестве токена токен интерактивного пользователя. Прежде чем приступить к перечислению способов получения этого токена, напомню, что в системе может быть более одного интерактивного пользователя. Поэтому прежде всего предлагаю подумать о том, как узнать, в контексте какого из интерактивных пользователей нужно запустить процесс. Именно эта часть задачи представляется мне наиболее интересной.


AF>А токен можно получить несколькими способами:


AF>1) [простой и надежный способ, работает на всех системах] Делается небольшая программа, которая регистируется в HKLM\Software\Microsoft\Windows\CurrentVersion\Run. При запуске программа соединяется со службой используя COM, RPC или named pipes. C одной стороны, это позволяет узнать службе о факте входа интерактивного пользователя в систему, а с другой — служба может имперсонировать соединение (CoImpersonateClient, RpcImpersonateClient, ImpersonateNamedPipeClient) и получить токен пользователя (OpenThreadToken). Tаким образом получается так называемый impersonation token, который нужно преобразовать в primary token с помощью DuplicateTokenEx, прежде чем можно будет вызвать CreateProcessAsUser.


AF>2) [очень простой и в тоже время надежный способ, WinXP and later] WTSEnumerateSessions и WTSQueryUserToken. Таким образом получаются токены для всех интерактивных сессий в системе.


AF>3) [вариация первого способа, Win2K and later] Написать Winlogon notification package, в котором отследить вход пользователя в систему и получить его токен.


AF>4) [не очень надежный способ, к которому у меня персональная антипатия] Перечислить все процессы, найти процесс оболочки и получить токен этого процесса с помощью OpenProcessToken. Очевидная проблема в том, что процесса оболочки может и не существовать. Кроме того, надо аккуратно обрабатывать ситуации когда таких процессов несколько, так как они могут принадлежать как одной интерактивной сессии, так и разным.


У меня COM server;
Пробую первый метод:
в теле одного из методов интерфейса, я вызываю
CoImpersonateClient()

затем получаю
OpenThreadToken(GetCurrentThread(), ...)


все ок, но когда я хочу получить primary token с помощью функции DuplicateTokenEx ничего не выходит
DuplicateTokenEx(ImpToken, TOKEN_ALL_ACCESS, NULL, SecurityAnonymous, TokenPrimary, &PrimToken)

возвращяет FALSE
Может быть я неправильно указываю параметры??
Re[3]: Запуск программы под правами юзера из NT сервиса
От: Alex Fedotov США  
Дата: 30.11.03 16:09
Оценка:
Здравствуйте, Disappear, Вы писали:

D>У меня COM server;

D>Пробую первый метод:
D>в теле одного из методов интерфейса, я вызываю
D>
D>CoImpersonateClient()
D>

D>затем получаю
D>
D>OpenThreadToken(GetCurrentThread(), ...)
D>


Какие access rights были запрошены в OpenThreadToken?

D>все ок, но когда я хочу получить primary token с помощью функции DuplicateTokenEx ничего не выходит

D>
D>DuplicateTokenEx(ImpToken, TOKEN_ALL_ACCESS, NULL, SecurityAnonymous, TokenPrimary, &PrimToken)
D>

D>возвращяет FALSE
D>Может быть я неправильно указываю параметры??

А код ошибки какой?
-- Alex Fedotov
Re[4]: Запуск программы под правами юзера из NT сервиса
От: Disappear  
Дата: 30.11.03 16:36
Оценка:
Здравствуйте, Alex Fedotov, Вы писали:

AF>Какие access rights были запрошены в OpenThreadToken?


OpenThreadToken(CurThread, TOKEN_ALL_ACCESS, TRUE, &ImpToken)


AF>А код ошибки какой?


0x542 Either a required impersonation level was not provided, or the provided impersonation level is invalid

вот такой в целом код:
if (CoImpersonateClient() != S_OK) return E_FAIL;
HANDLE hImpToken, hPrimToken;
HANDLE hCurThread = GetCurrentThread();
if (OpenThreadToken(hCurThread, TOKEN_ALL_ACCESS, TRUE, &hImpToken) == TRUE)
{
    
    if (DuplicateTokenEx(hImpToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &hPrimToken) == TRUE) //возвращает FALSE :no: 
    {
        hPrimToken = (HANDLE)Token;
        if (CreateProcessAsUser(hPrimToken,
                                NULL,
                                (LPTSTR)(LPCTSTR)(sPath + szFileToStart),
                                NULL,
                                NULL,
                                FALSE,
                                NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
                                NULL,
                                sPath,
                                &StartInfo,
                                &ProcInfo) == TRUE)
        {
            m_ProcessHash.Add(ProcInfo);
            *pProcessID = ProcInfo.dwProcessId;
            hRet = S_OK;
        }
        CloseHandle(hPrimToken);
    } else
    {
        DWORD dwError = GetLastError();
        CString sMsg;
        sMsg.Format("0x%X: %s", dwError, GetErrorMessage(dwError));
        MessageBox(NULL, sMsg, NULL, MB_OK | MB_SERVICE_NOTIFICATION);                
    }
    CloseHandle(hImpToken);            
}
CoRevertToSelf();
Re[5]: Запуск программы под правами юзера из NT сервиса
От: Alex Fedotov США  
Дата: 30.11.03 21:04
Оценка:
Здравствуйте, Disappear, Вы писали:

D>Здравствуйте, Alex Fedotov, Вы писали:


AF>>Какие access rights были запрошены в OpenThreadToken?


D>
OpenThreadToken(CurThread, TOKEN_ALL_ACCESS, TRUE, &ImpToken)


AF>>А код ошибки какой?


D>0x542 Either a required impersonation level was not provided, or the provided impersonation level is invalid


D>вот такой в целом код:

D>
D>if (CoImpersonateClient() != S_OK) return E_FAIL;
D>HANDLE hImpToken, hPrimToken;
D>HANDLE hCurThread = GetCurrentThread();
D>if (OpenThreadToken(hCurThread, TOKEN_ALL_ACCESS, TRUE, &hImpToken) == TRUE)
D>{
    
D>    if (DuplicateTokenEx(hImpToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &hPrimToken) == TRUE) //возвращает FALSE :no: 
D>    {
D>        hPrimToken = (HANDLE)Token;
D>        if (CreateProcessAsUser(hPrimToken,
D>                                NULL,
D>                                (LPTSTR)(LPCTSTR)(sPath + szFileToStart),
D>                                NULL,
D>                                NULL,
D>                                FALSE,
D>                                NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
D>                                NULL,
D>                                sPath,
D>                                &StartInfo,
D>                                &ProcInfo) == TRUE)
D>        {
D>            m_ProcessHash.Add(ProcInfo);
D>            *pProcessID = ProcInfo.dwProcessId;
D>            hRet = S_OK;
D>        }
D>        CloseHandle(hPrimToken);
D>    } else
D>    {
D>        DWORD dwError = GetLastError();
D>        CString sMsg;
D>        sMsg.Format("0x%X: %s", dwError, GetErrorMessage(dwError));
D>        MessageBox(NULL, sMsg, NULL, MB_OK | MB_SERVICE_NOTIFICATION);                
D>    }
D>    CloseHandle(hImpToken);            
D>}
D>CoRevertToSelf();
D>


Интересно. Перенеси для начала CoRevertToSelf сразу после OpenThreadToken и замени SecurityImpersonation на SecurityAnonymous.
-- Alex Fedotov
Re[6]: Запуск программы под правами юзера из NT сервиса
От: Disappear  
Дата: 30.11.03 21:34
Оценка:
Здравствуйте, Alex Fedotov, Вы писали:

AF>Здравствуйте, Disappear, Вы писали:


D>>Здравствуйте, Alex Fedotov, Вы писали:


AF>>>Какие access rights были запрошены в OpenThreadToken?


D>>
OpenThreadToken(CurThread, TOKEN_ALL_ACCESS, TRUE, &ImpToken)


AF>>>А код ошибки какой?


D>>0x542 Either a required impersonation level was not provided, or the provided impersonation level is invalid


D>>вот такой в целом код:

D>>
D>>if (CoImpersonateClient() != S_OK) return E_FAIL;
D>>HANDLE hImpToken, hPrimToken;
D>>HANDLE hCurThread = GetCurrentThread();
D>>if (OpenThreadToken(hCurThread, TOKEN_ALL_ACCESS, TRUE, &hImpToken) == TRUE)
D>>{
    
D>>    if (DuplicateTokenEx(hImpToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &hPrimToken) == TRUE) //возвращает FALSE :no: 
D>>    {
D>>        hPrimToken = (HANDLE)Token;
D>>        if (CreateProcessAsUser(hPrimToken,
D>>                                NULL,
D>>                                (LPTSTR)(LPCTSTR)(sPath + szFileToStart),
D>>                                NULL,
D>>                                NULL,
D>>                                FALSE,
D>>                                NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
D>>                                NULL,
D>>                                sPath,
D>>                                &StartInfo,
D>>                                &ProcInfo) == TRUE)
D>>        {
D>>            m_ProcessHash.Add(ProcInfo);
D>>            *pProcessID = ProcInfo.dwProcessId;
D>>            hRet = S_OK;
D>>        }
D>>        CloseHandle(hPrimToken);
D>>    } else
D>>    {
D>>        DWORD dwError = GetLastError();
D>>        CString sMsg;
D>>        sMsg.Format("0x%X: %s", dwError, GetErrorMessage(dwError));
D>>        MessageBox(NULL, sMsg, NULL, MB_OK | MB_SERVICE_NOTIFICATION);                
D>>    }
D>>    CloseHandle(hImpToken);            
D>>}
D>>CoRevertToSelf();
D>>


AF>Интересно. Перенеси для начала CoRevertToSelf сразу после OpenThreadToken и замени SecurityImpersonation на SecurityAnonymous.


Тоже самое, только сообщение об ошибке теперь выдается по русски, видимо это какраз связано с CoRevertToSelf.
Я пробовал под WinXP и под Win2k, — толку нуль.
Блин, чтож такое, я не верю, что такую простую вещь, как запуск клиенского процесса из под сервиса нельзя реализовать.
Re[7]: А если передвать из клиенского процесса?
От: Disappear  
Дата: 01.12.03 11:33
Оценка:
Может быть стоит попробовать передавать токен из клиенского процесса системному??
Re[8]: А если передвать из клиенского процесса?
От: Alex Fedotov США  
Дата: 01.12.03 18:58
Оценка:
Здравствуйте, Disappear, Вы писали:

D>Может быть стоит попробовать передавать токен из клиенского процесса системному??


А может просто попросить клиентский процесс запустить нужную программу?
-- Alex Fedotov
Re[9]: Низя :(
От: Disappear  
Дата: 01.12.03 19:08
Оценка:
Здравствуйте, Alex Fedotov, Вы писали:

AF>Здравствуйте, Disappear, Вы писали:


D>>Может быть стоит попробовать передавать токен из клиенского процесса системному??


AF>А может просто попросить клиентский процесс запустить нужную программу?


Дело в том, что клиенский процесс — это DLL-ка, которая ставит глобальный хук, и соответственно постоянно выполняется в контексте разных процессов.
Ели она сама будет запускать процессы, это будет затормаживать другие программы. Если она запустит для этого отдельный поток, то неизвестно чем это обернется, так как DLL может влюбой момент быть выгружена из чужого процесса.
Re[10]: Интересные сводки, чудеса имперсонации
От: Disappear  
Дата: 01.12.03 23:04
Оценка:
Я составил список привелегий токена текущего процесса до ипмерсонации и поле, вот что получилось:

До вызова CoImpersonateClient

                                      enabled      on/off
-----------------------------------------------------------------
SeAssignPrimaryTokenPrivilege        enabled        off
SeAuditPrivilege                    enabled     on
SeBackupPrivilege                    enabled        off
SeChangeNotifyPrivilege                enabled        on
SeCreatePagefilePrivilege            enabled        on
SeCreatePermanentPrivilege            enabled     on
SeCreateTokenPrivilege                enabled     off
SeDebugPrivilege                    enabled        on
SeEnableDelegationPrivilege            disabled    off
SeImpersonatePrivilege                disabled    off
SeIncreaseBasePriorityPrivilege        enabled        on
SeIncreaseQuotaPrivilege            enabled        off
SeLoadDriverPrivilege                enabled        off
SeLockMemoryPrivilege                enabled     on
SeMachineAccountPrivilege            disabled    off
SeManageVolumePrivilege                enabled        off
SeProfileSingleProcessPrivilege        enabled        on
SeRemoteShutdownPrivilege            disabled    off
SeRestorePrivilege                    enabled        off
SeSecurityPrivilege                    enabled        off
SeShutdownPrivilege                    enabled        off
SeSyncAgentPrivilege                disabled    off
SeSystemEnvironmentPrivilege        enabled        off
SeSystemProfilePrivilege            disabled    off
SeSystemtimePrivilege                enabled        off
SeTakeOwnershipPrivilege            enabled        off
SeTcbPrivilege                        enabled     on
SeUndockPrivilege                    enabled        off
SeUnsolicitedInputPrivilege            disabled    off


После вызова CoImpersonateClient (функция возвращает S_OK)
                                      enabled      on/off
-----------------------------------------------------------------
SeAssignPrimaryTokenPrivilege        disabled    off
SeAuditPrivilege                    disabled    off
SeBackupPrivilege                    disabled    off
SeChangeNotifyPrivilege                disabled    off
SeCreatePagefilePrivilege            disabled    off
SeCreatePermanentPrivilege            disabled    off
SeCreateTokenPrivilege                disabled    off
SeDebugPrivilege                    disabled    off
SedisabledelegationPrivilege        disabled    off
SeImpersonatePrivilege                disabled    off
SeIncreaseBasePriorityPrivilege        disabled    off
SeIncreaseQuotaPrivilege            disabled    off
SeLoadDriverPrivilege                disabled    off
SeLockMemoryPrivilege                disabled    off
SeMachineAccountPrivilege            disabled    off
SeManageVolumePrivilege                disabled    off
SeProfileSingleProcessPrivilege        disabled    off
SeRemoteShutdownPrivilege            disabled    off
SeRestorePrivilege                    disabled    off
SeSecurityPrivilege                    disabled    off
SeShutdownPrivilege                    disabled    off
SeSyncAgentPrivilege                disabled    off
SeSystemEnvironmentPrivilege        disabled    off
SeSystemProfilePrivilege            disabled    off
SeSystemtimePrivilege                disabled    off
SeTakeOwnershipPrivilege            disabled    off
SeTcbPrivilege                        disabled    off
SeUndockPrivilege                    disabled    off
SeUnsolicitedInputPrivilege            disabled    off


В моем случае COM сервер — системный сервис, а клиент — процесс запущенный под _администратором_.
Теперь я запутался еще больше.
Не понимаю, как после имперсонации может получится токен, вообще без привилегий???
Re[11]: Интересные сводки, чудеса имперсонации
От: Alex Fedotov США  
Дата: 01.12.03 23:09
Оценка:
Здравствуйте, Disappear, Вы писали:

D>Я составил список привелегий токена текущего процесса до ипмерсонации и поле, вот что получилось:


У тебя CoInitializeSecurity в клиенте и сервере вызывается, и как?
-- Alex Fedotov
Re[11]: Интересные сводки, чудеса имперсонации
От: Alex Fedotov США  
Дата: 01.12.03 23:10
Оценка:
Здравствуйте, Disappear, Вы писали:

D>Я составил список привелегий токена текущего процесса до ипмерсонации и поле, вот что получилось:


И таки процесса или потока?
-- Alex Fedotov
Re[12]: Интересные сводки, чудеса имперсонации
От: Disappear  
Дата: 02.12.03 01:17
Оценка:
Здравствуйте, Alex Fedotov, Вы писали:

AF>У тебя CoInitializeSecurity в клиенте и сервере вызывается, и как?

CSecurityDescriptor sd;
sd.InitializeFromThreadToken();
hr = CoInitializeSecurity(sd, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);

— как AppWizzard прописал

AF>И таки процесса или потока?

Всетаки процесса, токен потока почему-то не удалось получить до вызова CoImpersonateClient
Re[13]: Интересные сводки, чудеса имперсонации
От: Alex Fedotov США  
Дата: 02.12.03 08:26
Оценка:
Здравствуйте, Disappear, Вы писали:

AF>>И таки процесса или потока?


D>Всетаки процесса, токен потока почему-то не удалось получить до вызова CoImpersonateClient


Так и должно быть. До вызова CoImpersonateClient у потока не было своего токена. Имперсонация в том и заключается, что берется токен клиента и назначается потоку. Интересно посмотреть на токен потока после имперсонации, в частности, его impersonation level.
-- Alex Fedotov
Re[14]: Интересные сводки, чудеса имперсонации
От: Disappear  
Дата: 03.12.03 00:47
Оценка:
Здравствуйте, Alex Fedotov, Вы писали:

AF>Здравствуйте, Disappear, Вы писали:


AF>>>И таки процесса или потока?


D>>Всетаки процесса, токен потока почему-то не удалось получить до вызова CoImpersonateClient


AF>Так и должно быть. До вызова CoImpersonateClient у потока не было своего токена. Имперсонация в том и заключается, что берется токен клиента и назначается потоку. Интересно посмотреть на токен потока после имперсонации, в частности, его impersonation level.


Я посмотрел через GetTokenInformation, уровень — SecurityIdentification
Что это значит?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.