首页
社区
课程
招聘
[翻译]红队战术: 结合直接系统调用和sRDI来绕过AV / EDR
发表于: 2019-8-3 21:36 28675

[翻译]红队战术: 结合直接系统调用和sRDI来绕过AV / EDR

2019-8-3 21:36
28675

English:https://outflank.nl/blog/2019/06/19/red-team-tactics-combining-direct-system-calls-and-srdi-to-bypass-av-edr/


在本文我们将介绍如何使用直接系统调用(Direct System Calls)以及配合sRDI注入来绕过R3层的行为监控。


随着安全技术的防御能力逐渐增强,另一方面,攻击技术也在不断发展,作为一个Red Team需要研究更先进的技术来绕过当下比较流行的防御和检测机制。


近期一篇恶意代码的研究报告声称,使用"直接系统调用"技术来绕过安全软件用户层Hook的恶意样本正在与日俱增。


研究报告:https://www.cyberbit.com/blog/endpoint-security/malware-mitigation-when-direct-system-calls-are-used/


作为一名ReadTeamer,要与时俱进!! 现在轮到我们也来更新一波shellcode攻击代码了。


我们将接下来将使用这种技术证明,在不触碰磁盘的情况下绕过AV/EDR监控的用户层Hook,使用Cobalt Strike来dump LSASS.exe进程内存。


PoC代码可以在这里下载:https://github.com/outflanknl/Dumpert


为了弄清楚直接系统调用的真正含义,首先我们需要先深入Windows操作系统底层架构。


如果你使用过MS-DOS年代Windows系统,也许你会记得,一个简单的程序崩溃可以引起整个操作系统瘫痪。


这是因为操作系统在实模式(Real Mode)运行,处理器在实模式下运行时,不会有内存隔离的概念(没有严格限制或者声明,哪些内存区域是可以访问,哪些不能访问)。


也就意味者,如果你写的程序出现了bug导致内存破坏(Memory Currption)会导致整个操作系统停止运行。




一直到后来出现了可以支持保护模式的新处理器和操作系统,这一现象才被改变。


为了防止一个进程崩溃导致操作系统也跟着崩溃,在保护模式下引入了许多安全措施,通过虚拟内存(Virtual Memory)和权限级别(Privilege Levels),和一个叫Rings的概念,来隔离运行的不同进程之间,以及进程和操作系统之间的内存访问。


Rings一共有4层,Ring0 ~ Ring3分别对应4个特权级别。


Windows操作系统中实际只使用了两个特权级别:


一个是Ring3层,平时我们所见到的应用程序运行在这一层,所以叫它用户层,也叫User-Mode。所以下次听到别人讲(Ring3、用户层、User-Mode)时,其实是在讲同一个概念。

一个是Ring0层,像操作系统内核(Kernel)这样重要的系统组件,以及设备驱动都是运行在Ring0,内核层,也叫Kernel-Mode。


通过这些保护层来隔离普通的用户程序,不能直接访问内存区域,以及运行在内核模式下的系统资源。


当一个用户层程序需要执行一个特权系统操作,或者访问内核资源时。处理器首先需要切换到Ring0模式下才能执行后面的操作。


切换Ring0的代码,也就是直接系统调用所在的地方。


我们通过监控Notepad.exe进程保存一个.txt文件,来演示一个应用层程序如何切换到内核模式执行的:

上面截图展示了Notepad.exe进程保存一个文件时的执行流程(call stack),从下往上看执行流程。


我们可以看到 notepad调用了kernel32模块中的WriteFile 函数,然后该函数内部又调用了ntdll中的NtWriteFile来到了Ring3与Ring0的临界点。


因为程序保存文件到磁盘上,所以操作系统需要访问相关的文件系统和设备驱动。应用层程序自己是不允许直接访问这些需要特权资源的。


应用程序直接访问设备驱动会引起一些意外的后果(当然操作系统不会出事,最多就是应用程序的执行流程出错导致崩溃)。所以,在进入内核层之前,调用的最后一个用户层API就是负责切换到内核模式的。


CPU中通过执行syscall指令,来进入内核模式,至少x64架构是这样的。我们可以通过下面 WinDBG截图中看到,反汇编的NtWriteFile指令:

把被调用函数相关的参数PUSH到栈上以后,ntdll中的NtWriteFile函数的职责就是,设置EAX为对应的"系统调用号",最后执行syscall指令,CPU就来到了内核模式(Ring0)下执行。


进入内核模式后,内核通过diapatch table(SSDT),来找到和系统调用号对应的Kernel API,然后将用户层栈上的参数,拷贝到内核层的栈中,最后调用内核版本的ZwWriteFile函数。


当内核函数执行完成时,使用几乎相同的方法回到用户层,并返回内核API函数的返回值(指向接收数据的指针或文件句柄)。


像NtWriteFile这样在进入内核层之前的函数,一般也是大部分安全产品,比如:AV、EDR和Sanbox软件经常设置Hook的地方,它们通过Inline Hook来劫持执行流程到自己引擎中,以便完成对一些敏感API的监控,


如果发现任何可疑的参数,则直接返回失败,或弹出窗口警告。


正如上图NtWriteFile函数的反汇编指令,你可能注意到了,它只有短短8行汇编指令,在这些指令中最重要的就是:系统调用号、syscall指令、进入NtWriteFile函数前,PUSH到栈上的正确的参数,以及使用正确的调用约定。



有了上面这些知识的铺垫,我们为何不自己来实现这几行汇编代码,模拟直接系统调用(Direct System Calls)就可以不用再调用NTDLL中的任何函数了,同时我们也Bypass了User-Mode(Ring3)下面任何设置在NTDLL函数中的Hook。


这正是本文的目的,在开始动手之前,我们先来简单了解一下Windows编程接口。

用户层的应用程序要想和底层系统交互,通常使用应用程序编程接口(Application Programming Interface )也就是所谓的API。如果你是编写C/C++应用的Windows程序开发程序员,通常使用 Win32 API。


Win32API是微软封装的一套API接口,由几个DLL(所谓的Win32子系统DLL)组成。在Win32 API下面使用的是Naitve API(ntdll.dll),这个才是真正用户层和系统底层交互的接口,一般称为用户层和内核层之间的桥梁。


但是ntdll中函数大部分都没有被微软记录到官方的开发文档中,为了兼容性问题,大多数情况在写程序时,应该避免直接使用ntdll中的API。




微软在Native API上面又封装一层的神奇之处正是因为Native API是用户层与内核层之间的桥梁,这样就可以在不影响Win32编程接口的情况下对系统结构进行修改。


现在我们对系统调用和Windows编程API有了一些了解,让我们看看如何通过编程来绕过Win32接口层,直接调用系统API并绕过潜在的Ring3层Hook。

有一个小问题还没有提到,系统调用号会受OS版本影响而变化,有时甚至是Service Pack、内置版本号等。不过不用担心,Google Project Zero项目的 @j00ru 成员统计了所有Windows系统版本中的Native API的系统调用号。


在线查询系统调用号:https://j00ru.vexillium.org/syscalls/nt/64/  有了这张表,我们可以直接搜索我们想要使用的Native API,就可以看到该API在不同系统中的调用号。


我们需要编写汇编来调用Driect System Calls。 在Virtual Studio项目中需要启用MASM编译依赖的支持,我们才能在项目中添加.asm文件。

要想通过这种方法来编写一个高级木马来完全绕过用户层API调用几乎是不可能的,至少实现起来非常麻烦,因为这些参数结构的问题、等等。


有时候可能你只是想在恶意代码中使用一个API函数,但是,不曾想这个API的调用堆栈某处早已被一些AV、EDR软件设置了Hook,随时等你上钩。


让我们来看看如何使用直接系统调用来卸载Hook。



通常情况下,基于用户模式的AV、EDR软件通过使用跳转指令(JMP),将API入口处前5个字节修改为指向安全软件的Hook函数。


卸载这种Hook的方法也早被 @SpecialHoang 和@domchell这两位大神公布过了: https://www.mdsec.co.uk/2019/03/silencing-cylance-a-case-study-in-modern-edrs/


如果你仔细研究这些卸载Hook的思路,你会注意到这些方法中用到了诸如:VirtualProtectEx、WriteProcessMemory之类的API来卸载Native API函数的Hook。


但是如果VirtualProtectEx这些API也被Hook和监视了呢?嘿嘿!这下我们就可以通过直接系统调用来卸载这些Hook,不怕半路杀出个程咬金了。


在我们的PoC代码中,基本上和普通卸载Hook的思路一样,恢复被Hook函数的前5字节原始的汇编指令代码。唯一的区别是我们执行恢复时调用的是Direct System Calls函数(ZwProtectVirtualMemory 和ZwWriteVirtualMemory)。

​在攻击过程中,通常我们需要使用Mimikatz来获取目标系统上的凭证、Hashes、Kerberos票据。如今,终端检测软件和情报分析系统在检测和预防Mimikatz方面做的相当不错。


如果你正在进行评估,并且你的攻击场景需要尽可能保持隐蔽,直接在终端上使用Mimikatz并不是最好的方法(即使是在内存中)。另外使用procdump等工具转储LSASS内存通常会被 AV、EDR的Hooks检测到。


因此我们需要一个替代方案来访问LSASS内存,@SpecialHoang 博客中公布了一个方法,先卸载相关函数的Hook,然后再创建LSASS的内存转储。



作为概念证明,我们创建了一个名为”Dumpert“的LSASS内存转储工具。此工具结合了直接系统调用和卸载API  Hook,可以让你创建一个LSASS的minidump。并且可能会Bypass一些AV、EDR产品的检测。

得到Minidump文件后,我们就可以在自己机器上使用Mimikatz来提取凭证信息。

如果我们不想磁盘落地,就得需要使用某种注入技术。我们可以写一个反射式加载的DLL,但是反射式DLL注入会留下可以被检测到的内存数据。


我的同事@StanHacked告诉我一种称为 "Shellcode Reflective DLL Injection"的DLL注入技术。


sRDI可以把一个普通的DLL文件转换为一段不依赖任何位置的Shellcode,这项技术是被Slient Break Security的Nick Landers(@monoxgas)开发,基本上属于RDI的升级版。


相对于标准RDI,使用SRDI的一些优点:



[招生]系统0day安全班,企业级设备固件漏洞挖掘,Linux平台漏洞挖掘!

最后于 2019-8-4 10:09 被Adventure编辑 ,原因: 修正错别字
收藏
免费 5
支持
分享
打赏 + 2.00雪花
打赏次数 1 雪花 + 2.00
 
赞赏  mb_ovrzbwwl   +2.00 2019/08/07 有事找你处理,如果有时间请加Q7620971,给报酬!!!
最新回复 (12)
雪    币: 5836
活跃值: (1948)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
2
不明觉厉
2019-8-4 12:18
0
雪    币: 10446
活跃值: (4596)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
PatchGuard还真是防君子不防小人
2019-8-4 18:17
0
雪    币: 7005
活跃值: (1846)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
想法可以的~棒!
2019-8-5 18:02
0
雪    币: 877
活跃值: (4061)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
good
2019-8-6 15:36
0
雪    币: 478
活跃值: (2838)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
厉害,mark一下.
2019-8-18 11:53
0
雪    币: 9771
活跃值: (2596)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
mark,直接系统调用。
2019-10-8 00:36
0
雪    币: 83
活跃值: (1092)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
8
good
2019-10-19 15:06
0
雪    币: 73
活跃值: (3110)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
9
卧槽,正好有个样本就是这么做的。。。
2019-11-26 17:20
0
雪    币: 370
活跃值: (256)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
nice啊,写的真不错
2021-7-17 09:56
0
雪    币: 143
活跃值: (780)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
这ZwProtectVirtualMemory未导出能这样用吗???
2021-8-6 16:22
0
雪    币: 47
活跃值: (396)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
联想到Linux 中的Shellcode  就是写汇编代码直接实现系统调用
2023-7-3 21:59
0
雪    币: 5109
活跃值: (994)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
13
感谢分享
2023-7-4 08:15
0
游客
登录 | 注册 方可回帖
返回
//