漏洞利用视角下的CVE-2020-0796漏洞
2020-4-18 00:34:27 Author: mp.weixin.qq.com(查看原文) 阅读量:5 收藏

1
概述

初见是惊鸿一瞥,重逢是始料未及。

各位“蓝颜知己”我们又见面了,本文是《漏洞分析视角下的CVE-2020-0796漏洞》的兄弟篇。CVE-2020-796漏洞成因已经在前文说明,这次我们从漏洞利用视角来看看CVE-2020-796漏洞。

这次我们分析对象是github.com/danigargu上的本地权限提升(LPE,Local Privilege Escalation)利用(Exploit)。

LPE的exploit是以C++源码形式提供的,这也有便于我们分析exploit开发原理。我们可以用Microsoft Visual Studio编译它。然后以非管理员身份运行cmd程序,执行编译后的文件cve-2020-07960local.exe。如图1所示:

图1

在exploit执行前后的whoami命令显示用户名并未改变。

图2

如图2所示,而是新弹出一个cmd的界面,在其中执行whoami显示用户名已经被修改为nt authority\system。

幸亏本文标题不是《漏洞复现视角下的CVE-2020-0796漏洞》,不然本文就到此为止了。由此可见选一个好标题的重要性,来让我们看看,这一闪而显的黑窗口背后发生了什么。

2
一串神奇的数字

使用之前分析工作中的断点,查看

bp srv2!Srv2DecompressData+0x108 ".printf \"srv2!memmove(Src=0x%I64x, Dst=0x%I64x,Size=%d) \n\", rdx, rcx, r8d;db rdx;.echo"
srv2!memmove(Src=0xffffc68fe8ee2840, Dst=0xffff8d8dec51e0a0,Size=16)
kd> rrax=ffffc68fe8ee2540 rbx=ffffc68fea74c150 rcx=ffff8d8dec51e0a0rdx=ffffc68fe8ee2840 rsi=0000000000000010 rdi=ffffc68fe8ee22c0rip=fffff80fae8a7f68 rsp=fffff2013002ee70 rbp=0000000000000002r8=0000000000000010  r9=ffffc68fea9012a0 r10=ffffc68fe7e02160r11=fffff2013002ee50 r12=0000000000000000 r13=ffffc68fec5ff240r14=00000000ffffffff r15=0000000000000000iopl=0         nv up ei ng nz na pe nccs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00000282srv2!Srv2DecompressData+0x108:fffff80f`ae8a7f68 e85376ffff      call    srv2!memcpy (fffff80f`ae89f5c0)

目的地址内存:

kd> db 0xffff8d8dec51e0a0 L0n16ffff8d8d`ec51e0a0  00 00 88 02 06 00 00 00-00 00 80 00 00 00 00 00  ................

源地址内存:

kd> db 0xffffc68fe8ee2840 L0n16ffffc68f`e8ee2840  bc ff ff f2 1f 00 00 00-bc ff ff f2 1f 00 00 00  ................

这个Exploit要从一个特定的地址读16字节的数据,然后再写入另一个特定的地方去。根据前文的分析,此处memmove的函数,是要把数据流头部未压缩的数据,移动过来,完成预定的解压缩业务流程。

图3

如图3所示,从我们抓到的流量数据来看,offset大小与memmove的size,以及数据和数据的确能匹配上。我们要搞明白这个来自网络流中,现在是memmove的源地址存放的数据,对这个特定目的地址来说有什么特别的意义。

一番眼花缭乱的操作之后,“我不再是我”。我们需要额外了解一些关于Windows内核提权的小技巧。这是一个在虚拟世界中如何向Windows“证明你自己是你自己”的问题。和现实世界中“大内侍卫凌凌漆的腰牌”有些类似。

3
进程的访问令牌

微软文档中关于访问令牌(Access Token,原文详见引用2)的描述如下:

访问令牌是一个描述进程或线程的安全上下文的对象。令牌中的信息包括与进程或线程关联的用户帐号的标识和特权。当用户登录时,系统通过将用户密码与安全数据库中存储的信息进行比较来验证用户密码。如果密码通过了验证,则系统将生成一个访问令牌。以该用户名义执行的每个进程都有此访问令牌的副本。

当线程与安全对象进行交互或尝试执行需要特权的系统任务时,系统使用访问令牌来标识用户。访问令牌包含以下信息:

  • 用户帐号的安全标识符(SID)

  • 用户所属的组的SID

  • 标识当前登录会话的登录SID

  • 用户或用户组拥有的特权列表

  • 所有者SID

  • 主要组(primary group)的SID

  • 用户创建安全对象而没有指定安全描述符时,系统使用的默认DACL

  • 访问令牌的来源

  • 令牌是主令牌(primary token)还是模拟令牌(impersonation token) 

  • 限制SID(restricting SIDs)的可选列表

  • 当前的模拟级别

  • 其他统计信息

每个进程都有一个主要令牌,用于描述与该进程关联的用户帐号的安全上下文。默认情况下,当进程的线程与安全对象进行交互时,系统将使用主令牌。此外,线程可以模拟当事人帐号(client account)。模拟允许线程使用当事人的安全上下文与安全对象进行交互。模拟当事人的线程同时具有主令牌和模拟令牌。

4
ATT&CK中的访问令牌操纵攻击技术

MITRE ATT&CK®是一个基于真实世界的观察对手的战术和技术的可全球访问的知识库。ATT&CK知识库被用作在私营部门、政府以及网络安全产品和服务社区中开发特定威胁模型和方法的基础。

在权限提升(Privilege Escalation)一节中的访问令牌操纵(Access Token Manipulation)详细介绍了在Windows系统中通过如何操纵访问令牌来提升权限的技巧。

Windows使用访问令牌来确定正在运行的进程的所有权。用户可以操纵访问令牌以使正在运行的进程看起来像它属于启动该进程的用户以外的其他人。发生这种情况时,该进程还将采用与新令牌关联的安全上下文。例如,Microsoft提倡使用访问令牌作为最佳安全实践。管理员应以标准用户身份登录,通过内置的访问令牌操作命令runas,以管理员特权运行其工具。

攻击者可以使用访问令牌在不同的用户或系统安全上下文下进行操作,并逃避检测。对手可以使用内置的Windows API函数来复制现有进程中的访问令牌;这被称为令牌窃取。对手必须已经在特权用户上下文(即管理员)中才能窃取令牌。但是,攻击者通常使用令牌窃取来将其安全上下文从管理员级别提升到SYSTEM级别。如果帐户在远程系统上具有适当的权限,则对手可以使用令牌作为该令牌的帐户向远程系统进行身份验证。

5
手动修改访问令牌

我们了解到Windows识别进程的身份靠的就是这个令牌。在Windows中应用态的内存可被进程任意读写,为了更好地安全性,Windows把令牌(token)的放进了内核态。

先看其中一个手动修改方法:

WinDBG中的!process扩展命令会显示指定进程或者全部进程的EPROCESS块信息。

kd> !process 0 0 SystemPROCESS ffff980dd646a380SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000DirBase: 001ad002  ObjectTable: ffffd5872c604b80  HandleCount: 2203.Image: System

其中的PROCESS ffff980dd646a380即表示System进程的EPROCESS的内存地址是0x ffff980dd646a380。可使用dt _EPROCESS指令查看0x ffff980dd646a380地址处的EPROCESS块信息:

kd>  dt _EPROCESS ffff980dd646a380nt!_EPROCESS+0x000 Pcb              : _KPROCESS+0x2e0 ProcessLock      : _EX_PUSH_LOCK+0x2e8 UniqueProcessId  : 0x00000000`00000004 Void+0x2f0 ActiveProcessLinks : _LIST_ENTRY [ 0xffff980d`d64d2370 - 0xfffff804`6ece1bc0 ]+0x300 RundownProtect   : _EX_RUNDOWN_REF..+0x360 Token            : _EX_FAST_REF..

EPROCESS是较大的结构体,我们省略了部分,重点关注0x360偏移处的这个Token结构。该结构是一个_EX_FAST_REF类型。

kd> dt _EX_FAST_REFnt!_EX_FAST_REF+0x000 Object           : Ptr64 Void+0x000 RefCnt           : Pos 0, 4 Bits+0x000 Value            : Uint8B

观察_EX_FAST_REF字段定义可知,0~4bit是引用计数,其余bit位才是value。

kd> dq ffff980dd646a380+0x360 L1ffff980d`d646a6e0  ffffd587`2c60604f

一般会通过位与法获得最终的值

kd> ? ffffd587`2c60604f & ffffffff`fffffff0Evaluate expression: -46698434895808 = ffffd587`2c606040

可使用!token扩展指令查看令牌的具体结构

kd> !token ffffd587`2c606040_TOKEN 0xffffd5872c606040TS Session ID: 0User: S-1-5-18User Groups:00 S-1-5-32-544Attributes - Default Enabled Owner01 S-1-1-0Attributes - Mandatory Default Enabled02 S-1-5-11Attributes - Mandatory Default Enabled03 S-1-16-16384Attributes - GroupIntegrity GroupIntegrityEnabledPrimary Group: S-1-5-18Privs:02 0x000000002 SeCreateTokenPrivilege            Attributes -03 0x000000003 SeAssignPrimaryTokenPrivilege     Attributes -04 0x000000004 SeLockMemoryPrivilege             Attributes - Enabled Default05 0x000000005 SeIncreaseQuotaPrivilege          Attributes -07 0x000000007 SeTcbPrivilege                    Attributes - Enabled Default08 0x000000008 SeSecurityPrivilege               Attributes -09 0x000000009 SeTakeOwnershipPrivilege          Attributes -10 0x00000000a SeLoadDriverPrivilege             Attributes -11 0x00000000b SeSystemProfilePrivilege          Attributes - Enabled Default12 0x00000000c SeSystemtimePrivilege             Attributes -13 0x00000000d SeProfileSingleProcessPrivilege   Attributes - Enabled Default14 0x00000000e SeIncreaseBasePriorityPrivilege   Attributes - Enabled Default15 0x00000000f SeCreatePagefilePrivilege         Attributes - Enabled Default16 0x000000010 SeCreatePermanentPrivilege        Attributes - Enabled Default17 0x000000011 SeBackupPrivilege                 Attributes -18 0x000000012 SeRestorePrivilege                Attributes -19 0x000000013 SeShutdownPrivilege               Attributes -20 0x000000014 SeDebugPrivilege                  Attributes - Enabled Default21 0x000000015 SeAuditPrivilege                  Attributes - Enabled Default22 0x000000016 SeSystemEnvironmentPrivilege      Attributes -23 0x000000017 SeChangeNotifyPrivilege           Attributes - Enabled Default25 0x000000019 SeUndockPrivilege                 Attributes -28 0x00000001c SeManageVolumePrivilege           Attributes -29 0x00000001d SeImpersonatePrivilege            Attributes - Enabled Default30 0x00000001e SeCreateGlobalPrivilege           Attributes - Enabled Default31 0x00000001f SeTrustedCredManAccessPrivilege   Attributes -32 0x000000020 SeRelabelPrivilege                Attributes -33 0x000000021 SeIncreaseWorkingSetPrivilege     Attributes - Enabled Default34 0x000000022 SeTimeZonePrivilege               Attributes - Enabled Default35 0x000000023 SeCreateSymbolicLinkPrivilege     Attributes - Enabled Default36 0x000000024 SeDelegateSessionUserImpersonatePrivilege  Attributes - Enabled DefaultAuthentication ID:         (0,3e7)Impersonation Level:       AnonymousTokenType:                 PrimarySource: *SYSTEM*           TokenFlags: 0x2000 ( Token in use )Token ID: 3eb              ParentToken ID: 0Modified ID:               (0, 3ec)RestrictedSidCount: 0      RestrictedSids: 0x0000000000000000OriginatingLogonSession: 0PackageSid: (null)CapabilityCount: 0      Capabilities: 0x0000000000000000LowboxNumberEntry: 0x0000000000000000Security Attributes:Invalid AUTHZBASEP_SECURITY_ATTRIBUTES_INFORMATION with no claimsProcess Token TrustLevelSid: S-1-19-1024-8192

也可使用dt _TOKEN查看字段定义。

kd> dt _TOKENnt!_TOKEN+0x000 TokenSource      : _TOKEN_SOURCE+0x010 TokenId          : _LUID+0x018 AuthenticationId : _LUID+0x020 ParentTokenId    : _LUID+0x028 ExpirationTime   : _LARGE_INTEGER+0x030 TokenLock        : Ptr64 _ERESOURCE+0x038 ModifiedId       : _LUID+0x040 Privileges       : _SEP_TOKEN_PRIVILEGES+0x058 AuditPolicy      : _SEP_AUDIT_POLICY..

在尝试把替换cmd.exe进程的TOKEN指针之前,我们先执行一下whoami看看。

图4

如图4中,whoami显示,当前账户是admin。

手动查看cmd.exe进程的TOKEN指针和前文所述基本一致,不再赘述。

kd> !process 0 0 cmd.exePROCESS ffff980ddcba8080SessionId: 1  Cid: 0ae8    Peb: 1265dcd000  ParentCid: 0d38DirBase: 530d6002  ObjectTable: ffffd58733943400  HandleCount:  75.Image: cmd.exe

然后把cmd.exe进程的TOKEN指针替换为system的TOKEN指针。

kd> eq ffff980ddcba8080+0x360 ffffd587`2c606040


图5

如图5中,再执行一下whoami显示,当前账户已经由admin变化为nt authority\system。

6
TOKEN+0x40偏移

我们现在来看看memmove()函数的目的地址是否就是cve-2020-0796-local.exe进程的TOKEN指针。

srv2!memmove(Src=0xffff8205e4678590, Dst=0xffff998e13d780a0,Size=16)
kd> rrax=ffff8205e4678290 rbx=ffff8205e9ad4150 rcx=ffff998e13d780a0rdx=ffff8205e4678590 rsi=0000000000000010 rdi=ffff8205e4678010rip=fffff80218327f68 rsp=ffffe8861b123e70 rbp=0000000000000002r8=0000000000000010  r9=0000000000000000 r10=ffff8205df002290r11=ffffe8861b123e50 r12=0000000000000000 r13=ffff8205e8434680r14=00000000ffffffff r15=0000000000000000iopl=0         nv up ei ng nz na po nccs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286srv2!Srv2DecompressData+0x108:fffff802`18327f68 e85376ffff      call    srv2!memcpy (fffff802`1831f5c0)
kd> db rdx L0n16ffff8205`e4678590  bc ff ff f2 1f 00 00 00-bc ff ff f2 1f 00 00 00  ................
kd> db rcx L0n16ffff998e`13d780a0  00 00 88 02 06 00 00 00-00 00 80 00 00 00 00 00  ................
kd> !process 0 0 cve-2020-0796-local.exePROCESS ffff8205e9ad5080SessionId: 1  Cid: 16e0    Peb: 44e943b000  ParentCid: 024cDirBase: 1abc2002  ObjectTable: ffff998e13777580  HandleCount:  58.Image: cve-2020-0796-local.exe
kd> dq ffff8205e9ad5080+0x360 L1ffff8205`e9ad53e0  ffff998e`13d7806e

我们发现memmove()函数的目的地0xffff998e`13d780a0和cve-2020-0796-local.exe进程的TOKEN指针存放地址ffff8205`e9ad53e0相去甚远。但却指向ffff998e`13d78060+0x40处。

kd> dt _TOKENnt!_TOKEN+0x000 TokenSource      : _TOKEN_SOURCE+0x010 TokenId          : _LUID+0x018 AuthenticationId : _LUID+0x020 ParentTokenId    : _LUID+0x028 ExpirationTime   : _LARGE_INTEGER+0x030 TokenLock        : Ptr64 _ERESOURCE+0x038 ModifiedId       : _LUID+0x040 Privileges       : _SEP_TOKEN_PRIVILEGES

从_TOKEN结构体的定义中,我们了解在0x40偏移处是一个_SEP_TOKEN_PRIVILEGES的结构。

kd> db ffff998e`13d78060+0x40 L0x16ffff998e`13d780a0  00 00 88 02 06 00 00 00-00 00 80 00 00 00 00 00  ................ffff998e`13d780b0  00 00 80 40 00 00                                ...@..fffff802`18327f6d 8b442460        mov     eax,dword ptr [rsp+60h]
kd> dt _SEP_TOKEN_PRIVILEGES ffff998e`13d78060+0x40nt!_SEP_TOKEN_PRIVILEGES+0x000 Present          : 0x00000006`02880000+0x008 Enabled          : 0x800000+0x010 EnabledByDefault : 0x40800000
kd> psrv2!Srv2DecompressData+0x10d:

单步步过之后,再查看一下:

kd> db ffff998e`13d78060+0x40 L0x16ffff998e`13d780a0  bc ff ff f2 1f 00 00 00-bc ff ff f2 1f 00 00 00  ................ffff998e`13d780b0  00 00 80 40 00 00                                ...@..
kd> dt _SEP_TOKEN_PRIVILEGES ffff998e`13d78060+0x40nt!_SEP_TOKEN_PRIVILEGES+0x000 Present : 0x0000001f`f2ffffbc+0x008 Enabled : 0x0000001f`f2ffffbc+0x010 EnabledByDefault : 0x40800000

我们观察到cve-2020-0796-local.exe进程的TOKEN中的Privileges 确实被修改过了。

kd> dt _SEP_TOKEN_PRIVILEGES ffff8d8de`1206040+0x40nt!_SEP_TOKEN_PRIVILEGES[+0x000] Present          : 0x1ff2ffffbc [Type: unsigned __int64][+0x008] Enabled          : 0x1e60b1e890 [Type: unsigned __int64][+0x010] EnabledByDefault : 0x1e60b1e890 [Type: unsigned __int64]

这神奇的16字节数据正是之前我们曾观察到的System进程的TOKEN中的Privileges的Present值。Present字段表示启用的特权,Enabled字段表示拥有的特权。这神奇的16字节数据覆盖写进程的Privileges结构之后,系统即拥有并启用了的system进程所有的特权。

我们了解到_SEP_TOKEN_PRIVILEGES是由3个bitmap构成的结构体,通过每bit是否为1来判断进程特权的。看上去应该不会超过64种特权。

7
“有种贪心叫我全要”

如果我们把这16字节全部用0xFF填充呢?

图6

我们使用前文所述的WinDBG手动设置了一下,如图6所示,使用whoami /PRIV命令时会提示“错误:指定的特权不存在”。我们在微软文档中也仅发现了44中特权。

我们修改了Exploit的源码,编译后执行验证,并在之前的断点停下来确认符合预期。

srv2!memmove(Src=0xffff8205e32a2590, Dst=0xffff998e11a4c6b0,Size=16)srv2!Srv2DecompressData+0x108:fffff802`18327f68 e85376ffff      call    srv2!memcpy (fffff802`1831f5c0)
kd> rrax=ffff8205e32a2290 rbx=ffff8205e5679150 rcx=ffff998e11a4c6b0rdx=ffff8205e32a2590 rsi=0000000000000010 rdi=ffff8205e32a2010rip=fffff80218327f68 rsp=ffffe8861a6f9e70 rbp=0000000000000002r8=0000000000000010  r9=ffff8205e4e008e0 r10=ffff8205df002160r11=ffffe8861a6f9e50 r12=0000000000000000 r13=ffff8205e8434680r14=00000000ffffffff r15=0000000000000000iopl=0         nv up ei ng nz na po nccs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286srv2!Srv2DecompressData+0x108:fffff802`18327f68 e85376ffff      call    srv2!memcpy (fffff802`1831f5c0)
kd> db rdx L0n16ffff8205`e32a2590  ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff  ................
kd> db rcx L0n16ffff998e`11a4c6b0 00 00 88 02 06 00 00 00-00 00 80 00 00 00 00 00 ................


图7

在图7中,结果显示这并不影响Exploit的效果,

8
特权影响名字?

替换TOKEN不仅可以获取特权,也直接变更了账户。这个可以理解。那么问题来了,虽然修改Privileges结构,可以获得特权,但又是如何影响账户名的呢?

现在我们需要来看看exploit的源码。

图8

如图8中源码显示,在修改本进程的_SEP_TOKEN_PRIVILEGES结构之后,就已经获得system进程的特权,后续调用了inject()函数。

图9

在图9中,inject()函数中通过CreateToolhelp32Snapshot()创建进程快照,使用比较进程名的方法找到"winlogon.exe"进程。然后使用VirtualAllocEx申请了一块带有可执行属性的内存(PAGE_EXECUTE_READWRITE),WriteProcessMemory把shellcode写入目标进程,CreateRemoteThread()最终完成任务。这是一个经典的远程线程注入。

图10

图10中shellcode应该开启cmd的功能。

图11

如图11所示,从进程树上我们能清楚的看出cmd.exe是winlogon.exe的子进程,和powershell.exe并未任何关系。

winlogon.exe是以nt authority\system用户的名义启动的,而子进程继承了父进程winlogon.exe的TOKEN,也就获得了system的特权,在使用whoami命令时显示用户也就是nt authority\system。

选取winlogon.exe作为注入进程只是一个特例,任何以NT AUTHORITY\SYSTEM或者其他特权账户名义启动的进程都有相同的效果。

9
应用层获取内核进程TOKEN的地址编程技巧

前文我们介绍了如何借助WinDBG手动修改位于内核态内存的进程的访问令牌,现在我们需要了解一下exploit如何使用编程技巧从应用层获取了TOKEN的地址的。

从源码上来看,其使用get_process_token()获取到了token在内核中的地址,然后利用CVE-2020-0796漏洞向ktoken+0x40处,即访问令牌中的_SEP_TOKEN_PRIVILEGES字段,写入了数据。

在Windows上有一些众所周知的信息泄漏技巧,如本例中使用的NtQuerySystemInformation函数。这个函数有一些神奇的功能,它会返回许多内核地址。我们主要感兴趣的是此函数能够提供目前分配的每个对象的列表,使用SystemExtendedHandleInformation参数调用NtQuerySystemInformation,我们可以得到SYSTEM_HANDLE_INFORMATION_EX结构。借助此列表,我们可以使用PID和句柄获取所需对象的内核地址。

至此漏洞利用视角下的工作基本完成。

10
综述

本文介绍了2种通过手动修改进程访问令牌或特权结构提升进程权限的技巧,分析了本地权限提升exploit中使用的获取内核地址信息的技巧。带领大家近距离体会了本地权限提升利用过程。后续有机会我们再谈谈关于此漏洞的检测。再次提醒请尽快安装官方补丁。

11
参考&引用
https://github.com/danigargu/CVE-2020-0796https://docs.microsoft.com/zh-cn/windows/win32/secauthz/access-tokenshttps://attack.mitre.org/techniques/T1134/https://docs.microsoft.com/zh-cn/windows/win32/secauthz/how-dacls-control-access-to-an-objecthttps://bbs.pediy.com/thread-224058-1.htmhttps://www.anquanke.com/post/id/86188

文章来源: https://mp.weixin.qq.com/s?__biz=MzI1NTg3NzU1Nw==&mid=2247483708&idx=1&sn=88b0d45ba39ec8c8b98fb52127526b84&chksm=ea2e09e6dd5980f09e15cb3d1c522635f0c2c2ced058b365604d96c3eb7a1483691c01804e57&scene=58&subscene=0#rd
如有侵权请联系:admin#unsafe.sh