Jump to content


Photo

ExecuteAsUserSession


  • Please log in to reply
3 replies to this topic

#1 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 22 January 2015 - 06:48 AM

ExecuteAsUserSession se trata de una pequeña aplicación escrita sólo con la API de Windows que nos permite ejecutar una aplicación en el entorno de la sesión abierta por otro usuario. La diferencia con "ejecutar como", es que esta ejecuta como otro usuario pero en nuestra sesión. Se trata de abrir la aplicación en la sesión del usuario en cuestión, y esto es lo que hace ExecuteAsUserSession.

Queden claro tres cosas:
1.- La sesión del otro usuario debe existir y estar abierta.
2.- ExecuteAsUserSession debe ejecutarse como usuario System, en otro caso ejecutará la aplicación pasada como parámetro como nuestro usuario y sesión.
3.- Si se ejecuta como system pero la sesión no está abierta, la aplicación pasada como parámetro se ejecutará como system, dado que es el usuario elegido.

El código:

delphi
  1. program ExecuteAsUserSession;
  2.  
  3. uses
  4.   Windows, ShellAPI;
  5.  
  6. type
  7. WTS_SESSION_INFOA = record
  8.   SessionId:      DWORD; 
  9.   pWinStationName: PCHAR;
  10.   State:          DWORD;
  11. end;
  12. PWTS_SESSION_INFOA = ^WTS_SESSION_INFOA;
  13. PPWTS_SESSION_INFOA = ^PWTS_SESSION_INFOA;
  14. WTS_SESSION_INFO_ARRAY = array [0..0] of WTS_SESSION_INFOA;
  15. PWTS_SESSION_INFO_ARRAY = ^WTS_SESSION_INFO_ARRAY;
  16.  
  17. type
  18. WTS_PROCESS_INFOA = record
  19.   SessionId: DWORD;    // session id
  20.   ProcessId: DWORD;    // process id
  21.   pProcessName: LPSTR; // name of process
  22.   pUserSid: PSID;      // user's SID
  23. end;
  24. PWTS_PROCESS_INFOA = ^WTS_PROCESS_INFOA;
  25. PPWTS_PROCESS_INFOA = ^PWTS_PROCESS_INFOA;
  26. WTS_PROCESS_INFO_ARRAY = array [0..0] of WTS_PROCESS_INFOA;
  27. PWTS_PROCESS_INFO_ARRAY = ^WTS_PROCESS_INFO_ARRAY;
  28.  
  29. function  WTSEnumerateSessionsA(hServer: THandle; Reserved, Version: DWORD; ppSI: PPWTS_SESSION_INFOA; pCount: PDWORD): BOOL; stdcall external 'Wtsapi32.dll';
  30. function  WTSQuerySessionInformationW(hServer: THandle; SessionId: DWORD; WTSInfoClass: DWORD; var Buffer: pointer; var BytesReturned: DWORD): BOOL; stdcall external 'Wtsapi32.dll';
  31. procedure WTSFreeMemory(pMemory: Pointer); stdcall external 'Wtsapi32';
  32. function  WTSQueryUserToken(SessionId: ULONG; phToken: PHANDLE ): BOOL; stdcall external 'Wtsapi32';
  33. function  CreateEnvironmentBlock(lpEnvironment: PPointer; hToken: THANDLE; bInherit: BOOL): BOOL; stdcall external 'Userenv';
  34. function  DestroyEnvironmentBlock(lpEnvironment: Pointer): BOOL; stdcall external 'Userenv';
  35. function  AttachConsole(dwProcessId: DWORD): BOOL; stdcall external 'Kernel32.dll';
  36.  
  37. const
  38. WTS_CURRENT_SERVER_HANDLE = 0;
  39.  
  40.  
  41. function GetUserSessionId(User: PWCHAR): integer;
  42. var
  43.   pSi: PWTS_SESSION_INFOA;
  44.   pSiA: PWTS_SESSION_INFO_ARRAY;
  45.   Count, i: DWORD;
  46.   Buff: PWCHAR;
  47.   SizeBuff: DWORD;
  48. begin
  49.   Result:= -1;
  50.   WTSEnumerateSessionsA(WTS_CURRENT_SERVER_HANDLE, 0, 1, @pSi, @Count);
  51.   pSiA:= PWTS_SESSION_INFO_ARRAY(pSi);
  52.   // Buscamos la sesión
  53.   for i:= 0 to Count-1 do
  54.   begin
  55.     if WTSQuerySessionInformationW(0 {WTS_CURRENT_SERVER_HANDLE}, pSiA[i].SessionId, 5 {WTSUserName}, Pointer(Buff), SizeBuff) then
  56.     begin
  57.       if lstrcmpiW(Buff, User) = 0 then Result:= pSiA[i].SessionId;
  58.       WTSFreeMemory(Buff);
  59.     end;
  60.   end;
  61.   WTSFreeMemory(pSi);
  62. end;
  63.  
  64. function GetUserToken(User: PWCHAR): THandle;
  65. var
  66.   hToken: THandle;
  67.   SessionId: integer;
  68. begin
  69.   hToken:= 0;
  70.   Result:= 0;
  71.   SessionId:= GetUserSessionId(User);
  72.   if SessionId <> -1 then
  73.     // Duplicamos el token del usuario de la sesión
  74.     if WTSQueryUserToken(SessionId, @hToken) then
  75.       DuplicateTokenEx(hToken, TOKEN_ASSIGN_PRIMARY or TOKEN_ALL_ACCESS, nil, SecurityImpersonation, TokenPrimary, Result);
  76. end;
  77.  
  78. procedure HowToUse;
  79. var
  80.   Help: ShortString;
  81.   F: THANDLE;
  82. begin
  83.   Help:= #10+#10+'ExecuteAsUserSession User CmdPath' + #10 + #0;
  84.   AttachConsole(DWORD(-1));
  85.   F:= CreateFile('CONOUT$', GENERIC_READ or GENERIC_WRITE, FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
  86.   WriteConsole(F, @Help[1], lstrlen(@Help[1]), PDWORD(nil)^, nil);
  87.   CloseHandle(F);
  88.   FreeConsole;
  89. end;
  90.  
  91. //------------------------------------------------------------------------------
  92. // Punto de entrada al programa
  93. //------------------------------------------------------------------------------
  94. type
  95. AWCHAR  = Array [0..2] of PWCHAR;
  96. PAWCHAR = ^AWCHAR;
  97.  
  98.  
  99. var
  100.   pi: PROCESS_INFORMATION;
  101.   si: STARTUPINFO;
  102.   hToken: THANDLE;
  103.   lpEnvironment: Pointer;
  104.   Cmd: PWCHAR;
  105.   Argc: integer;
  106.   Argv: PAWCHAR;
  107. begin
  108.  
  109.   // Buscando los parámetros pasados
  110.   Argv:= PAWCHAR(CommandLineToArgvW(GetCommandLineW, Argc));
  111.   // Si no hay parámetros, muestro ayuda
  112.   if Argc <= 1 then
  113.   begin
  114.     HowToUse;
  115.     exit;
  116.   end;
  117.  
  118.   // Buscando el hToken del usuario dado
  119.   hToken:= GetUserToken(Argv[1]);
  120.   Cmd:= Argv[2];
  121.  
  122.   // Ejecutando el proceso
  123.   lpEnvironment:= nil;
  124.   CreateEnvironmentBlock(@lpEnvironment, hToken, FALSE);
  125.   CreateProcessAsUserW(hToken, nil, Cmd, nil, nil, FALSE,
  126.                 CREATE_NO_WINDOW or NORMAL_PRIORITY_CLASS or CREATE_UNICODE_ENVIRONMENT,
  127.                 lpEnvironment, nil, si, pi);
  128.   DestroyEnvironmentBlock(lpEnvironment);
  129.   CloseHandle(hToken);
  130.  
  131.   LocalFree(THANDLE(Argv));
  132. end.


Un ejemplo de uso en una consola ejecutada como administrador:

delphi
  1. MiniSystem ExecuteAsUserSession "pruebas Notepad.exe"


Adjunto el código fuente y binario, así como la aplicación MiniSystem para poder ejecutarlo como System. Recordar que MiniSystem debe ejecutarse específicamente como administrador.

Espero que sea de utilidad.


Saludos.
  • 0

#2 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 22 January 2015 - 08:57 AM

Siempre con "pequeñas" aplicaciones pero grandes enseñanzas, se agradece por supuesto  :)

Saludos
  • 0

#3 poliburro

poliburro

    Advanced Member

  • Administrador
  • 4945 posts
  • LocationMéxico

Posted 22 January 2015 - 02:18 PM

Como siempre, muy interesante el aporte amigo. No se de dónde, pero tengo este código que uso en un CGI que generá imágenes JPG. Su objetivo es colocar modificar el contexto de la aplicación en la que está ejecutándose el programa para poder realizar determinada operación:


delphi
  1. function NTLogon(User: string; Password: string; Dominio: String; Token: cardinal): String;
  2. begin
  3. Result := '';
  4. try
  5. if LogonUser(PChar(User), Pchar(Dominio), PChar(Password), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, Token) then
  6. if ImpersonateLoggedOnUser(token) then
  7. Result := 'Nada';
  8. except
  9.   on E: Exception do
  10.     Result := E.Message;
  11.   end;
  12. end;

desgraciadamente no recuerdo de dónde la tome para dar el crédito...
  • 0

#4 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 22 January 2015 - 05:14 PM

El problema de usar ese sistema es que falla al pretender usar la API CreateProcessAsUser, necesaria para "logearse" en otra sesión para crear un proceso en dicha sesión. El problema está en la falta de privilegios suficientes, es por eso que hay que hacerlo desde usuario system.

La técnica que muestro, permite lanzar un proceso GUI en cualquier sesión abierta, activa o no, desde un servicio, por ejemplo.


Saludos.
  • 0




IP.Board spam blocked by CleanTalk.