Generar un proceso que se ejecuta en el contexto del usuario suplantado en Microsoft ASP.NET

En este artículo se describe cómo generar un proceso que se ejecuta en el contexto del usuario suplantado.

              Versión original del producto: ASP.NET
Número de KB original: 889251

Introducción

En este artículo paso a paso se describe cómo generar un proceso que se ejecuta en el contexto del usuario suplantado en ASP.NET páginas. Para generar un proceso que se ejecuta en el contexto del usuario suplantado, no puede usar el System.Diagnostics.Process.Start método . Esto se debe a que, en ASP.NET, la suplantación se realiza en el nivel de subproceso y no en el nivel de proceso. Por lo tanto, cualquier proceso que genere a partir de ASP.NET se ejecutará en el contexto del proceso de trabajo de ASP.NET y no en el contexto suplantado.

Descripción de la técnica

Para solucionar este problema, debe realizar llamadas de invocación de plataforma (P/Invoke) a las siguientes API de Win32:

  • La CreateProcessAsUser función crea un proceso bajo la identidad del token de seguridad especificado en uno de los parámetros. Sin embargo, la llamada a la CreateProcessAsUser función requiere un token principal. Por lo tanto, debe convertir el token suplantado en un token principal.

  • La DuplicateTokenEx función convierte un token suplantado en un token principal. La llamada a la CreateProcessAsUser función usa este token principal.

Nota:

Para que la llamada a la CreateProcessAsUser función funcione, se deben asignar los siguientes derechos de usuario de seguridad al usuario suplantado:

  • En un equipo que ejecuta Windows, asigne el derecho Reemplazar un token de nivel de proceso y el derecho de usuario Aumentar cuotas al usuario suplantado.
  • En un equipo que ejecuta Windows Server o Windows XP, asigne el derecho Reemplazar un usuario de token de nivel de proceso al usuario suplantado.

Pasos para generar un proceso

Microsoft proporciona ejemplos de programación con fines ilustrativos únicamente, sin ninguna garantía, ya sea expresa o implícita. Esto incluye, entre otras, las garantías implícitas de comerciabilidad e idoneidad para un fin determinado. Se considera que está familiarizado con el lenguaje de programación que se muestra y con las herramientas para crear y depurar procedimientos. Los ingenieros de soporte técnico de Microsoft pueden explicarle la funcionalidad de un determinado procedimiento, pero no modificarán estos ejemplos para ofrecer mayor funcionalidad ni crearán procedimientos adaptados a sus necesidades específicas. Para generar un proceso que se ejecute en el contexto del usuario suplantado, siga estos pasos:

  1. En Visual Studio .NET, cree una nueva aplicación web de Visual C# ASP.NET y, a continuación, asigne a la aplicación el nombre Q889251.

  2. Abra el archivo WebForm1.aspx en la vista de código.

  3. En el archivo WebForm1.aspx , agregue las siguientes instrucciones al bloque de código using.

    using System.Runtime.InteropServices;
    using System.Security.Principal;
    
  4. Busque la línea de código similar a la siguiente línea de código.

    public class WebForm1 : System.Web.UI.Page
    
  5. Después de la línea de código que se identifica en el paso 4, agregue el código siguiente.

    [StructLayout(LayoutKind.Sequential)]
    public struct STARTUPINFO
    {
        public int cb;
        public String lpReserved;
        public String lpDesktop;
        public String lpTitle;
        public uint dwX;
        public uint dwY;
        public uint dwXSize;
        public uint dwYSize;
        public uint dwXCountChars;
        public uint dwYCountChars;
        public uint dwFillAttribute;
        public uint dwFlags;
        public short wShowWindow;
        public short cbReserved2;
        public IntPtr lpReserved2;
        public IntPtr hStdInput;
        public IntPtr hStdOutput;
        public IntPtr hStdError;
    }
    [StructLayout(LayoutKind.Sequential)]
    public struct PROCESS_INFORMATION
    {
        public IntPtr hProcess;
        public IntPtr hThread;
        public uint dwProcessId;
        public uint dwThreadId;
    }
    [StructLayout(LayoutKind.Sequential)]
    public struct SECURITY_ATTRIBUTES
    {
        public int Length;
        public IntPtr lpSecurityDescriptor;
        public bool bInheritHandle;
    }
    [DllImport("kernel32.dll", EntryPoint="CloseHandle", SetLastError=true, CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)]
    public extern static bool CloseHandle(IntPtr handle);
    [DllImport("advapi32.dll", EntryPoint="CreateProcessAsUser", SetLastError=true, CharSet=CharSet.Ansi, CallingConvention=CallingConvention.StdCall)]
    public extern static bool CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment, String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
    [DllImport("advapi32.dll", EntryPoint="DuplicateTokenEx")]
    public extern static bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess, ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType, int ImpersonationLevel, ref IntPtr DuplicateTokenHandle);
    
  6. En Explorador de soluciones, haga clic con el botón derecho en WebForm1.aspx y, a continuación, haga clic en Abrir. El formulario web se abre en la vista de diseño.

  7. En el menú Ver , haga clic en Código fuente HTML.

  8. Reemplace todo el código existente en la ventana Código fuente HTML por el código siguiente.

    <%@ Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false" Inherits="Q889251.WebForm1" %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
    <HTML>
       <HEAD>
          <title>WebForm1</title>
          <meta name="GENERATOR" Content="Microsoft Visual Studio 7.0">
          <meta name="CODE_LANGUAGE" Content="C#">
          <meta name="vs_defaultClientScript" content="JavaScript">
          <meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
       </HEAD>
       <body>
          <form id="Form1" method="post" runat="server">
             <P>&nbsp;</P>
             <P>
                Enter Path of process to be run (with relevant parameters)
                <asp:TextBox id="TextBox1" runat="server"></asp:TextBox>
             </P>
             <P>
                <asp:Button id="Button1" runat="server" Text="CreateProcess"></asp:Button>
             </P>
             <P>
                <asp:Label id="Label1" runat="server">Status:</asp:Label>
             </P>
             <P>
                <asp:Label id="Label2" runat="server">Impersonated Identity:</asp:Label>
             </P>
          </form>
       </body>
    </HTML>
    
  9. En el menú Ver , haga clic en Diseño.

  10. Haga doble clic en CreateProcess. El Button1_Click método se inserta en el código y el código aparece en el panel de contenido.

  11. Reemplace el método existente Button1_Click por el código siguiente.

    private void Button1_Click(object sender, System.EventArgs e)
    {
        IntPtr Token = new IntPtr(0);
        IntPtr DupedToken = new IntPtr(0);
        bool ret;
        Label2.Text+=WindowsIdentity.GetCurrent().Name.ToString();
        SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
        sa.bInheritHandle = false;
        sa.Length = Marshal.SizeOf(sa);
        sa.lpSecurityDescriptor = (IntPtr)0;
        Token = WindowsIdentity.GetCurrent().Token;
        const uint GENERIC_ALL = 0x10000000;
        const int SecurityImpersonation = 2;
        const int TokenType = 1;
        ret = DuplicateTokenEx(Token, GENERIC_ALL, ref sa, SecurityImpersonation, TokenType, ref DupedToken);
        if (ret == false)
        {
            Label1.Text +="DuplicateTokenEx failed with " + Marshal.GetLastWin32Error();
        }
        else
        {
            Label1.Text+= "DuplicateTokenEx SUCCESS";
            STARTUPINFO si = new STARTUPINFO();
            si.cb = Marshal.SizeOf(si);
            si.lpDesktop = "";
            string commandLinePath;
            commandLinePath = TextBox1.Text;
            PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
            ret = CreateProcessAsUser(DupedToken,null,commandLinePath, ref sa, ref sa, false, 0, (IntPtr)0, "c:\\", ref si, out pi);
            if (ret == false)
            {
                Label1.Text +="CreateProcessAsUser failed with " + Marshal.GetLastWin32Error();
            }
            else
            {
                Label1.Text +="CreateProcessAsUser SUCCESS. The child PID is" + pi.dwProcessId;
                CloseHandle(pi.hProcess);
                CloseHandle(pi.hThread);
            }
            ret = CloseHandle(DupedToken);
            if (ret == false)
            {
                Label1.Text+=Marshal.GetLastWin32Error();
            }
            else
            {
                Label1.Text+="CloseHandle SUCCESS";
            }
        }
    }
    
  12. On the Build menu, click Build Solution.

  13. En el menú Depurar , haga clic en Iniciar.

  14. En la página WebForm1 , escriba la ruta de acceso de un proceso que desea iniciar. Por ejemplo, escriba SystemDriver \Windows\Notepad.exe.

  15. Haga clic en CreateProcess.

Referencias