欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]Windbg和IDA脚本辅助分析

[原创]Windbg和IDA脚本辅助分析

本文尝试解决另个问题:内核漏洞快速定位漏洞触发点 && Windbg执行流在IDA中高亮标示
内核漏洞快速定位漏洞触发点:
拿到一个内核漏洞的POC,首先我们需要定位触发漏洞,提权的地方。直接看反汇编代码往往不容易看出来
内核漏洞常见的目标是提权,一般会替换本进程的token为System的token,这种办法简单粗暴,成功率极高,所以往往为各黑客所爱。
既然要提权token,那么必须要对token所在的地址有写入操作,本文的思路就是对token所在地址下写入断点,一但触发,便是来到替换token,也就是提权的地方,再栈回溯,就能找到触发漏洞的函数了。下面我们来演示一下,我写了个windbg脚本:

$$注意一:凡是寄存器操作需加上r

$$注意二:打印字符串用%ma

$$此脚本用到了一个硬编码token偏移 0xf8,请根据你的实际系统修正它。

r @$t0=@$proc;

r @$t1=@$proc;

.while(1)

{

  

  .if ((poi(@$t1+0xb8)-0xb8) != @$t0 ) 

  {

    

    $$比较是否为test进程

    .if ( poi(@$t1+0x16c)==0x74736574 )   

    {

      .printf "进程名:%ma\t",@$t1+0x16c;

      .printf "进程EPROCESS:%x\t",@$t1;

      .printf "进程TOKEN:%x\n",poi(@$t1+0xf8);

      .printf "请输入:\n";

      .printf "ba w1 %x+f8 \".if (wo(%x+f8+2)!=0x%x){} .else{gc;}\"",@$t1,@$t1,wo(@$t1+0xf8+2);

    }

    r @$t1=poi(@$t1+0xb8)-0xb8;

  }

  .else

  {

    .break;

  }

}


代码便不会解释,如有不明,烦请百度。我用CVE-2014-4113这个漏洞演示,把win32.exe复制到虚拟机改名为test.exe。然后

回到物理机,把前面的代码保存为js.txt,然后

执行提示的那条命令,结果如下

然后物理机g跑起来,虚拟机也g跑起来,稍等一会,断在这里,ring3地址

再看看此是test.exe进程token

这个token恰好是System的token,请看

找到了提权的地方后,就可以对test.exe反汇编代码进行进一步分析了。
Windbg执行流在IDA中高亮标示:
前面得到了提权的地方,但是往往漏洞触发条件很复杂,需要经过很多函数,我们需要逐步跟踪这个函数,理解漏洞的成功,而有些函数及其庞大,分支又多,我们需要确定走哪些分析导致漏洞触发。前面得到了关键点,打印此时的堆栈
ChildEBP RetAddr  Args to Child              

WARNING: Stack unwind information not available. Following frames may be wrong.

99a80a24 96d094f3 fffffffb 000001ed 0192fac4 test+0x186d

99a80a64 96d095c5 fffffffb 000001ed 0192fac4 win32k!xxxSendMessageTimeout+0x1ac

99a80a8c 96d892fb fffffffb 000001ed 0192fac4 win32k!xxxSendMessage+0x28

99a80aec 96d88c1f 99a80b0c 00000000 0192fac4 win32k!xxxHandleMenuMessages+0x582

99a80b38 96d8f8f1 ffb89bb0 96e6f580 00000000 win32k!xxxMNLoop+0x2c6

99a80ba0 96d8f9dc 0000001c 00000000 ffffd8f0 win32k!xxxTrackPopupMenuEx+0x5cd

99a80c14 83e501ea 0009017d 00000000 ffffd8f0 win32k!NtUserTrackPopupMenuEx+0xc3

99a80c14 772570b4 0009017d 00000000 ffffd8f0 nt!KiFastCallEntry+0x12a

0192fad8 76b6483e 76b52243 0009017d 00000000 ntdll!KiFastSystemCallRet

0192fadc 76b52243 0009017d 00000000 ffffd8f0 USER32!NtUserTrackPopupMenuEx+0xc

0192fafc 013c1604 0009017d 00000000 ffffd8f0 USER32!TrackPopupMenu+0x1b

0192fb8c 75d93c45 00000000 0192fbd8 772737f5 test+0x1604

0192fb98 772737f5 00000000 76bae6a7 00000000 kernel32!BaseThreadInitThunk+0xe

0192fbd8 772737c8 013c1526 00000000 00000000 ntdll!__RtlUserThreadStart+0x70

0192fbf0 00000000 013c1526 00000000 00000000 ntdll!_RtlUserThreadStart+0x1b

PS:这是CVE-2015-1701,也是用前面的windbg脚本定位到关键点,上面是断下来后的堆栈。win32k!xxxSendMessageTimeout是最直接调用了提权函数,我们首先想到这这个函数下断,然后分析。但是win32k!xxxSendMessageTimeout频繁被系统调用,所以不好确定什么时候调用了提权函数。我选择在USER32!NtUserTrackPopupMenuEx下断。来到win32k!xxxSendMessageTimeout后
.logopen "C:\Users\Netfairy\Desktop\test.txt"

把指令流记录下来,然后一直按p,其实按一次p,接着按住回车键就可以。一会之后,windbg记录的指令流如下:

接着使用这个IDA脚本:
//

//IDC脚本,用于配合windbg动态调试得到的指令流,自动化用高亮绿色在IDA中标示出来,方便静态分析

//By www.netfairy.net

//

#include <idc.idc>

extern ida_image_base_addr,windbg_image_base_addr,offset;  //全局变量

//主函数

static main(void)

{

  auto i,temp;

  auto FileName,FileLength,hFile,str,Target="66666666";

  //

  //获取输入Windbg和IDA中模块的基址

  //

  temp=AskStr("96c50000","Please input Windbg's Win32k.sys imageBase,For example:");

  windbg_image_base_addr=xtol(temp); 

  temp=AskStr("bf800000","Please input IDA's Win32k.sys imageBase,For example:"); 

  ida_image_base_addr=xtol(temp); 

  FileName=AskFile(0,"*.*","Please choose Windbg Instruction stream file");  //选择文件

  hFile=fopen(FileName,"r+");  //读写方式打开文件

  FileLength=filelength(hFile);  //读取文件长度

  //

  //跳到指令流开头

  //

  for(i=0;i<FileLength;i++)

  {

  //往后读取八个字符

  Target[0]=fgetc(hFile);

  Target[1]=fgetc(hFile);

  Target[2]=fgetc(hFile);

  Target[3]=fgetc(hFile);

  Target[4]=fgetc(hFile);

  Target[5]=fgetc(hFile);

  Target[6]=fgetc(hFile);

  Target[7]=fgetc(hFile);

  temp=xtol(Target); // 转换字符为十六进制地址

  

  if( temp > windbg_image_base_addr && temp < 0xffffffff )  //判断地址范围

  {

     temp=temp-windbg_image_base_addr+ida_image_base_addr;  //转换为IDA地址

     str=fgetc(hFile);  //因为Windbg得到的指令流有(地址)情况,需要排除它

     fseek(hFile,-1,1);

     if(str=='\x29')  //0x29是 ')'的十六进制

     {

     }

     else

     {

       Jump(temp);  //首次跳转到指令流开头

       fseek(hFile,0,0);  //修正文件指针到文件开头

       break;

       

     }

  }

  else

  {

    fseek(hFile,-7,1);

  }

  

  }

  

 

  //

  //功能代码

  //

  for(i=0;i<FileLength;i++)

  {

  //往后读取八个字符

  Target[0]=fgetc(hFile);

  Target[1]=fgetc(hFile);

  Target[2]=fgetc(hFile);

  Target[3]=fgetc(hFile);

  Target[4]=fgetc(hFile);

  Target[5]=fgetc(hFile);

  Target[6]=fgetc(hFile);

  Target[7]=fgetc(hFile);

  temp=xtol(Target); // 转换字符为十六进制地址

  

  if( temp > windbg_image_base_addr && temp < 0xffffffff )  //判断地址范围

  {

     temp=temp-windbg_image_base_addr+ida_image_base_addr;  //转换为IDA地址

     str=fgetc(hFile);  //因为Windbg得到的指令流有(地址)情况,需要排除它

     fseek(hFile,-1,1);

     if(str=='\x29')  //0x29是 ')'的十六进制

     {

     }

     else

     {

       SetColor(temp,1,0x98fb98);  //染高亮绿色

       

     }

  }

  else

  {

    fseek(hFile,-7,1);

  }

  

  }

}


根据提示输入相应参数,一会之后

图一

图二
下面就可以进行进一步的分析了,还是看IDA舒服!!!

上传的附件 1.png
2.png
3.png
4.png
5.png
6.png
7.png
8.png
9.png

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功