Handle copy dump

这已经不是最新的技术了,但是也非常的有趣。

由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。(本文仅用于交流学习)

这个方法大概是2020年的时候国外友人提出的了,虽然不是新方法但是思路还是很有意思,值得去学习。
作者的大概思路就是利用NtDuplicateObject间接的去获取句柄,我们先来看看NtDuplicateObject函数是什么意思。

NtDuplicateObject

https://learn.microsoft.com/zh-cn/windows-hardware/drivers/ddi/ntifs/nf-ntifs-zwduplicateobject

9.PNG

NTSYSAPI NTSTATUS ZwDuplicateObject(
  [in]            HANDLE      SourceProcessHandle,
  [in]            HANDLE      SourceHandle,
  [in, optional]  HANDLE      TargetProcessHandle,
  [out, optional] PHANDLE     TargetHandle,
  [in]            ACCESS_MASK DesiredAccess,
  [in]            ULONG       HandleAttributes,
  [in]            ULONG       Options
);

我们着重看前三个参数

10.PNG
其和DuplicateHandle参数是差不多的,我们先创建两个个实例m.exe、t.exe,我们将m.exe的线程句柄复制到t.exe中,并在t.exe中将其线程终止。
m.exe

#include <iostream>
#include <windows.h>
#include <process.h>
#include <TlHelp32.h>
#include "ntdll.h"
#pragma comment(lib, "ntdll.lib")

using namespace std;

unsigned __stdcall thread(void* lpPragma)
{
    while (1)
    {
        Sleep(500);
        cout << "terminal me" << endl;
    }

    return 0;
}

HANDLE GetProcessHandle()
{
    DWORD pid;
    PROCESSENTRY32 ed;
    ed.dwSize = sizeof(PROCESSENTRY32);
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
    if (Process32First(snapshot, &ed) == TRUE)
    {
        while (Process32Next(snapshot, &ed) == TRUE)
        {
            if (string(ed.szExeFile) == "t.exe") {
                pid = ed.th32ProcessID;

                return OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
            }
        }
    }
}

int main(void)
{
    HANDLE hThread;
    hThread = (HANDLE)_beginthreadex(NULL, 0, thread, NULL, 0, NULL);
    cout << "Thread Handle: " << hThread << endl;

    HANDLE hTarget;

    if (NtDuplicateObject(GetCurrentProcess(), hThread, GetProcessHandle(), &hTarget, 
                            PROCESS_ALL_ACCESS, 0, DUPLICATE_SAME_ACCESS) == STATUS_SUCCESS) {
        cout << "句柄复制成功, 其句柄值为:" << hTarget << endl;
    }
    cin.get();
    return 0;
}

t.exe

#include <iostream>
#include <windows.h>
#include <stdlib.h>
#include <process.h>
using namespace std;

int main(void)
{
    HANDLE hRecv;

    cout << "请输入复制过来的句柄:" << endl;
    cin >> hRecv;

    TerminateThread(hRecv, 0);

    system("pause");
    return 0;
}

11.PNG
了解了NtDuplicateObject函数,那么我们如何获得进程打开的句柄呢?我们再来看看NtQuerySystemInformation函数

NtQuerySystemInformation

https://learn.microsoft.com/zh-cn/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation

1.PNG

__kernel_entry NTSTATUS NtQuerySystemInformation(
  [in]            SYSTEM_INFORMATION_CLASS SystemInformationClass,
  [in, out]       PVOID                    SystemInformation,
  [in]            ULONG                    SystemInformationLength,
  [out, optional] PULONG                   ReturnLength
);

我们着重看一下第一个参数SystemInformationClass(官方文档给出的参数很多,我们着重看一下要使用的就行)
我们使用SystemHandleInformation参数,遍历系统句柄信息,我们来看看SYSTEM_HANDLE_INFORMATION结构体

12.PNG
将所以的句柄放在Handles[1]中,其总数由NumberOfHandles参数表示,我们再来看看SYSTEM_HANDLE_INFORMATION结构体

3.PNG
其中UniqueProcessId、HandleValue是什么意思很明了了

OpenProcess

这个函数再熟悉不过了,我们主要看看第一个参数
https://learn.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights
因为我们只是要复制句柄,因此我们不必使用PROCESS_ALL_ACCESS,我们可以使用如下

14.PNG

大致思路

  • 我们先获得SeDebug权限
  • 通过NtQuerySystemInformation函数获取所有进程打开的句柄
  • 通过OpenProcess打开进程的句柄
  • 通过NtDuplicateObject函数获得句柄的副本信息
  • NtQueryObject获得句柄的信息,来筛选是否是进程
  • 最后通过QueryFullProcessImageName函数来获得进程的路径,以判断是不是我们要获得的指定进程
  • 最后利用MiniDumpWriteDump进行转储
    怎么获得SeDebug权限这里就不叙述了
    NtQuerySystemInformation获得所以进程打开的句柄
    4.PNG
    NtDuplicateObject
    6.PNG
    NtQueryObject
    5.PNG
    QueryFullProcessImageNameW

8.PNG

14.PNG

参考

https://skelsec.medium.com/duping-av-with-handles-537ef985eb03

  • 发表于 2023-02-15 09:00:01
  • 阅读 ( 6829 )
  • 分类:内网渗透

0 条评论

请先 登录 后评论
事与愿违
事与愿违

9 篇文章