CAN-2003-0910(Windows Expand-Down 数据段 权限提升漏洞)

漏洞描述

Windows 2000 允许攻击者添加自己的LDT,但是操作系统没有对LDT的 Expand-Down位进行检查,这样可使攻击添加一个位于kernle-mode的数据段,且操作系统在一些操作中并没有对数据段基址进行检查,导致目标地址被移动任意值,产生任意地址写任意值漏洞。

漏洞分析

两个问题导致此漏洞:

  • NtSetLdtEntries中对加入的LDT没有进行充足的检查,可以绕过NtSetLdtEntries的安全检查创建一个危险的数据段。
  • 在内核中缺乏有效检查,如果user-mode传入一个恶意的段,将导致任意地址写任意值漏洞。

NtSetLdtEntries允许进程为自己创建一个LDT,此函数会对LDT的base和limit进行检查来确保创建的LDT段位于user-mode。但是它并没有检查LDT的Expand-Down标志(位于数据段Type域的第2位)。

这样我们可以成功创建一个Expand-Downd,并且满足操作系统检查(“base < 7FFF0000h”, “base <= base + limit”(为了防止整数溢出), 并且 “base + limit < 7FFF0000h” )的数据段描述符。

关于Expand_Down标志,在intel手册中的描述:

For expand-down data segments, the segment limit has the same function but is interpreted differently. Here, the effective limit specifies the last address that is not allowed to be accessed within the segment; the range of valid offsets is from (effective-limit + 1) to FFFFFFFFH if the B flag is set and from (effective-limit + 1) to FFFFH if the B flag is clear.An expand-down segment has maximum size when the segment limit is 0.

根据以上描述可知,当limit设置为0时expand-down 数据段的可寻址范围最大,如果B标志位被设置,寻址范围为 1- 0xffffffff。

Expand-down数据段的limit,指明了有多少内存被排除,而不是包含在此段中,一个正常的数据段, 内存寻址是从base 到 base+limit。而在expand-down数据段,寻址范围是从 base+limit+1 到 base-1。

当limit为0并且Granularity位被设置为1时, 一个expand-down数据段包括除4K外的所有4G虚拟地址空间,但是NtSetLdtEntries没有注意到数据段expand-down标志位的影响,认为此段只包含4K地址空间,允许这样的段被创建。由于内核接收到user-mode的DS和ES寄存器并没有做任何检查和处理就直接使用了,大多数情况下,内核代码会对用户模式传入的地址进行校验,如果为kernel-mode地址(>=0x7FFF0000),则会抛出一个 “访问违例”的异常。但是因为数据段的base并没有被检查,所以检测机制可以被绕过。其它假设数据段基址为0的操作同样可以被攻击。

例如: ntoskrnl中int 2eh中断处理函数:

mov eax, service_id  
lea edx, service_param  
int 2e  

当运行rep movsd指令时:

edi为内核堆栈指针
esi指向service_param
ecx为参数的个数(in 32bit)

相当于memcpy (es.base+edi, ds.base+esi, ecx*4);

如果ES被设置成一个以 非0为基址并且 位于内核地址空间的数据段,那么目标地址将被移动ES.Base个字节。如果可以获取kernle-mode的栈指针(esp),那么可以通过设置es.base,将造成一个任意地址写任意值的漏洞。

参考

1 2 3