导语:今天,我发布了SharpSploit,这是我过去几个月以来一直在用C#开发的一系列攻击工具中的第一个。SharpSploit是一个用C#编写的.NET框架漏洞后期利用库,目的是为了突出.NET的攻击面,并使red teamers更容易的使用和攻击.NET框架。
今天,我发布了SharpSploit,这是我过去几个月以来一直在用C#开发的一系列攻击工具中的第一个。SharpSploit是一个用C#编写的.NET框架漏洞后期利用库,目的是为了突出.NET的攻击面,并使red teamers更容易的使用和攻击.NET框架。
SharpSploit的部分名称是对PowerSploit项目的致敬,这也是一款我个人最爱的攻击工具!虽然SharpSploit确实移植了PowerSploit的某些功能,但我的目的并不是创建一个完全一样的PowerSploit。SharpSploit将是一个独立的项目,尽管它与PowerSploit的目标是相似的。
C#的吸引力
在将现有PowerShell工具集移植到C时,安全社区在攻击性方面似乎正在出现一种趋势,特别是最近我的SpecterOps队友发布的工具,包括:@harmj0y的GhostPack工具集和@0xthirteen的SharpView。而SharpSploit则是整个发展趋势中的一小部分。随着PowerShell中增加的安全功能(即ScriptBlock Logging,AMSI等),red teamers正在将注意力转向其他攻击方式是有一定道理的。而且,C#是PowerShell未来发展过程中合乎逻辑的下一步,它们都是基于.NET框架的,所以将工具集从PowerShell移植到C#是相当容易的。
但是,从攻击的角度来看,C#并不是没有它自己的问题。从Matt Graeber的解释来看 optics 要出现在.NET里(点击查看Matt Graeber的解释),并且从开发人员可用性的角度来看,我们失去了相当多的灵活性,因为我们的编程语言从一个像PowerShell的脚本语言变成了像C#这样的编译语言。
现在,我们还得开始担心.NET版本的问题。默认情况下,你会在大多数Windows操作系统版本上找到.NET v3.5,但较新的Windows 10和Server 2016系统默认只安装了.NET v4.0 +。另外的一个“问题”是所有的Windows操作系统版本上都没有默认启用.NET,你会发现在Windows Server 2008和早期的服务器操作系统版本上需要明确启用.NET。SharpSploit试图通过使用.NET v3.5和v4.0来解决这个问题,尽可能获取更多的覆盖范围,但是你需要注意要在正确的操作系统上使用正确的版本。
控制台要还是不要?
你会在SharpSploit和到目前为止已经发布的大多数其他攻击性的C#库之间看到的最重要的区别,我的工具没有SharpSploit.exe,因为SharpSploit被设计为一个“库”,所以只有一个SharpSploit.dll。
我的目的是让SharpSploit主要用于安全人员在自己的工具集中引用的库。但是,我预计此实现会有一些限制,这可能会迫使我最终添加基于控制台的界面。例如,Cobalt Strike的execute-assembly模块需要应用程序具有EntryPoint(即“main”函数)来执行,因此SharpSploit目前还无法使用Cobalt Strike来轻松操作。这是一个很好的例子,说明了在我们从PowerShell过渡到C#时我们必须解决一些灵活性问题。
现在不要太担心这个问题,你很快就能看到我在这篇文章中描述的执行SharpSploit的一些具有创新性的其他方法。我可能会在某些方面撰写后续的文章来介绍执行如何方便的执行SharpSploit的功能。
SharpSploit 功能介绍
那么SharpSploit到底包含了些什么?我们继续深入吧!SharpSploit目前包括4个关键的高级别名称空间:Credentials,Enumeration,Execution,和LateralMovement。接下来,我们将逐一介绍每个名称空间。
SharpSploit.Credentials
该SharpSploit.Credentials命名空间包含了与凭证处理相关的任何一个类!目前,这包括了Mimikatz的所有功能以及令牌操作。
SharpSploit.Credentials.Mimikatz
SharpSploit.Credentials.Mimikatz类实现了执行任何Mimikatz命令的功能。SharpSploit的这个功能实现使用了@subtee的PELoader 的改编版本,并借鉴了@xorrior的实现思路,以及加载@gentilkiwi开发的优秀项目——Mimikatz。
在这里,我要提及下@harmj0y的SafetyKatz项目。主要区别在于SafetyKatz提供了在lsass.exe的minidump上使用Mimikatz的便利,同时SharpSploit.Credentials.Mimikatz可以让用户执行任何Mimikatz命令。
以下是SharpSploit.Credentials.Mimikatz类中实现的主要功能:
· Command() – 使用PE.Load()加载Mimikatz PE并执行选定的Mimikatz命令。
· LogonPasswords()- 使用PE.Load()加载Mimikatz PE并执行Mimikatz命令并从LSASS检索明文密码。等价于Command("privilege::debug sekurlsa::logonPasswords")。(需要管理员权限)
· SamDump() – 使用PE.Load() 加载Mimikatz PE并执行Mimikatz命令并从SAM数据库中检索密码哈希值。等价于Command("privilege::debug lsadump::sam")。(需要管理员权限)
· LsaSecrets() – 使用PE.Load()加载Mimikatz PE并执行Mimikatz命令并检索存储在注册表中的LSA密文。等价于Command("privilege::debug lsadump::secrets")。(需要管理员权限)
· LsaCache() – 使用PE.Load()加载Mimikatz PE并执行Mimikatz命令并从注册表中检索域缓存凭证哈希值。等价于Command("privilege::debug lsadump::cache")。(需要管理员权限)
· Wdigest() – 使用PE.Load()加载Mimikatz PE并执行Mimikatz命令并从注册表中检索Wdigest凭证。等价于Command("sekurlsa::wdigest")。
· All()- 使用PE.Load()加载Mimikatz PE并执行上述每个内置的本地凭证转储命令。(需要管理员权限)
· DCSync() – 使用PE.Load()加载Mimikatz PE并执行“dcsync”模块以检索指定(或所有)Domain用户的NTLM哈希值。(需要域管理员权限(或同等权限))
· PassTheHash() – 使用PE.Load()加载Mimikatz PE并执行“pth”模块然后以使用NTLM密码哈希进行身份验证的用户启动新进程。(需要管理员权限)
SharpSploit.Credentials.Tokens
SharpSploit.Credentials.Tokens类实现了令牌操作功能,以及依赖于令牌操作更复杂的动作。虽然目前已经创建了许多令牌操作项目,但SharpSploit.Credentials.Tokens的开发过程中多次借鉴了@0xbadjuju开发的很棒的Tokenvator项目。
以下是SharpSploit.Credentials.Tokens类中实现的主要功能:
· WhoAmI() – 获取当前使用的或模拟令牌的用户名。
· ImpersonateUser() – 模拟指定用户拥有的进程的令牌。用于以指定用户身份执行后续命令。(需要管理员权限)
· ImpersonateProcess() – 模拟指定进程的令牌。用于以与指定进程的令牌关联的用户身份执行后续命令。(需要管理员权限)
· GetSystem() – 模拟SYSTEM用户。等价于ImpersonateUser("NT AUTHORITY\SYSTEM")。(需要管理员权限)
· BypassUAC() – 通过令牌复制绕过UAC并生成具有高完整性的指定进程。(需要管理员权限)
· RunAs() – 使用指定密码作为指定用户运行指定函数的新令牌。RevertToSelf()执行该功能后会自动调用。
· MakeToken() – 使用指定的用户名和密码创建新令牌,并模拟该令牌以指定用户的身份执行后续的操作。
· RevertToSelf() – 结束模拟任何令牌,恢复到与当前进程关联的初始令牌。在与模拟令牌功能一起使用并且不自动RevertToSelf功能时非常有用,如:ImpersonateUser(),ImpersonateProcess(),GetSystem(),和MakeToken()。
· EnableTokenPrivilege() – 为指定的令牌启用指定的安全权限。(需要管理员权限)
SharpSploit.Enumeration
SharpSploit.Enumeration命名空间包含了用作枚举的任何类。目前,这包括了一些基本的基于本地主机的枚举,网络枚举(即ping /端口扫描),以及域和网络枚举。我认为这个命名空间有很多增加和改进的空间。
SharpSploit.Enumeration.Host
SharpSploit.Enumeration.Host类执行本地基于主机的基本枚举操作。这个类目前实现的是非常基础的功能。我计划最终做一些有用的补充功能,但目前还有许多其他更强大的工具,如Seatbelt。
以下是SharpSploit.Enumeration.Host类中实现的主要功能:
· GetProcessList() – 获取系统上正在运行的进程的列表。
· CreateProcessDump() – 创建正在运行的进程的内存的小型转储。如果转储LSASS进程,会对离线使用Mimikatz很有用。(需要管理员权限)
· GetHostname() – 获取系统的主机名。
· GetUsername() – 获取正在运行的进程的当前域和用户名。
· GetCurrentDirectory() – 获取当前工作目录的完整路径。
· GetDirectoryListing() – 获取当前工作目录的目录列表。
· ChangeCurrentDirectory() – 通过将指定的字符串附加到当前工作目录来更改当前目录。
· RegistryRead() – 读取存储在注册表中的值。
· RegistryWrite() – 将值写入注册表。
SharpSploit.Enumeration.Network
SharpSploit.Enumeration.Network类包含了用于网络枚举的TCP ping/端口扫描器。
以下是SharpSploit.Enumeration.Network类中实现的主要功能:
· PortScan() – 对指定的计算机和端口进行端口扫描并报告打开的端口。
· Ping() – Ping指定的计算机并识别存活的系统。
SharpSploit.Enumeration.Domain
SharpSploit.Enumeration.Domain类提供了Active Directory域枚举库。这是@harmj0y的PowerView项目的部分C#实现。
这个类不打算成为PowerView的直接或完整实现,有很多东西的格式和实现方式也不同。我还应该提到@0xthirteen的SharpView项目,它的目标是成为PowerView更直接或更完整的C#实现。
SharpSploit.Enumeration.Domain.DomainSearcher
SharpSploit.Enumeration.Domain.DomainSearcher类的功能有助于使用一组凭证搜索特定的AD域。
与使用PowerView相比,这是你在使用SharpSploit.Enumeration.Domain时会注意到的第一个主要差异。PowerView功能可以作为“静态”函数独立执行,符合PowerShell作为脚本语言的性质。SharpSploit包含了面向对象编程语言(如C#)的本质。你需要创建一个DomainSearcher对象,该对象需要设置为使用一组特定的凭据搜索特定域,并在该DomainSearcher对象上调用特定的枚举函数。
DomainSearcher类包含了下列主要功能:
· GetDomainUsers()- 获取DomainObject当前域中指定(或所有)的用户列表。
· GetDomainGroups()- 获取DomainObject当前域中指定(或所有)的用户组的列表。
· GetDomainComputers()- 获取DomainObject当前域中指定(或所有)的计算机列表。
· GetDomainSPNTickets()- 获取指定的DomainObjects的SPNTicket。
· Kerberoast()- 获取SPNTicket在当前域中设置了SPN的指定(或所有)的用户列表。
SharpSploit.Enumeration.Net
SharpSploit.Enumeration.Net类依旧是PowerView的部分C#实现,并且包括了通过使用Windows API函数(类似于Windows 本地的“NET.EXE”实用程序)枚举在远程计算机上的本地用户,用户组,登录和会话的功能。需要注意的一点是不支持PowerView中针对“WinNT”的枚举功能。
SharpSploit.Enumeration.Net类包括了以下主要功能:
· GetNetLocalGroups()-从指定的远程计算机上获取LocalGroup 列表。
· GetNetLocalGroupMembers()-从指定的计算机组中的指定远程计算机上获取LocalGroupMember 列表。
· GetNetLoggedOnUsers()-从指定的远程计算机上获取LoggedOnUser 列表。
· GetNetSessions()-从指定的远程计算机上获取SessionInfo 列表。
SharpSploit.Execution
SharpSploit.Execution命名空间包含了与执行相关的任何类。目前的功能有PE加载,.NET程序集和shell / powershell命令。
SharpSploit.Execution.Assembly
SharpSploit.Execution.Assembly类包括了用于加载.NET组件和通过反射在组件内执行功能的方法。
SharpSploit.Execution.Assembly类包括了以下主要功能:
· Load() – 加载.NET程序集字节数组或base64编码的字节数组。
· AssemblyExecute() – 加载.NET程序集字节数组或base64编码的字节数组,并使用反射在指定类型中使用指定的参数执行指定的方法。
SharpSploit.Execution.PE
SharpSploit.Execution.PE这个类计划是用于加载任意的PE文件。目前,它实际上只作为Mimikatz PE的加载器。这个类是@subtee的PE加载器的改编版本,用于支持任意PE文件的加载。顺便提醒一下,我在使用这个类的时候没有成功的加载过任意PE文件,所以你的实际操作可能和我的会有所不同。我希望这个类的功能最终能够得到充分实现。
SharpSploit.Execution.PE类包括了以下主要功能:
· Load() – 使用指定的字节数组加载PE。(需要管理员权限)
· GetFunctionExport() – 获取指向已加载的PE中导出函数的指针。之后,指针可用于执行PE中的功能。
SharpSploit.Execution.Shell
SharpSploit.Execution.Shell类包括了用于执行“Shell”(cmd.exe)命令和PowerShell命令和脚本的的方法。可以作为备用用户来执行shell命令(假设你具有有效的密码),类似于在Windows本地文件中的runas.exe可执行文件。
这个PowerShellExecute()功能让我感到特别兴奋。默认情况下,PowerShellExecute()函数使用了@mattifestation的AMSI绕过方式和@tifkin_的PowerShell日志记录绕过方式(绕过ScriptBlock日志记录和模块日志记录)。以前通过PowerShell执行某些类型的绕过的时候会遇到绕过方式本身被记录或被AMSI扫描的问题,这就造成了一些是“先有的鸡”还是“先有的蛋”的问题。通过使用C#,我们可以在执行任何PowerShell之前在C#中执行这些绕过,从而实现无日志和无AMSI的PowerShell执行!
SharpSploit.Execution.Shell类包含了以下主要功能:
· PowerShellExecute() – 使用System.Management.Automation.dll执行指定的PowerShell代码,并绕过AMSI,ScriptBlock日志记录和模块日志记录(但不转录日志记录)。
· ShellExecute() – 执行指定的Shell命令,可选择使用备用用户名和密码。等价于ShellExecuteWithPath(ShellCommand, "C:\\WINDOWS\\System32")
· ShellExecuteWithPath() – 从指定目录执行指定的Shell命令,可选择使用备用用户名和密码。
SharpSploit.Execution.ShellCode
SharpSploit.Execution.ShellCode类包括了用于执行shellcode的方法。Shellcode执行是通过将其复制到固定内存,使用Win32.Kernel32.VirtualProtect()修改内存权限并通过.NET delegate来完成执行。该类是在@enigma0x3编写的代码上实现的。
SharpSploit.Execution.ShellCode类包括了以下主要功能:
· ShellCodeExecute()- 通过将指定的shellcode字节数组复制到固定内存,使用Win32.Kernel32.VirtualProtect()修改内存权限并使用.NET delegate来执行指定的shellcode字节数组。
SharpSploit.Execution.Win32
SharpSploit.Execution.Win32是一个比较大的库,其中包含了SharpSploit的各种功能中使用的Win32 API函数的PInvoke签名和结构。www.pinvoke.net是实现此类的宝贵资源。我不会在本文中记录所有的签名,但你可以在Win32.cs文件中查看这些签名。
SharpSploit.LateralMovement
SharpSploit.LateralMovement命名空间包括了允许在远程计算机上执行任何类型的代码的类。目前,只有WMI横向移动的功能,但其他的功能将很快到来!
SharpSploit.LateralMovement.WMI
SharpSploit.LateralMovement.WMI类包含了基本的WMI横向移动功能。目前,唯一的功能是使用WMI的Win32_Process.Create方法并指定用户名和密码在远程系统上生成进程。
SharpSploit.LateralMovement.WMI类目前仅包括下列主要功能:
· WMIExecute() – 使用Win32_Process并指定登录凭据在远程系统上创建进程。
测试和文档
有关SharpSploit的完整的文档,请访问https://sharpsploit.cobbr.io/api/index.html!
SharpSploit项目还包括了SharpSploit.Tests,单元测试万岁!我没有在这些单元测试中实现完全覆盖,但我仍在努力。我认为,如果我们作为一个安全社区可以尝试升级我们的软件开发游戏并包含攻击性项目的单元测试,那将是极好的。它们提供了很好的示例,向其他人说明了该如何使用我们的工具集,同时提升了代码质量,并对贡献者很有用。
更多待办事项
本文只是SharpSploit的一个开始!你会注意到我在上面的描述中提到了很多需要在SharpSploit中实现的补充功能。我打算继续努力和维护SharpSploit,所以希望你很快就能看到很多的更新功能。
.NET 防御
本文确实是一个通过介绍SharpSploit 来阐述.NET攻击的文章,但是至少我会谈及.NET的防守面。在进行了一些自我教育之后,我会计划一个更全面的防御性博客文章作为后续的跟进。
要开始讨论.NET的防御,澄清术语很重要。我在这篇文章中几乎可以互换的使用“.NET”和“C#”,但是这里有一个微妙的区别。.NET框架是Windows的“托管代码”的库和运行时。“托管代码”是编译为CIL(通用中间语言,以前称为“MSIL”)的任何代码,将由CLR(公共语言运行时)管理,它是.NET框架的运行时并将CIL转换为“原生”的机器代码。C#是使用编译为CIL的托管代码的语言示例。此外,C#专门针对.NET而创建,它的对象模型与.NET对象模型是对齐的。其他可以编译为CIL的语言(因此可以在.NET框架下执行)包括VB.NET和JScript.NET。
因此,虽然我们从攻击性方面谈了很多关于C#的内容,但从防守的角度来看,我们真正关心的是.NET。具体来说,我们关心的是CLR解释的CIL代码。有一个坏消息是,传统上,防御者对.NET代码中发生的事情没有多少视角。即使他们这样做,也可能很难识别出恶意的.NET。事实上,在@blowdart发布的这条推文中,首先让我对攻击性.NET感到兴奋:
好消息是,这似乎正在发生变化。我在本文的开头提到了这一点,但似乎.NET optics目前正在开发中(由@mattifestation发现):
但是,据我所知,微软尚未就如何利用这些optics提供官方指导。虽然希望我们能得到一些指导和文件,但似乎这些工作仍在进行中。
没有这些optics,我们还有其他选择吗?好消息是,在某些时候没有磁盘读写的情况下执行.NET的方法仍然很少。如果你可以从磁盘恢复.NET程序集,很容易将程序集逆向为源代码并开始识别关键指标(CIL代码仍然是字节码!)。
执行恶意.NET程序集的最简单和最流行的方法是利用System.Reflection.Assembly.Load()方法。那么攻击者将如何执行此方法来启动恶意的.NET程序集呢?通常情况下,无论是通过powershell.exe还是通过基于scriptlet的执行技术,例如regsvr32.exe和wmic.exe(@tiraniddo 开发的DotNetToJScript项目中有相应的示例代码)。虽然这些基于scriptlet的技术确实能够执行远程托管的scriplet,但这仍然导致scriptlet在可预测的位置下进行磁盘读写,路径是%LOCALAPPDATA%\Microsoft\Windows\Temporary Internet Files\(我不确定所有的red teamers是否都已经明白)。这是脱离了powershell.exe在不进行磁盘读写的情况下执行.NET程序集的最后一种真正可用的方式,PowerShell具有出色的日志记录功能,可确保你在ScriptBlock日志中捕获程序集!从磁盘或日志中捕获组件后,你将能够轻松地对其进行逆向并使用.NET调试器(例如dnSpy)进行源码分析。
我希望这是一个像样的,而不是简短的描述如何检测恶意的.NET。再次说明,一旦我进一步的进行了自我教育,我会尝试在后续发表更详细的文章。
结论
本文只是SharpSploit的一个开始!你会注意到我在上面的描述中提到了很多需要在SharpSploit中实现的补充功能。我打算继续努力和维护SharpSploit,所以希望你很快就能看到很多的更新功能。
我希望其他人能够觉得SharpSploit确实有帮助,特别是那些试图从PowerShell多样化他们的工具集的人。正如我在本文开头所暗示的那样,SharpSploit是我在过去几个月里一直在开发的一系列C#工具中的第一个,所以期待在这里看到更多!
信任和感谢
我辜负了很多人的信任。SharpSploit的功能中几乎没有一个是真正的原创作品。SharpSploit移植了其他人用PowerShell编写的许多模块,利用其他人发现的技术,并借用了其他C#项目的想法和代码。话虽如此,但我还是要感谢以下人员为该项目做出的贡献:
· Justin Bui(@youslydawg) – 贡献了SharpSploit.Enumeration.Host.CreateProcessDump()功能。
· Matt Graeber(@mattifestation),Will Schroeder(@harmj0y)和Ruben(@FuzzySec) – 感谢他们在PowerSploit上的付出和分享。
· Will Schroeder(@harmj0y) – PowerView项目。
· Alexander Leary(@0xbadjuju) – Tokenvator项目。
· James Foreshaw(@tiraniddo) – 因为他发现了这里记录的令牌复制绕过UAC的技术。
· Matt Nelson(@enigma0x3) – 用于令牌复制绕过UAC的Invoke-TokenDuplication实现,以及他的C# 执行shellcode的方法。
· Benjamin Delpy(@gentilkiwi) – 为Mimikatz项目。
· Casey Smith(@subtee) – C# PE加载器。
· Chris Ross(@xorrior) – 他在这里公布了Mimikatz PE加载器的实现。
· Matt Graeber(@mattifestation) – 他在这里公布了AMSI绕过方法。
· Lee Christensen(@tifkin_) – 他在这里公布了PowerShell日志记录绕过方法。
· www.pinvoke.net的所有贡献者- 大部分PInvoke签名。