导语:本文介绍了如何使用Windbg和Direct Connect Interface(DCI)调试整个操作系统,包括系统管理模式(SMM)代码 ,我将调试我报告的kernel到SMM的本地特权提升漏洞作为例子。
本文介绍了如何使用Windbg和Direct Connect Interface(DCI)调试整个操作系统,包括系统管理模式(SMM)代码 ,我将调试我报告的kernel到SMM的本地特权提升漏洞作为例子。
有关该漏洞及其影响的更多详细信息,请参考GitHub存储库,这篇文章重点介绍DCI和Windbg。
https://github.com/tandasat/SmmExploit
0x01 DCI介绍
DCI是一种用于内核/固件调试和逆向的非常强大的技术,而针对WinDbg的英特尔调试扩展程序使我们可以通过Windbg的命令和GUI使用它,这样可以加快对它的研究。
直接连接接口(DCI)是Intel硬件提供的调试接口,它使开发人员无需依赖软件提供的调试机制即可调试整个系统,例如Windows的内核调试子系统和固件(EDK2)的Debug Agent。
由于DCI由硬件实现,因此使用此接口的调试器能够调试更大范围的代码,包括复位向量和在系统管理模式(SMM)上运行的代码。例如,这使得DCI成为开发和逆向固件的强大工具。
有关DCI技术的更全面概述,我强烈建议你花些时间观看Intel的视频并阅读Slim Bootloader团队的文档:·
· 英特尔®System Studio 2018中的系统调试和跟踪介绍
DCI在Skylake(第6代)或更高版本以及某些Atom和Xeon型号上可用。但是,较老的一代仅支持DCI OOB的连接类型,并且需要昂贵的适配器,如下表所示。
如果你的目标系统是第7代或更高版本,则支持DCI DbC,而你所需要购买的只是不需要VBus的USB电缆。购买ITPDCIAMAM1M 或DataPro一个,如果目标系统具有A型USB端口,或ITPDCIAMCM1M 为C型USB端口。我建议同时购买两者,因为我有一台只能与C型端口一起使用的设备。
如果你的目标系统是第六代,则不支持DbC,并且你需要购买昂贵的适配器CCA(EXIBSSBADAPTOR),允许你从复位向量中调试代码,而DbC不支持此功能。
DCI连接类型 (摘自Intel使用DCI和USB 3.0调试Intel固件)
对主机系统没有明显的要求,如果需要,可以使用USB-C-to-A适配器。
支持模型的完整列表可以在Intel System Debugger的发行说明中找到,我们将在稍后进行介绍。
如果设置了IA32_DEBUG_INTERFACE [0],则启用DCI。使用内核调试器或 RWEverything 进行检查。出于明显的原因,默认情况下应在市场上的系统上禁用DCI。如果不是,请向OEM报告,这是一个漏洞(请参阅CVE-2018-3652)。
0x02 如何启用DCI
有两种方法可以执行此操作:更改BIOS设置或使用RU.efi修补NVRAM。
BIOS设置偶尔会提供启用DCI的选项。我已经看到了几个用于此目的的配置名称,如下所示。
· CPU运行控制
· 启用HDCIEN
我遇到的情况是该配置可用,但对IA32_DEBUG_INTERFACE没有影响。
DCI的BIOS设置通常隐藏在生产系统中,但是可以通过覆盖存储设置值的NVRAM来实现与更改设置相同的效果。这是一个有点复杂的过程,但是在下面列出的多篇文章中对此进行了解释。
1. 使用Chipsec等软件提取BIOS
2. 提取模块899407D7-99FE-43D8-9A21-79EC328CAC21UEFITool
3. 使用IFR Extractor提取可读的BISO菜单实现的表示形式
4. 查找以下设置名称的偏移量和要设置的值,用=>表示
· 调试接口=>启用(1)
· 调试接口锁定=>禁用(0)
· DCI启用(HDCIEN)=>启用(1)
· 平台调试同意=>启用(DCI OOB + [DbC])(1)
· CPU运行控制=>启用(1)
· CPU运行控制锁定=>禁用(0)
· PCH跟踪集线器启用模式=>主机调试器(2) (取决于BIOS)
1. 下载RU.efi,将系统启动到UEFI Shell中并启动RU.efi
2. Alt + =,选择“设置”,然后更改找到的偏移值,提交更改并重新启动。
· 通过单步运行Coffee Lake-S硬件CPU调试UEFI代码
· そうだ,Intel DCIをしよう!& Intel DCI続编(资料まとめ)
有些设备没有安装程序模块,有些设备具有但未反映对IA32_DEBUG_INTERFACE的更改,而某些设备却更改了IA32_DEBUG_INTERFACE,但无论如何都不允许我连接。
Intel Flash Image Tool(FIT)是另一个可以修补固件并启用DCI的工具。
0x03 如何通过DCI连接目标
主机上需要安装Intel System Debugger才能进行连接。英特尔系统调试器是英特尔系统工作室(ISS)的一部分,可以从此链接下载。
· https://dynamicinstaller.intel.com/system-studio/
选择“获取完整的System Studio软件包”,然后下载“独立脱机安装程序”。
请注意,英特尔已从ISS过渡到其他产品集,并将系统调试器更名为Intel System Bring-up Toolkit,需要下载NDA。截至撰写本文时,以上下载链接仍然有效,但将来可能会关闭。
在安装时,请确保至少安装英特尔系统调试器。安装ISS后,你可以参考以下页面以通过ISS连接到目标:
· 使用英特尔®系统调试器调试基于EDK II的固件映像 (视频)
为了简单起见,我建议使用旧版本。可以用 如下文件
C:\ Program Files(x86)\ IntelSWTools \ sw_dev_tools \ system_debugger_2020 \ system_debug_legacy \ xdb.bat
· 英特尔系统调试器目标指示器有助于识别可能的原因。
· 并非所有端口都能正常工作。例如,只能通过C型端口调试我的设备之一,尝试其他端口,有时会重启。
0x04 WinDbg的Intel调试扩展
安装程序应该已经安装了扩展程序,该扩展程序使你可以通过DCI使用Windbg调试目标。要使用扩展,需要使用以下命令在主机上注册扩展调试接口(EXDI)IPC COM服务器:
---- > cd "C:\Program Files (x86)\IntelSWTools\sw_dev_tools\system_debugger_2020\windbg-ext\iajtagserver\intel64" > regsvr32 ExdiIpc.dll ----
然后,重新引导主机系统,从开始菜单启动英特尔系统调试器开发人员 Shell,然后键入“ windbg_dci”
成功建立连接后,键入“ windbg()”
Windbg启动后,显示反汇编和注册值,并且如果成功,则接受大多数命令,例如.reload。
尽管该扩展程序确实像标准的内核调试会话那样使用Windows特定位,但它并不依赖于某些Kd标志所指示的内核调试机制。如果你正在寻找隐秘的内核调试工具,那么DCI就是你的理想之选。
0x05 调试SMM漏洞
通过DCI调试Windows内核是可以的,但没有太大意义,我们调试SMM漏洞利用作为示例。
漏洞是SMI 0x40允许使用0x07覆盖任意SMRAM。该漏洞利用此原语来覆盖SMST全局变量中的函数指针, 以实现SMM中的任意代码执行。
SMST的地址被设计泄漏到了SMRAM外部,Ring0代码可以从UEFI运行时代码区域中搜索 具有独特的“ smmc”签名的SMM核心私有数据,然后在其中找到泄漏的指针。
SMST的地址在SMRAM外部泄漏
该利用程序利用了这一点,并在不依赖BIOS和系统版本的情况下在SMRAM中定位了函数指针的地址。有关漏洞和利用的更多详细信息,请参见GitHub。
当漏洞利用在打了补丁的系统上执行时,它会调试打印SMRAM的范围,SMM内核和SMST的地址,但无法运行Shellcode。
用Windbg调试漏洞并执行漏洞利用代码。
1. 加载“ dt”命令的符号,
2. 中断SMM,
3. 提取并分析SMRAM,
4. 在SMI 0x40处理程序上设置断点,
5. 调试和修改执行以模拟成功利用。
首先,进入Windbg,并为漏洞利用调用中的一个NT API设置一个断点。
---- 0: kd> bp nt!ExGetSystemFirmwareTable 0: kd> g ----
然后,在目标系统上重新运行该漏洞利用程序,重新加载漏洞利用程序的符号。
---- 0: kd> .reload demo.sys ... ModLoad: fffff806`4d860000 fffff806`4d869000 \??\C:\Users\tanda\Desktop\demo.sys Loading symbols for fffff806`4d860000 demo.sys -> demo.sys 0: kd> dt demo!SMM_CORE_PRIVATE_DATA +0x000 Signature : Uint8B ... ----
在另一个windbg_dci会话上,启用SMM入口中断并恢复系统,系统将再次进入调试器。
---- [SKL_C0_T0] Hardware Breakpoint Execution breakpoint #0001 at [0x10:fffff8064f795b00] [SKL_C0_T1] HLT Instruction Break at [0x38:000000000009e1e5] [SKL_C1_T0] HLT Instruction Break at [0x38:000000000009e1e5] [SKL_C1_T1] HLT Instruction Break at [0x38:000000000009e1e5] >>> itp.cv.smmentrybreak = 1 >>> go() CPUs Resuming execution >>> [SKL_C0_T0] Resuming [SKL_C0_T1] Resuming [SKL_C1_T0] Resuming [SKL_C1_T1] Resuming >>> [SKL_C0_T0] SMM entry Break at [0xcb00:0000000000008000] [SKL_C0_T1] SMM entry Break at [0xcb80:0000000000008000] [SKL_C1_T0] SMM entry Break at [0xcc00:0000000000008000] [SKL_C1_T1] SMM entry Break at [0xcc80:0000000000008000] >>> ----
在Windbg会话上,通过检查RIP为0x8000和AL为0x40来确认这是SMI 0x40。然后,根据先前运行的debug打印的范围转储SMRAM的内容。
---- Break instruction exception - code 80000003 (first chance) cb00:00000000`00008000 bb9180662e mov ebx,2E668091h 0: kd> r rax=0000000000000040 rbx=0000000000000000 rcx=ffff808cca4df080 rdx=00000000000000b2 rsi=ffff808cd5aff000 rdi=ffff808cd746b7d0 rip=0000000000008000 rsp=000000002c127668 rbp=0000000000000000 r8=0000000000098367 r9=0000000000000004 r10=00000000ffffffff r11=ffff808cd74f6040 r12=ffffffff80001998 r13=0000000000000002 r14=fffff8064d7f52f8 r15=ffff808cd5aff000 ... 0: kd> .writemem C:\temp\smram_88400000_88800000.bin 0`88400000 0`88800000-1 Writing 400000 bytes.........(snip)... ----
下载并运行由Dmytro Oleksiuk(aka Cr4sh,@d_olex)开发的SMRAM脚本,将显示SMI 0x40处理程序的地址。
---- $ wget https://raw.githubusercontent.com/tandasat/smram_parse/master/smram_parse.py $ python3 smram_parse.py smram_88400000_88800000.bin ... SW SMI HANDLERS: ... 0x88700110: SMI = 0x40, addr = 0x886e5c68, image = 0x886e5000 ... ----
在Windbg会话中,还可以发现函数能指向SMRAM外部。。
---- 0:kd> uf 0`886e5c68 00000000`886e5c68 4053 push rbx 00000000`886e5c6a 4883ec20 sub rsp,20h 00000000`886e5c6e 0fb704250e040000 movzx eax,word ptr [40Eh] 00000000`886e5c76 ba67000000 moveded mov byte ptr [00000000`886e6f40],1 00000000`886e5c82 c1e004 shl eax,4 00000000`886e5c85 0504010000 add eax,104h 00000000`886e5c8a 8b18 mov ebx,dword ptr [rax] 0:kd> g 0`886e5c8a \----
在下面的反汇编中,你可以看到SMRAM外部的0x104被引用,并包含要覆盖的地址。你还可以发现后续代码会覆盖地址的内容。
---- 0038:00000000`886e5c8a 8b18 mov ebx,dword ptr [rax] ds:0018:00000000`00000104=887f97fe 0038:00000000`886e5c8c 488bcb mov rcx,rbx 0038:00000000`886e5c8f e8bc0d0000 call 00000000`886e6a50 ... 0038:00000000`886e5c9e c6430207 mov byte ptr [rbx+2],7 ds:0018:00000000`887f9800=8c 0038:00000000`886e5ca2 eb10 jmp 00000000`886e5cb4 ----
漏洞利用程序如何计算该地址?该漏洞利用程序能够在0x87f21390处找到SMM核心私有数据。让我们“ dt”地址以确认该地址中确实存在SMM专用核心数据,以及泄漏的SMST地址。
---- 0: kd> db 0`87f21390 l10 00000000`87f21390 73 6d 6d 63 00 00 00 00-18 67 4f 84 00 00 00 00 smmc.....gO..... 0: kd> dt demo!SMM_CORE_PRIVATE_DATA 0`87f21390 +0x000 Signature : 0x636d6d73 +0x008 SmmIplImageHandle : 0x00000000`844f6718 Void +0x010 SmramRangeCount : 3 +0x018 SmramRanges : 0x00000000`844f2d18 Void +0x020 SmmEntryPoint : 0x00000000`887f9d7c Void +0x028 SmmEntryPointRegistered : 0x1 '' +0x029 InSmm : 0x1 '' +0x030 Smst : 0x00000000`887f9730 EFI_SMM_SYSTEM_TABLE2 +0x038 CommunicationBuffer : (null) +0x040 BufferSize : 0x20 +0x048 ReturnStatus : 0 +0x050 PiSmmCoreImageBase : _LARGE_INTEGER 0x1 +0x058 PiSmmCoreImageSize : 0xfffff806`53427320 +0x060 PiSmmCoreEntryPoint : _LARGE_INTEGER 0xfffff806`53427980 ----
该漏洞利用将0xd0添加到SMST的地址,因为它的布局是已知的。如下所示,偏移量0xd0是函数指针SmmLocateProtocol。
---- 0: kd> db 0`887f9730 l10 00000000`887f9730 53 4d 53 54 00 00 00 00-1e 00 01 00 18 00 00 00 SMST............ 0: kd> dt demo!EFI_SMM_SYSTEM_TABLE2 0`887f9730 +0x000 Hdr : EFI_TABLE_HEADER +0x018 SmmFirmwareVendor : (null) +0x020 SmmFirmwareRevision : 0 +0x028 SmmInstallConfigurationTable : 0x00000000`887fa1b0 Void +0x030 SmmIo : EFI_SMM_CPU_IO2_PROTOCOL +0x050 SmmAllocatePool : 0x00000000`887fb61c Void +0x058 SmmFreePool : 0x00000000`887fb744 Void +0x060 SmmAllocatePages : 0x00000000`887fbd20 Void +0x068 SmmFreePages : 0x00000000`887fbe30 Void +0x070 SmmStartupThisAp : 0x00000000`887e0af0 Void +0x078 CurrentlyExecutingCpu : 0 +0x080 NumberOfCpus : 4 +0x088 CpuSaveStateSize : 0x00000000`887ddd50 -> 0x400 +0x090 CpuSaveState : 0x00000000`887ddf50 -> 0x00000000`887dac00 Void +0x098 NumberOfTableEntries : 6 +0x0a0 SmmConfigurationTable : 0x00000000`887e5810 Void +0x0a8 SmmInstallProtocolInterface : 0x00000000`887fb928 Void +0x0b0 SmmUninstallProtocolInterface : 0x00000000`887fbaf4 Void +0x0b8 SmmHandleProtocol : 0x00000000`887fbc1c Void +0x0c0 SmmRegisterProtocolNotify : 0x00000000`887fbf2c Void +0x0c8 SmmLocateHandle : 0x00000000`887fa058 Void +0x0d0 SmmLocateProtocol : 0x00000000`887f9f8c Void +0x0d8 SmiManage : 0x00000000`887fb2fc Void +0x0e0 SmiHandlerRegister : 0x00000000`887fb3d4 Void +0x0e8 SmiHandlerUnRegister : 0x00000000`887fb48c Void ----
因此,SMI 0x40将要覆盖SmmLocateProtorol字段的内容。
由于我们正在调试的代码不再容易受到攻击,因此让我们通过将RIP更改为MOV指令来模拟成功的利用。在完成该指令之后,我们可以确认地址内容已更改为0x07。
---- 0: kd> dp 0`887f9800 l1 00000000`887f9800 00000000`887f9f8c 0: kd> r rip=0`886e5c9e 0: kd> t 0: kd> dp 0`887f9800 l1 00000000`887f9800 00000000`887f9f07 ----
重复此步骤4次后,该地址将被覆盖到SMRAM外部的0x07070707。
---- 0: kd> dp 0`887f9800 l1 00000000`887f9800 00000000`07070707 0: kd> dt demo!EFI_SMM_SYSTEM_TABLE2 0`887f9730 ... +0x0c8 SmmLocateHandle : 0x00000000`887fa058 Void +0x0d0 SmmLocateProtocol : 0x00000000`07070707 Void +0x0d8 SmiManage : 0x00000000`887fb2fc Void ... ----
让我们再运行一次目标,以验证利用成功。下一个SMI是0xdf,它将调用SmmLocateProtocol。
---- 0: kd> g Break instruction exception - code 80000003 (first chance) cb00:00000000`00008000 bb9180662e mov ebx,2E668091h 0: kd> r rax=00000000000000df rbx=0000000000000000 rcx=fffff8064d544180 rdx=ffffed842b8400b2 rsi=ffff808cd68ff000 rdi=ffff808cd521e7c0 rip=0000000000008000 rsp=000000002b8476e0 rbp=0000000000000000 r8=0000000000000001 r9=ffff808cd7345040 r10=6c6c656873204d4d r11=ffff808ccc4901e8 r12=ffffffff80002b6c r13=0000000000000002 r14=fffff8064d8652f8 r15=ffff808cd68ff000 ... 0: kd> uf 07070707 00000000`07070707 90 nop 00000000`07070708 90 nop 00000000`07070709 90 nop 00000000`0707070a 90 nop 00000000`0707070b 90 nop 00000000`0707070c 90 nop 00000000`0707070d 90 nop 00000000`0707070e 90 nop 00000000`0707070f 90 nop 00000000`07070710 4c89442418 mov qword ptr [rsp+18h],r8 00000000`07070715 4889542410 mov qword ptr [rsp+10h],rdx 00000000`0707071a 48894c2408 mov qword ptr [rsp+8],rcx 00000000`0707071f 4883ec28 sub rsp,28h 00000000`07070723 48c744240800000000 mov qword ptr [rsp+8],0 00000000`0707072c b99e000000 mov ecx,9Eh 00000000`07070731 0f32 rdmsr 0: kd> bp 0`07070707 0: kd> g Breakpoint 0 hit 0038:00000000`07070707 90 nop ----
如预期的那样,目标在0x07070707进入调试器。一旦执行了shellcode代码,就可以检查其存储在0x0的输出。
---- 0: kd> dx *(demo!HOOKED_SMM_LOCATE_PROTOCOL_PARAMETER_BLOCK*)0 *(demo!HOOKED_SMM_LOCATE_PROTOCOL_PARAMETER_BLOCK*)0 [Type: HOOKED_SMM_LOCATE_PROTOCOL_PARAMETER_BLOCK] [+0x000] Untouched : 0x1588748418 [Type: unsigned __int64] [+0x008] Smbase : 0x887cb000 [Type: unsigned __int64] [+0x010] SmmFeatureControl : 0x1 [Type: unsigned __int64] [+0x018] SmmMcaCap : 0xc00000000000000 [Type: unsigned __int64] [+0x020] Eptp : 0x0 [Type: unsigned __int64] [+0x028] HvPatchedAddress : 0x0 [Type: unsigned __int64] ----
0x06 参考资料
· 使用bcdedit将目标系统设为单核,我发现调试多核配置是不稳定的。
· 在调试之前,请在目标上完全禁用Hyper-V。即使禁用了VBS,Hyper-V也会通过看门狗错误检查使系统崩溃。
· DCI提供了中断VM退出/进入功能,但我无法使其正常工作。
· SMI由EDK2中的以下函数处理,你的系统可能完全相同。
· _SmiEntryPoint(SmiEntry.nasm)
· Windbg和Intel System Debugger都无法在SMM的开头正确显示16位模式代码,只需继续单步执行,直到偏移量0x90左右即可。
· evil-maid-firmware-attacks-using-usb-debug
· open-source-firmware-explorations-using-dci-on-the-aaeon-up-squared-board
· 在UP Squared上启用DCI。该设备的最详细的分步说明。优秀的博客。
· 使用DCI和Windbg逆向Windows
本文翻译自:http://standa-note.blogspot.com/2021/03/debugging-system-with-dci-and-windbg.html如若转载,请注明原文地址: