欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

深入剖析线程与进程句柄泄露漏洞(下)

来源:本站整理 作者:佚名 时间:2019-08-30 TAG: 我要投稿

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中的操作。下面给出实现所有这些目标的最终代码:

[1] [2] [3]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载