Pregunta

Estoy usando un servicio de fiesta thrid de Windows que se encarga de algunas tareas de automatización mediante scripts y ejecutables que se ejecutan utilizando CreateProcessAsUser (). Estoy corriendo en problemas en Windows Server 2008 debido a la UAC y la forma en que la elevación de LUA se maneja a través de las API.

El servicio se ejecuta como LocalSystem y no tiene "interactuar con el Escritorio" habilitado. Los procesos se ejecutan como usuarios en el grupo de administradores, pero no la cuenta de administrador (que está exenta de muchas restricciones UAC). Todos los ajustes por defecto UAC en su lugar.

Puedo pasar comandos arbitrarios o código de PowerShell para el servicio, pero me parece que no puede 'salir' del proceso no elevados, no interactivo que consigue puesto en marcha por el servicio.

El quid de la cuestión parece ser que la única opción API (público) para el inicio de un proceso de elevada es ShellExecute () con el verbo 'las runas', pero por lo que puedo decir que no se puede llamar desde una servicio no interactivo o se obtienen errores como "Esta operación requiere una estación de ventana interactiva".

La única solución que he encontrado es mencionado aquí: http://www.eggheadcafe.com/ software / Red PEA / 29620442 / cómo-a-uso adecuado-sendinp.aspx

  

En Vista, el funcionario documentado camino   para elevar un proceso sólo es el uso de la   shell API ShellExecute (Ex) (no   CreateProcess o CreateProcessAsUser).   Por lo que su aplicación debe llamar   ShellExecute (Ex) para lanzar un ayudante   elevada para llamar SendInput.   Además, debido a la sesión 0   aislamiento, un servicio sólo puede utilizar   CreateProcessAsUser o   CreateProcessWithLogonW (no se puede utilizar   ShellExecute (Ex)) para especificar el   escritorio interactivo.

     

.. Creo que no hay una forma directa de   desovar un proceso de elevada desde una   servicio de Windows. Sólo podemos utilizar primero   CreateProcessAsUser o   CreateProcessWithLogonW a generar una   no elevada proceso en el usuario   reunión (interactive desktop). Luego, en   el proceso no elevada, puede utilizar   ShellExecute (Ex) para desovar un elevado   proceso para la verdadera tarea.

Para hacer esto desde el código .net / PowerShell, parece que tendría que hacer algo elaborado P / Invoke cosas para llamar CreateProcessAsUser o CreateProcessWithLogonW ya que el .Net System.Diagnostics.ProcessStartInfo no tiene un equivalente de lpDesktop que podría fijar a "winsta0 \ default". Y no me queda claro si el sistema local incluso tiene los derechos para llamar CreateProcessAsUser o CreateProcessWithLogonW.

I también vieron http: //blogs.msdn.com/alejacma/archive/2007/12/20/how-to-call-createprocesswithlogonw-createprocessasuser-in-net.aspx y Process.Start con diferentes credenciales con UAC en

Sobre la base de todo esto, estoy llegando a la conclusión de que no hay manera fácil de hacer esto. ¿Me estoy perdiendo de algo? Esto realmente no parece como tiene que ser tan difícil. Se siente como UAC fue nunca diseñada para manejar los casos de uso no interactivos.

Y si alguna gente de Microsoft acaban de leer esto, me di cuenta de que la forma ShellExecute maneja internamente elevación es llamando a Servicio de información de aplicaciones (AIS). ¿Por qué no es la misma llamada a AIS disponibles a través de algún Win32 o .NET API? http://msdn.microsoft.com/en-us/library/bb756945. aspx

Lo siento que corrió un poco largo. Gracias por cualquier idea.

¿Fue útil?

Solución

La forma "oficial" para romper el aislamiento sesión de cero es utilizar una combinación de la API de servicios de terminal y CreateProcessAsUser() para poner en marcha un proceso dentro de la sesión de un usuario. En mi antiguo trabajo, nos hicieron eso, ya que necesitábamos para mostrar un cuadro de diálogo para el usuario de un servicio antes de instalar una actualización descargada Por lo tanto, sé que funciona, en WinXP, Win2K3, Vista y Win7 al menos, pero no espere que Win 2K8 sería demasiado diferente. Básicamente, el proceso es el siguiente:

  1. Llamada WTSGetActiveConsoleSessionId() para obtener la sesión de consola activa Identificación (muy importante, ya que la sesión interactiva es no siempre la sesión 1, incluso en los sistemas cliente). Esta API también devolverá un -1 si no hay ningún usuario activo registrado en la sesión interactiva (es decir, conectado localmente a la máquina física, en lugar de utilizar RDP).
  2. Pasar el identificador de sesión de la llamada a la API anterior a WTSQueryUserToken() para obtener un token abierto que reprents el usuario ha iniciado sesión en la consola.
  3. DuplicateTokenEx() para convertir el testigo de suplantación (de WTSQueryUserToken) Llamar a un identificador primario.
  4. Llamada CreateEnvironmentBlock() para crear un nuevo entorno para el proceso (opcional, pero si no lo hace, el proceso no tendrá uno).
  5. Pasar el testigo primario desde el paso # 3 en una llamada a CreateProccessAsUser(), junto con la línea de comandos para el ejecutable. Si ha creado un bloque de entorno desde el paso # 4, se debe pasar la bandera CREATE_UNICODE_ENVIRONMENT así (siempre). Esto puede parecer una tontería, pero la API falla horriblemente si no lo hace (con ERROR_INVALID_PARAMTER).
  6. Si ha creado un bloque de entorno, entonces usted necesita llamar DestroyEnvironmentBlock, de lo contrario se generará una pérdida de memoria. El proceso se da una copia separada del bloque de entorno cuando se pone en marcha, por lo que sólo están destruyendo los datos locales.

Y listo! Ventanas hace un poco de magia interna, y se ve el inicio de la aplicación. Sin embargo, aunque esto pondrá en marcha y el proceso interactivo de un servicio, no estoy seguro de si va a pasar por alto el UAC (pero no me cita en eso). En otras palabras, no puede lanzar como un proceso elevada a menos que el registro o manifiesto interno dice a hacerlo, e incluso entonces, se le podría aún así obtener una solicitud de UAC. Si el testigo se obtiene a partir del paso # 3 es un token restringido, es posible que pueda utilizar AdjustTokenPrivileges() para restaurar el token elevado (completa), pero no me cita en eso, tampoco. Sin embargo, como se indica en la documentación de MSDN, tenga en cuenta que no es posible "añadir" privilegios en una señal de que no tuviera ya ellos (por ejemplo, no se puede convertir un token de usuario restringido a un administrador mediante el uso de AdjustTokenPrivileges; el subyacente el usuario tendría que ser un administrador para empezar).

Es técnicamente posible hacer todo esto desde WIN2K adelante. Sin embargo, es realmente sólo es factible comenzar con WinXP, ya que carece de la Win2K WTSGetActiveConsoleSessionId() y WTSQueryUserToken() de API (junto con WTSEnumerateProcesses() para Win2K Pro). Puede codificar 0 como el identificador de sesión (ya que es siempre el caso en Win2K), y supongo que podría ser capaz de obtener el token de usuario mediante la enumeración de los procesos en ejecución y la duplicación de una de sus fichas (que debe ser uno que tiene la SID interactivo presente). En cualquier caso, la CreateProcessAsUser() se comportará de la misma manera cuando se pasa un token de usuario interactivo, incluso si no se selecciona "interactuar con el escritorio" de los ajustes de servicio. También es más seguro que el lanzamiento directamente desde el servicio de todos modos, ya que el proceso no heredará el token de acceso LocalSystem piadosa.

Ahora, no sé si su aplicación de terceros hace nada de esto cuando se ejecuta el script / proceso, pero si desea hacerlo desde un servicio, que es cómo (y con Vista o Win7, que es el única manera de superar el aislamiento de la sesión 0).

Otros consejos

En función de su caso de uso, usted podría hacer lo que hago. Yo cazo el proceso Winlogon para la sesión activa y robar su testigo. Si no hay sesión activa (API devuelve -1), use 1 si WINVER> = 6 lo contrario 0. Esto da como resultado en el sistema en la sesión activa.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top