Hi!请登陆

利用 DCI 与 Windbg 调试器调试 SMM 模式的代码

2021-5-7 87 5/7

本文介绍了如何使用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中的系统调试和跟踪介绍

·使用英特尔(R)SVT CCA进行源代码级调试

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 =,选择"设置",然后更改找到的偏移值,提交更改并重新启动。

·在技嘉BKi5HA-7200上启用DCI调试

·通过单步运行Coffee Lake-S硬件CPU调试UEFI代码

·使用RU.EFI修改BIOS

·そうだ,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:ProgramFiles(x86)IntelSWToolssw_dev_toolssystem_debugger_2020windbg-extiajtagserverintel64" >regsvr32ExdiIpc.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>bpnt!ExGetSystemFirmwareTable 0:kd>g ----

然后,在目标系统上重新运行该漏洞利用程序,重新加载漏洞利用程序的符号。

---- 0:kd>.reloaddemo.sys ... ModLoad:fffff806`4d860000fffff806`4d869000??C:UserstandaDesktopdemo.sys Loadingsymbolsforfffff806`4d860000demo.sys->demo.sys 0:kd>dtdemo!SMM_CORE_PRIVATE_DATA
0x000Signature:Uint8B ... ----

在另一个windbg_dci会话上,启用SMM入口中断并恢复系统,系统将再次进入调试器。

---- [SKL_C0_T0]HardwareBreakpointExecutionbreakpoint#0001at[0x10:fffff8064f795b00] [SKL_C0_T1]HLTInstructionBreakat[0x38:000000000009e1e5] [SKL_C1_T0]HLTInstructionBreakat[0x38:000000000009e1e5]
[SKL_C1_T1]HLTInstructionBreakat[0x38:000000000009e1e5] >>>itp.cv.smmentrybreak=1 >>>go() CPUsResumingexecution >>> [SKL_C0_T0]Resuming [SKL_C0_T1]Resuming
[SKL_C1_T0]Resuming [SKL_C1_T1]Resuming >>> [SKL_C0_T0]SMMentryBreakat[0xcb00:0000000000008000] [SKL_C0_T1]SMMentryBreakat[0xcb80:0000000000008000]
[SKL_C1_T0]SMMentryBreakat[0xcc00:0000000000008000] [SKL_C1_T1]SMMentryBreakat[0xcc80:0000000000008000] >>> ----

在Windbg会话上,通过检查RIP为0x8000和AL为0x40来确认这是SMI 0x40。然后,根据先前运行的debug打印的范围转储SMRAM的内容。

---- Breakinstructionexception-code80000003(firstchance) cb00:00000000`00008000bb9180662emovebx,2E668091h 0:kd>r rax=000000000000040rbx=0000000000000000rcx=ffff808cca4df080
rdx=00000000000000b2rsi=ffff808cd5aff000rdi=ffff808cd746b7d0 rip=0000000000008000rsp=000000002c127668rbp=0000000000000000 r8=0000000000098367r9=0000000000000004r10=00000000ffffffff
r11=ffff808cd74f6040r12=ffffffff80001998r13=0000000000000002 r14=fffff8064d7f52f8r15=ffff808cd5aff000 ... 0:kd>.writememC:tempsmram_88400000_88800000.bin0`884000000`88800000-1
Writing400000bytes.........(snip)... ----

下载并运行由Dmytro Oleksiuk(aka Cr4sh,@d_olex)开发的SMRAM脚本,将显示SMI 0x40处理程序的地址。

---- $wgethttps://raw.githubusercontent.com/tandasat/smram_parse/master/smram_parse.py $python3smram_parse.pysmram_88400000_88800000.bin ... SWSMIHANDLERS: ...
0x88700110:SMI=0x40,addr=0x886e5c68,image=0x886e5000 ... ----

在Windbg会话中,还可以发现函数能指向SMRAM外部。。

---- 0:kd>uf0`886e5c68 00000000`886e5c684053pushrbx 00000000`886e5c6a4883ec20subrsp,20h 00000000`886e5c6e0fb704250e040000movzxeax,wordptr[40Eh] 00000000`886e5c76ba67000000
movededmovbyteptr[00000000`886e6f40],1 00000000`886e5c82c1e004shleax,4 00000000`886e5c850504010000addeax,104h 00000000`886e5c8a8b18movebx,dwordptr[rax] 0:kd>g0`886e5c8a ----

在下面的反汇编中,你可以看到SMRAM外部的0x104被引用,并包含要覆盖的地址。你还可以发现后续代码会覆盖地址的内容。

---- 0038:00000000`886e5c8a8b18movebx,dwordptr[rax]ds:0018:00000000`00000104=887f97fe 0038:00000000`886e5c8c488bcbmovrcx,rbx 0038:00000000`886e5c8fe8bc0d0000call00000000`886e6a50 ...
0038:00000000`886e5c9ec6430207movbyteptr[rbx 2],7ds:0018:00000000`887f9800=8c 0038:00000000`886e5ca2eb10jmp00000000`886e5cb4 ----

漏洞利用程序如何计算该地址?该漏洞利用程序能够在0x87f21390处找到SMM核心私有数据。让我们" dt"地址以确认该地址中确实存在SMM专用核心数据,以及泄漏的SMST地址。

---- 0:kd>db0`87f21390l10 00000000`87f21390736d6d6300000000-18674f8400000000smmc.....gO..... 0:kd>dtdemo!SMM_CORE_PRIVATE_DATA0`87f21390 0x000Signature:0x636d6d73
0x008SmmIplImageHandle:0x00000000`844f6718Void 0x010SmramRangeCount:3 0x018SmramRanges:0x00000000`844f2d18Void 0x020SmmEntryPoint:0x00000000`887f9d7cVoid 0x028SmmEntryPointRegistered:0x1''
0x029InSmm:0x1'' 0x030Smst:0x00000000`887f9730EFI_SMM_SYSTEM_TABLE2 0x038CommunicationBuffer:(null) 0x040BufferSize:0x20 0x048ReturnStatus:0 0x050PiSmmCoreImageBase:_LARGE_INTEGER0x1
0x058PiSmmCoreImageSize:0xfffff806`53427320 0x060PiSmmCoreEntryPoint:_LARGE_INTEGER0xfffff806`53427980 ----

该漏洞利用将0xd0添加到SMST的地址,因为它的布局是已知的。如下所示,偏移量0xd0是函数指针SmmLocateProtocol。

---- 0:kd>db0`887f9730l10 00000000`887f9730534d535400000000-1e00010018000000SMST............ 0:kd>dtdemo!EFI_SMM_SYSTEM_TABLE20`887f9730 0x000Hdr:EFI_TABLE_HEADER
0x018SmmFirmwareVendor:(null) 0x020SmmFirmwareRevision:0 0x028SmmInstallConfigurationTable:0x00000000`887fa1b0Void 0x030SmmIo:EFI_SMM_CPU_IO2_PROTOCOL 0x050SmmAllocatePool:0x00000000`887fb61cVoid
0x058SmmFreePool:0x00000000`887fb744Void 0x060SmmAllocatePages:0x00000000`887fbd20Void 0x068SmmFreePages:0x00000000`887fbe30Void 0x070SmmStartupThisAp:0x00000000`887e0af0Void
0x078CurrentlyExecutingCpu:0 0x080NumberOfCpus:4 0x088CpuSaveStateSize:0x00000000`887ddd50->0x400 0x090CpuSaveState:0x00000000`887ddf50->0x00000000`887dac00Void 0x098NumberOfTableEntries:6
0x0a0SmmConfigurationTable:0x00000000`887e5810Void 0x0a8SmmInstallProtocolInterface:0x00000000`887fb928Void 0x0b0SmmUninstallProtocolInterface:0x00000000`887fbaf4Void
0x0b8SmmHandleProtocol:0x00000000`887fbc1cVoid 0x0c0SmmRegisterProtocolNotify:0x00000000`887fbf2cVoid 0x0c8SmmLocateHandle:0x00000000`887fa058Void 0x0d0SmmLocateProtocol:0x00000000`887f9f8cVoid
0x0d8SmiManage:0x00000000`887fb2fcVoid 0x0e0SmiHandlerRegister:0x00000000`887fb3d4Void 0x0e8SmiHandlerUnRegister:0x00000000`887fb48cVoid ----

因此,SMI 0x40将要覆盖SmmLocateProtorol字段的内容。

由于我们正在调试的代码不再容易受到攻击,因此让我们通过将RIP更改为MOV指令来模拟成功的利用。在完成该指令之后,我们可以确认地址内容已更改为0x07。

---- 0:kd>dp0`887f9800l1 00000000`887f980000000000`887f9f8c 0:kd>rrip=0`886e5c9e 0:kd>t 0:kd>dp0`887f9800l1 00000000`887f980000000000`887f9f07 ----

重复此步骤4次后,该地址将被覆盖到SMRAM外部的0x07070707。

---- 0:kd>dp0`887f9800l1 00000000`887f980000000000`07070707 0:kd>dtdemo!EFI_SMM_SYSTEM_TABLE20`887f9730 ... 0x0c8SmmLocateHandle:0x00000000`887fa058Void
0x0d0SmmLocateProtocol:0x00000000`07070707Void 0x0d8SmiManage:0x00000000`887fb2fcVoid ... ----

让我们再运行一次目标,以验证利用成功。下一个SMI是0xdf,它将调用SmmLocateProtocol。

---- 0:kd>g Breakinstructionexception-code80000003(firstchance) cb00:00000000`00008000bb9180662emovebx,2E668091h 0:kd>r rax=00000000000000dfrbx=0000000000000000rcx=fffff8064d544180
rdx=ffffed842b8400b2rsi=ffff808cd68ff000rdi=ffff808cd521e7c0 rip=0000000000008000rsp=000000002b8476e0rbp=0000000000000000 r8=0000000000000001r9=ffff808cd7345040r10=6c6c656873204d4d
r11=ffff808ccc4901e8r12=ffffffff80002b6cr13=0000000000000002 r14=fffff8064d8652f8r15=ffff808cd68ff000 ... 0:kd>uf07070707 00000000`0707070790nop 00000000`0707070890nop 00000000`0707070990nop
00000000`0707070a90nop 00000000`0707070b90nop 00000000`0707070c90nop 00000000`0707070d90nop 00000000`0707070e90nop 00000000`0707070f90nop 00000000`070707104c89442418movqwordptr[rsp 18h],r8
00000000`070707154889542410movqwordptr[rsp 10h],rdx 00000000`0707071a48894c2408movqwordptr[rsp 8],rcx 00000000`0707071f4883ec28subrsp,28h 00000000`0707072348c744240800000000movqwordptr[rsp 8],0
00000000`0707072cb99e000000movecx,9Eh 00000000`070707310f32rdmsr 0:kd>bp0`07070707 0:kd>g Breakpoint0hit 0038:00000000`0707070790nop ----

如预期的那样,目标在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中的以下函数处理,你的系统可能完全相同。

·SmiRendezvous(MpService.c)

·SmmEntryPoint(PiSmmCore.c)

·SmiManage(Smi.c)

·BSPHandler(MpService.c)

·_SmiEntryPoint(SmiEntry.nasm)

·Windbg和Intel System Debugger都无法在SMM的开头正确显示16位模式代码,只需继续单步执行,直到偏移量0x90左右即可。

·UEFI BIOS漏洞

·tapping-into-the-core

·UEFI_EXPLOITATION

·evil-maid-firmware-attacks-using-usb-debug

·open-source-firmware-explorations-using-dci-on-the-aaeon-up-squared-board

·在UP Squared上启用DCI。该设备的最详细的分步说明。优秀的博客。

·使用DCI EXDI会话调试Windows内核

·使用DCI和Windbg逆向Windows

·在Intel NUC的示例上利用AMI Aptio固件

相关推荐