Esta es la primera parte de una serie de dos. El planteamiento es crear un programa que replique la funcionalidad básica de "RunAs", la utilidad de línea de comandos que permite ejecutar cualquier programa suplantando a otro usuario. Nuestro particular RunAs se encargará de solicitarnos de forma segura la clave para el usuario indicado y luego lanzará el .exe indicado suplantando al mismo y por lo tanto permitiéndonos hacer una escalada de privilegios o, por el contrario, ejecutar un programa con menos privilegios que el usuario actualmente autenticado en el sistema.

Su uso básico es este:

runas usuario ejecutable.exe

o bien

runas dominio\usuario ejecutable.exe

si queremos indicar el dominio también.

En este primer post voy a mostrar lo más sencillo que es lanzar el proceso suplantando a un usuario. Dejaré para el próximo la obtención de la clave del usuario y su almacenamiento seguro y pondré el código completo para descarga.

El código principal del programa es el que muestro a continuación y que ahroa explicaré:

public static void Main(string[] args)
        {
            if (args.Length != 2)
            {
                MuestraUso();
                return;
            }

            //Nombre de usuario a suplantar
            string usuario = args[0];
            string[] partes = usuario.Split('\\');

            SecureString claveSegura = PideClave(usuario);

            //Si no han introducido han pulsado ESC salimos sin hacer nada.
            if (claveSegura == null)
                return;

            //Programa a ejecutar
            string programa = args[1];

            try
            {
                ProcessStartInfo psi = new ProcessStartInfo(programa);
                psi.UseShellExecute = false;

                if (partes.Length == 2)
                {
                    psi.Domain = partes[0];
                    psi.UserName = partes[1];
                }
                else
                {
                    psi.UserName = partes[0];
                }

                psi.Password = claveSegura;

                Process.Start(psi);
            }
            catch (Win32Exception e)
            {
                Console.WriteLine("Se ha producido un error ejecutando la aplicación:");
                Console.WriteLine(e.Message);
            }

Si no se introducen dos argumentos en la línea de comandos se usa el método MuestraUso que muestra por pantalla la ayuda del programa (no lo voy a poner aquí pues es trivial). Para poder depurar el programa deberemos introducir unos parámetros de ejemplo en la pestaña "Debug" de las propiedades del proyecto:

En el primer parámetro se espera el nombre de usuario, el cual puede estar formado (o no) por dos partes: el dominio y el nombre de usuario separado por una barra inclinada "\", por lo que lo separamos para manejarlos indpendientemente.

El método PideClave, el más interesante de todo el código, se encarga de solicitar la clave al usuario de forma segura (lo veremos en el próximo post).

Usamos la clase ProcessStartInfo, aparecida en .NET 2.0, para lanzar el proceso indicado. Como vemos el código es directo excepto por dos o tres puntos interesantes:

1.- Establecemos la propiedad UseShellExecute a false. Esta propiedad sirve para especificar si se usará el Shell de Windows para lanzar la nueva aplicación o si por el contrario se lanzará directamente un proceso. La principal diferencia entre una u otra opción es que si esta propiedad es false podremos redirigir los flujos de consola (entrada, salida y errores) a voluntad. Además sólo nos permitirá lanzar ejecutables, que es el propósito de este programa. Si usásemos el valor true se podrían lanzar también los ejecutable a partir de un archivo asociado con éstos. Así, si pusiésemos "miDocumento.docx" se ejecutaría Microsoft Word, pero en nuestro caso tendríamos que poner el ejecutable siempre (lo que es más adecuado para el propósito de este programa). Todos los detalles en la página de MSDN para UseShellExecute.

2.- Sólo es posible asignar la clave en la propiedad PassWord usando una cadena segura, es decir, una clase SecureString, también aparecida con .NET 2.0. Más en el próximo.

3.- El método Start de la clase Process se usa para lanzar el proceso a partir de la información almacenada en la clase ProcessStartInfo.

El próximo día comentaré lo que es para mi más interesante de todo este programa: cómo pedir al usuario que introduzca su contraseña por consola de una manera segura, sin almacenarla nunca en memoria y usando la clase SecureString. También dejaré entonces el código de ejemplo completo.

¡Hasta pronto!

💪🏻 ¿Este post te ha ayudado?, ¿has aprendido algo nuevo?
Pues NO te pido que me invites a un café... Te pido algo más fácil y mucho mejor

Escrito por un humano, no por una IA