执行摘要
2022 年 1 月下旬,社交媒体上的几份报告表明,一个新的 Microsoft Windows 提权漏洞 ( CVE-2022-21882 ) 正在被广泛利用。这些报告促使我们对 CVE-2022-21882 进行了分析,结果证明这是 Win32k.sys 用户模式回调函数xxxClientAllocWindowClassExtraBytes中的一个漏洞。2021 年,微软报告了一个非常相似的漏洞 ( CVE-2021-1732 ),并由微软修复。我们决定仔细研究这两个漏洞,以更好地理解每个漏洞中涉及的代码。在我们的初始分析中,我们想确定为什么 CVE-2021-1732 补丁不足以阻止 CVE-2022-21882。这是涵盖 Win32k 内部结构和一般利用的系列的第一部分,使用这两个漏洞及其相关的概念验证 (PoC) 作为示例。在这里,我们涵盖了大量的背景信息,包括由几位优秀研究人员进行的多年背景研究,以使读者了解 Win32k 的最新实现及其相关的利用方法。为了更深入地了解该主题,我们还建议阅读帖子末尾的所有链接参考资料。本系列中讨论的两个漏洞均由 Cortex XDR Anti-LPE 保护模块检测并阻止。这两个漏洞都是纯数据攻击,它们将 NT/Authority System 特权令牌复制到当前(利用)进程的令牌以进行特权升级。XDR Anti-LPE 模块监视这种特定类型的特权升级技术。CVE-2022-1732 和 CVE-2022-21882 简介
通过 Win32 API 和 Windows 内部机制编写了很多关于 Windows 开发的文章。然而,根据我们的经验,很少有安全相关资源涵盖通过图形用户界面 (GUI) 或其底层内部结构进行的开发。该接口在Win32k.sys、Win32kbase.sys和Win32kfull.sys中实现。因此,我们决定进行一些研究,以更好地了解 Windows GUI 内部结构和相关 API。我们阅读了过去 10 年左右编写的一些关于 Win32k 开发的白皮书,以及关于 Win32 API 的 Microsoft Developer Network (MSDN)文档。我们不想假定对所涉及的底层代码有任何专业知识水平。因此,为了便于理解所分析的两个漏洞以及其他Win32k.sys漏洞和利用,在我们的第一篇文章中,我们将介绍相关 API、对象和涉及的数据结构的一些背景知识。由于这些漏洞的利用和补丁绕过方法相对容易理解,我们选择了这两个最近的示例来浏览一些 Win32k 内部结构,以帮助人们了解通常如何利用它们来获取读/写原语。它还为我们提供了一个很好的机会来讨论Win32k.sys代码库中常见的 Win32k 攻击目标(用户模式回调)。在 Windows NT 4.0 之前,Microsoft 在称为客户端-服务器运行时子系统( CSRSS.exe )的用户模式进程中实现了 Win32 API 的 GUI 功能。然而,用户模式和内核模式之间的上下文切换在计算上是昂贵的并且需要大量的内存开销。为了消除这些问题并加快整个 Windows 操作系统的运行速度,Microsoft 决定将 Windows 子系统(Window Manager、GDI 和图形驱动程序)移至内核。这种转变始于 1996 年的 Windows NT 4.0。此更改是通过名为Win32k.sys的内核模式驱动程序实现的,该驱动程序位于现在称为内核模式 Windows 子系统中。Windows 子系统的用户模式组件仍然驻留在 CSRSS 中。虽然转向内核大大减少了所需的开销,但微软不得不求助于一些老把戏,例如在客户端地址空间的用户模式部分缓存管理数据结构。事实上,为了进一步避免上下文切换,一些管理结构历来专门存储在用户模式中。然而,为了消除内核地址泄漏,Microsoft 已开始实施使用这些结构的用户模式和内核模式副本的方法,以防止内核地址存储在用户模式结构中。此外,由于 Win32k 需要一种方法来访问这些用户模式结构并支持一些现有的用户模式功能,例如窗口挂钩,因此实现了用户模式回调以促进这些任务。“用户模式回调允许 Win32k 调用回用户模式并执行诸如调用应用程序定义的挂钩、提供事件通知以及将数据复制到用户模式或从用户模式复制数据等任务,”Tarjei Mandt 在一份详细的白皮书中写道。他的研究还于 2011 年在美国黑帽大会上发表。在此过程中,他展示了 Microsoft 在实施用户模式回调和保持数据完整性方面面临的挑战。Mandt 证明,在进行用户模式回调之前,许多对象没有被正确锁定,这允许用户模式代码在用户模式回调期间销毁这些对象,从而导致释放后使用 (UAF) 漏洞。尽管微软已经解决了 Mandt 在 2011 年指出的许多问题,但用户模式回调至今仍被滥用。受 Mandt 研究的启发,Gil Dabah在 2019 年基于 Mandt 的研究撰写了一篇论文。他发现,即使用户模式代码销毁了在用户模式回调期间正确锁定的对象,被销毁的对象也会对其他未正确锁定的对象产生二次影响。此活动导致二次对象破坏和进一步的 UAF 漏洞。在讨论 Win32k 内部结构之前,我们将简要介绍一个使用 Win32 API 创建和销毁窗口的简单 C 程序。这将使我们能够开始了解图形窗口是如何以编程方式创建和操作的。它还将允许我们检查定义每个窗口及其菜单的底层结构。我们将参考下面图 1-3 中的示例代码来讨论窗口创建的基础知识以及用于定义窗口和菜单的底层结构。注释已添加到示例代码中,以使其尽可能易于理解。如图 1 所示,示例程序首先定义一个窗口类。进程必须先注册窗口类,然后才能创建WNDCLASSEX结构中定义的类型的窗口。首先声明一个窗口类对象WNDCLASSEX wcx = { },然后填充窗口类结构。
图 1. 定义窗口类。
窗口类的元素如下:
cbSize:此结构的大小(以字节为单位)。将此成员设置为sizeof(WNDCLASSEX)。
style : 窗口类样式。该成员可以是Class Styles的任意组合。
lpfnWndProc:指向处理类中发送到窗口的所有消息并定义窗口行为的函数的指针。通常,默认窗口过程至少用于某些消息。但是,自定义窗口过程通常用于创建独特的窗口体验。有关详细信息,请参阅WindowProc。
cbClsExtra:要在窗口类结构之后分配的额外字节数。系统将字节初始化为零。
cbWndExtra:要在窗口实例之后分配的额外字节数。系统将字节初始化为零。不要将它与cbClsExtra混淆,后者对于该窗口类的所有窗口都是通用的。这通常为 0,但如果不是,则内存通常用于存储跨窗口不恒定的数据。我们稍后会在 PoC 中看到它的使用。
hInstance:包含该类的窗口过程的实例的句柄。标识注册该类的应用程序或 .DLL。在此处将hinstance参数分配给WinMain。
hIcon:类的句柄。LoadIcon(NULL, IDI_APPLICATION)加载默认图标。
hCursor:类游标的句柄。LoadCursor(NULL, IDC_ARROW)加载默认光标。
hbrBackground:类背景画笔的句柄。GetStockObject (WHITE_BRUSH)返回白色画笔的句柄。必须转换返回值,因为GetStockObject返回一个通用对象。
lpszMenuName:指向以空字符结尾的字符串的指针,该字符串指定类菜单的资源名称,因为该名称出现在资源文件中。如果不需要菜单栏,则此字段可以为NULL。
lpszClassName:标识此窗口类结构的类名。
hIconSm:小类图标的句柄。
现在已经定义了窗口类的属性,我们需要使用RegisterClassEx()将其注册到应用程序,如下面的图 2 所示。失败时,RegisterClassEX()返回 0。否则,它返回一个类原子,该原子唯一标识正在注册的类。注册窗口类将类及其关联的结构成员定义到 Windows。
图 2. 注册一个窗口类。
创建一个窗口
注册窗口后,我们可以通过调用CreateWindowExA()创建窗口类的实例,如下面的图 3 所示。
图 3. 创建窗口的代码。
CreateWindowEX的参数如图 4 所示。
图 4. CreateWindowExA函数原型。
下面列出了每个参数的简要说明:
dwExStyle:正在创建的窗口的扩展窗口样式。在这种情况下,我们已将其设置为默认窗口常量WS_EX_LEFT,这为窗口提供了通用的左对齐属性。
lpClassName:类名。取自在调用RegisterClassEX时声明的wcx.lpszClassName。
lpWindowName:窗口名称。
dwStyle:正在创建的窗口的样式。在本例中,我们使用了WS_OVERLAPPEDWINDOW,它创建了一个顶级(父)窗口。
X : 窗口的初始水平位置。对于重叠窗口或弹出窗口, x参数是窗口左上角的初始 x 坐标,以屏幕坐标表示。对于子窗口, x是窗口左上角相对于父窗口客户区左上角的 x 坐标。如果x设置为CW_USEDEFAULT,系统会选择窗口左上角的默认位置并忽略 y -参数。
Y:与上面相同,但用于 y 坐标。
nWidth:窗口的宽度。
nHeight : 窗口的高度。
hWndParent:正在创建的窗口的父窗口或所有者窗口的句柄。
hMenu:菜单句柄,或指定子窗口标识符,具体取决于窗口样式。对于重叠窗口或弹出窗口, hMenu标识要与窗口一起使用的菜单;如果要使用类菜单,它可以为NULL 。
hInstance:要与窗口关联的模块实例的句柄。
lpParam:传递给窗口窗口过程的额外信息。如果不传输额外信息,则传递NULL。
一旦通过调用CreateWindowEx()创建了窗口,就在内部创建了窗口——也就是说,已经分配了内存并填充了它的结构——但没有显示。要显示窗口,我们调用ShowWindow()函数。ShowWindow()采用从调用CreateWindowEXW()获得的句柄和从WinMain()获得的状态变量nCmdShow。nCmdShow变量决定窗口在屏幕上的显示方式,例如,是正常显示、最大化还是最小化。ShowWindow()仅控制应用程序窗口的显示方式。这包括标题栏、菜单栏、窗口菜单、最小化按钮等元素。客户区是应用程序显示数据的区域,例如您在文本编辑器中键入文本的区域。通过调用UpdateWindow()函数绘制客户区。如果将WS_VISIBLE窗口样式指定为CreateWindowEXW()函数的dwStyle参数,则不需要调用ShowWindow()函数。这是隐含的,Windows 将负责为您调用它。同样,如果您没有指定WS_VISIBLE样式并且您也没有调用ShowWindow()函数,则该窗口将保持隐藏状态。窗口消息和窗口过程
在调用UpdateWindow()之后,窗口完全可见并可以使用。在为 Windows 编写更简单的控制台应用程序时,应用程序会进行显式函数调用以响应来自控制台的用户输入。在窗口应用程序中,用户通常可以通过输入文本、单击按钮和菜单或仅通过移动鼠标来与应用程序交互。这些操作中的每一个都有自己的特殊功能。为实现这一目标,Microsoft 实施了一个事件驱动系统,该系统将来自用户输入(例如,键盘、鼠标或触摸)的消息中继到每个应用程序中的各种窗口。这些消息由每个窗口中的函数处理,称为窗口过程。Windows 为每个线程维护一个消息队列,它将中继任何影响窗口状态的用户输入事件。Windows 然后将这些事件翻译成消息并将它们放入消息队列中。应用程序通过执行类似于下面图 5 中的代码来处理这些消息。图 5. 窗口消息队列循环。
GetMessage ()函数从消息队列中检索下一条消息。MSG参数是一个结构,其中包含分配的窗口过程正确处理消息所需的消息信息。MSG结构的成员包括窗口句柄 ( hwnd ),窗口过程接收消息的窗口,以及包含标识符的消息,该标识符确定向窗口过程请求什么请求。例如,如果消息包含WM_PAINT消息,它会告诉窗口过程窗口的客户区已经改变,必须重新绘制。TranslateMessage ()函数将虚拟键消息转换为字符消息,但这对于当前的讨论并不重要。DispatchMessage ()将消息发送到由 msg 结构中的窗口句柄标识的窗口,由该窗口类定义的窗口过程处理。到目前为止,示例代码通过执行以下操作完成了定义窗口类的开销:注册窗口
创建由窗口类定义的窗口实例
在屏幕上显示窗口
进入消息循环
窗口过程决定了显示的内容以及它如何响应用户输入。Windows 提供了一个默认的窗口过程来处理应用程序不处理的任何窗口消息,它为任何窗口正常运行提供了最少的功能。窗口过程是定义窗口所有功能的地方,正如人们可能猜到的那样,它们可能非常复杂。出于我们的目的,我们目前只对 Microsoft 的默认窗口过程DefWindowProc()感兴趣。如前所述,Windows 现在通过Win32k.sys在内核中管理菜单、窗口等 GUI 对象。创建窗口对象时,会在称为tagWND 的数据结构中跟踪其属性。不幸的是,Microsoft 删除了许多 Win32k 调试符号,这使得获得这些结构的透明度变得更加困难。基于一些逆向工程,图 6 显示了 Windows 10 版本 21H1 中的结构。图 6. TagWND父结构。
这不是完整的成员列表,只是那些对本次讨论很重要的成员。在调用xxxCreateWindowEx期间查看HMAllocObject,其中发生结构分配,我们可以确认此结构的大小为0x150 (336) 字节。调用HMAllocObject之前的 WinDbg 输出如图7 所示。您可以看到第四个参数(表示分配大小)存储在r9寄存器中并且等于0x150。图 7. WinDbg输出显示HMAllocObject的输入参数。
tagWND结构,如图 6 所示,过去在线程环境块 (TEB) 的 Win32ClientInfo 条目中被引用。它已被删除,以防止内核模式地址轻易泄漏。内核tagWND结构中的第一个条目是窗口句柄。每个窗口在内核中都会有一个与之关联的代表性tagWND结构。在 CVE-2022-21882 的分析过程中,这个结构很重要,但现在,我们将关注偏移量0x28。我将其标记为*pWND,因为 Microsoft 不再提供符号。此外,Microsoft 不再为该结构提供名称——但是,在过去它被称为状态或 WW。据微软称,这些名称已被弃用,不再在内部使用。了解此指针很重要的一点是,它是不包含内核地址的tagWND数据的用户模式版本,并且其结构与其父tagWND结构不同。这个子结构既存在于内核中也存在于用户模式中。这就是 Windows 管理数据以避免内核地址泄漏的方式,因为任何用户模式应用程序都将使用位于用户模式桌面堆上的tagWND结构的副本,因此将无法看到任何内核 -模式地址。我将继续将子结构称为tagWND结构。请注意,它的结构与上面的父tagWND结构不同(如下图 8 所示),但在其他研究博客和论文中仍通常称为tagWND。子tagWND结构如图8所示,通过逆向工程确定了元素及其偏移量。未对差距进行分析,对本次讨论并不重要。在有关创建窗口的部分中讨论的WNDCLASSEX结构的许多元素都可以在tagWND结构中看到。因此,很明显,在创建窗口时,通过WNDCLASSEX结构分配的属性将传递给内核并存储在tagWND结构中。然后将属性传播到内核和用户模式桌面堆中的用户副本。图 8. tagWND结构的用户模式安全副本。
图 9 和图 10 分别显示了用户模式安全tagWND结构的父tagWND和内核副本。
图 9.父tagWND结构的WinDbg内存转储。
上图是父tagWND ,可以看到handle(offset 0x00)和下面复制的tagWND一样。您还可以看到父结构具有内核地址,而用户模式安全副本只有用户模式地址。最后,请注意父tagWND+0x28是指向子tagWND副本地址的指针。
图 10.子tagWND结构的WinDbg内存转储。
从历史上看,有几种方法可以泄露窗口对象的内核模式地址。Win32k 中存储由用户模式代码设置的属性的所有对象(例如,窗口、菜单)通常被称为用户对象。所有用户对象( tagWND结构的用户模式副本是其中之一)都在通常称为UserHandleTable的每个会话句柄表中进行索引。(尽管tagWND结构并不总是用户模式安全副本,并且曾经包含内核地址。)过去可以通过User32.dll中的可导出结构(称为gSharedInfo )通过UserHandleTable定位tagWND对象。从 Windows 10 版本 1703 开始,这不再可能。由于 Microsoft 不断努力消除内核地址泄漏,他们已从 UserHandleTable 中删除了桌面堆中对象的内核地址。窗口管理器使用位于User32.dll中的非导出函数HMValidateHandle验证句柄。在 Windows 10 版本 1803 之前,窗口管理器将内核模式指针返回到要验证其句柄的对象,通常用于泄漏该地址。尽管内核地址泄漏已被修复,但当我们稍后查看这两个漏洞时,此方法将很重要。exploit 编写者对定位tagWND结构如此感兴趣的原因是,从历史上看,您可以使用较大的值修改tagWND.cbExtra以允许使用SetWindowLong函数任意写入相邻的tagWND结构。但是,从 Windows 10 版本 1703 开始,SetWindowLong写入的任何字节都不再写入内核。那是在特定条件下除外,这将在稍后的漏洞利用分析中讨论。此修复有效地终止了这种创建任意写入的技术。用户对象存储在内核中三种内存类型之一:桌面堆、共享堆或会话池。出于本次讨论的目的,我们对桌面堆感兴趣,因为我们将使用的对象存储在这里。每个桌面都有自己的桌面堆。由于 Windows 将管理结构存储在驻留在内核中的桌面堆中,因此用户模式应用程序需要一种方法来访问这些结构。过去,Windows 创建了桌面堆的用户模式映射副本,其中包含指向相关结构的内核模式指针。今天,这些指针已经被用户模式指针所取代,表明 Windows 已经开始在用户模式下创建桌面堆的隔离副本,以消除内核模式指针地址的泄露。通常,当您尝试利用内核漏洞时,您需要一些东西才能从用户模式启用利用。其中之一是确定感兴趣的对象在内核中的位置,以绕过内核地址空间布局随机化 (KASLR)。因此,非常需要了解桌面堆所在的位置,以及在桌面堆中找到感兴趣的特定对象的能力。事实上,从 Windows 10 版本 1607 开始,微软就开始添加缓解措施,试图阻止漏洞编写者在内核中定位桌面堆及其相关对象。这些缓解措施包括从UserHandleTable中删除内核地址,如上文所述,以及在位于每个进程的线程环境块 ( TEB )中的Win32ClientInfo结构中删除对桌面堆的内核指针引用。此外,HMValidateHandle现在为传递给它的任何对象句柄返回用户模式(相对于内核模式)指针。有关 Microsoft Win32k 内核缓解历史的更多信息,请参阅Morten Schenk 的 2017 Black Hat USA presentation。我们应该注意,假设我们在低完整性流程下运营。如果进程是中等完整性或更高级别,则使用EnumDeviceDrivers和NtQuerySystemInformation等 API 函数来获取感兴趣的内核指针是微不足道的。在讨论这些 PoC 背景的第一篇文章中,最后需要讨论的是用户模式回调。因为 windows 子系统主要位于 Windows 内核中,而 windows 本身在用户模式下运行,Win32k 必须频繁地从内核调用到用户模式。用户模式回调提供了一种机制来实现诸如应用程序定义的挂钩、事件通知和从/向内核向/从内核向/向用户模式复制数据等项目。Win32k 在进行用户模式回调时调用KeUserModeCallback ,以及它要调用的用户模式函数的关联ApiNumber 。ApiNumber是函数表的索引,位于User32.dll ( USER32 !apfnDispatch ) 中。在每个进程中初始化User32.dll期间,该表的地址被复制到进程环境块 (PEB) ( PEB.KernelCallbackTable )。在即将进行的漏洞分析中,我们将展示如何通过KernelCallback表挂接用户模式回调,并展示该表在WinDbg中的样子。KeUserModeCallback函数原型及其相关参数如下图11所示。图 11. KeUserModeCallback函数原型。
用户模式回调输入参数通过InputBuffer传递,而回调函数的输出在OutputBuffer中返回。在调用系统调用时,ntdll!KiSystemService或ntdll!KiFastCallEntry在内核线程堆栈上存储一个陷阱帧 ( TRAP_FRAME ) 以保存当前线程上下文并在返回用户模式时启用寄存器恢复。
为了在用户模式回调中转换回用户模式,KeUserModeCallback首先使用线程对象持有的陷阱帧信息将InputBuffer复制到用户模式堆栈。然后它创建一个EIP设置为ntdll!KiUserCallbackDispatcher的新陷阱帧,替换线程对象的TrapFrame指针,最后调用ntdll!KiServiceExit将执行返回给用户模式回调调度程序。
图 12. KiUserCallbackDispatcher函数原型。一旦用户模式回调完成,就会调用NtCallbackReturn以在内核中恢复执行。此函数将回调的结果复制回原始内核堆栈,并恢复保存在KERNEL_STACK_CONTROL结构中的陷阱帧(PreviousTrapFrame)和内核堆栈。在跳转到之前停止的位置(在ntdll!KiCallUserMode中)之前,内核回调堆栈被删除。图 13. NtCallbackReturn函数原型。在 Win32k 管理结构上运行时,窗口管理器使用执行资源 ( ERESOURCE ) 同步原语,而不是独占锁。ERESOURCE原语允许多个线程在每个线程仅尝试读取相关资源的情况下访问共享资源。ERESOURCE原语也称为单写多读原语。ERESOURCE初始化后,线程可以使用ExAcquireResourceExclusiveLite获取独占锁(用于写入),或通过调用ExAcquireResourceSharedLite获取共享锁(用于读取)。然后线程通过调用释放资源ExReleaseResourceLite。需要禁用普通内核 APC 才能使用此处讨论的获取 API,这是通过在获取调用之前调用KeEnterCriticalRegion并在释放调用之后调用 KeLeaveCriticalRegion来完成的。如果 Win32k 在调用用户模式回调时没有释放资源,并且该用户模式回调允许应用程序冻结 GUI 子系统,则 Win32k 将无法在 GUI 子系统被冻结时执行其他任务。因此,Win32k 总是在调用用户模式回调时释放资源。下面图 14 中的代码演示了这是如何发生的。图 14. 显示 Windows 在调用KeUserModeCallback之前如何进入和离开临界区的伪代码。这种做法造成了两难境地。由于用户模式代码可以自由地执行修改对象属性和重新分配数组等操作,因此在从用户模式回调返回时,Win32k 必须确保引用的对象仍处于不受信任的状态。在不执行适当检查或对象锁定的情况下对此类对象进行操作可能并且确实会造成安全漏洞。事实上,Tarjei Mandt 2011 年的论文“通过用户模式回调进行内核攻击”确定了此类漏洞的多个实例,并且是多年来 Win32k 漏洞利用研究的基础。微软随后审查了 Windows 用户模式回调函数,以确保正确验证或锁定对象,这使得利用此类错误变得更加困难。2019 年,Gil Dabah 证明,虽然微软通过直接调用用户模式回调对修改对象的操作有效地消除了 Win32k 错误,但仍然可以将内核模式创建为间接修改对象的用户模式状态(例如销毁父窗口,同时在子窗口上执行操作)以利用类似的错误。发现的漏洞要复杂得多,这使得它们更难识别,而且数量可能也少得多。用户模式回调被认为重要到足以被微软跟踪,因为它们被赋予了特殊的前缀。用户模式回调函数名称以xxx或zzz开头。前面有xxx的那些离开临界区并调用用户模式回调,就像我们上面描述的那样。那些以zzz开头的调用异步或延迟回调。在本次讨论中,我们将只关注xxx类型的回调。在本系列的第一部分中,我们介绍了如何使用 Win32 API 创建 GUI 对象,例如窗口和菜单。我们介绍了用于管理这些对象的用户模式和内核模式数据结构,以及它们多年来如何变化以帮助优化和保护用户模式和内核模式之间的转换。在我们将于 6 月 20 日星期二发布的下一篇文章中,我们将介绍 CVE-2022-21882 的 PoC 并解释代码的作用。最后,我们将讨论该漏洞、它如何用于提升权限,以及为什么 CVE-2021-1732 补丁不足以阻止 CVE-2022021882。本系列中讨论的两个漏洞均由Cortex XDR Anti-LPE 保护模块检测并阻止。XDR Anti-LPE 模块监控诸如这些纯数据漏洞利用技术,这些技术将 NT/Authority System 权限令牌复制到当前进程的权限令牌以进行权限升级。原文翻译自:
https://unit42.paloaltonetworks.com/win32k-analysis-part-1/
参考:
https://www.blackhat.com/docs/us-17/wednesday/us-17-Schenk-Taking-Windows-10-Kernel-Exploitation-To-The-Next-Level%E2%80%93Leveraging-Write-What-Where-Vulnerabilities-In-Creators-Update.pdf
https://www.blackhat.com/docs/us-17/wednesday/us-17-Schenk-Taking-Windows-10-Kernel-Exploitation-To-The-Next-Level%E2%80%93Leveraging-Write-What-Where-Vulnerabilities-In-Creators-Update.pdf
https://www.ragestorm.net/blogs/?p=502
文章来源: http://mp.weixin.qq.com/s?__biz=MzAxMjYyMzkwOA==&mid=2247499056&idx=2&sn=6c50df8b7c1e87ff3f727976c81ebbd1&chksm=9badb47bacda3d6d0088a7712c9e11224ef75b9de595bed525ca6e6c7a26aff2185555d71b81#rd
如有侵权请联系:admin#unsafe.sh