Monday 15 May 2017

Exploiting Environment Variables in Scheduled Tasks for UAC Bypass

The Windows Task Scheduler is a great place to go and find privilege escalations, it's typically abused to add SUID style capabilities to Windows in a nice easy to misunderstand package. It can execute programs as LocalSystem, it can auto-elevate applications for UAC, it can even host arbitrary COM objects. All in all it's a mess, which is why finding bugs in the scheduler itself or in the tasks isn't especially difficult. For example here's a few I've found before. This short blog is about a quick and dirty UAC bypass I discovered which works silently even with UAC is set to the highest prompt level and can be executed without dropping any files (other that a registry key) to disk.

Anyway I'm technically on a sabbatical from finding bugs in Microsoft products (best not ask why) so I'll keep this brief. However sometimes while I'm not looking you just sort of trip over a bug. I was poking around various scheduled tasks and noticed one which looked interesting, SilentCleanup. The reason this is interesting is it's a marked as auto-elevating (so will silently run code as UAC admin if the caller is a split-token administrator) and it can be manually started by the non-administrator user.

It turns out I'm not alone in noticing this is interesting, Matt Nelson already found a UAC bypass in this scheduled task but as far as can be determined it's already been fixed, so is there still a way of exploiting it? Let's dump some of the task's properties using Powershell to find out.


We can see the Principal property, which determines what account the task runs as and the Actions property which determines what to run. In the Principal property we can see the Group to run as is Authenticated Users which really means it will run as the logged on user starting the task. We also see the RunLevel is set to Highest which means the Task Scheduler will try and elevate the task to administrator without any prompting. Now look at the actions, it's specifying a path, but notice something interesting? It's using an environment variable as part of the path, and in UAC scenarios these can be influenced by a normal user by writing to the registry key HKEY_CURRENT_USER\Enviroment and specifying a REG_SZ value.

So stop beating around the bush, let's try and exploit it. I dropped a simple executable to c:\dummy\system32\cleanmgr.exe, set the windir environment variable to c:\dummy and started the scheduled task I immediately get administrator privileges. So let's automate the process, I'll use everyone's favourite language, BATCH as we can use the reg and schtasks commands to do all the work we need. Also as we don't want to drop a file to disk we can abuse the fact that the executable path isn't quoted by the Task Scheduler, meaning we can inject arbitrary command line arguments and just run a simple CMD shell.

The BATCH file first sets the windir environment variable to "cmd /K" with a following script which deletes the original windir enviroment variable then uses REM to comment the rest of the line out. Executing this on Windows 10 Anniversary Edition and above as a split token admin will get you a shell running as an administrator. I've not tested it on any earlier versions of Windows so YMMV. I didn't send this to MSRC but through a friend confirmed that it should already be fixed in a coming version of RS3, so it really looks like MS are serious about trying to lock UAC back down, at least as far as it can be. If you want to mitigate now you should be able to reconfigure the task to not use environment variables using the following Powershell script run as administrator (doing this using the UAC bypass is left as an exercise for reader).

If you want to find other potential candidates the following Powershell script will find all tasks with
executable actions which will auto elevate. On my system there are 4 separate tasks, but only one (the SilentCleanup task) can be executed as a normal user, so the rest are not exploitable. Good thing I guess.