Alexander Sotirov逆出来的MS08-067问题函数伪代码

作者:tombkeeper

这个Biu漏洞分配给了小四。小四说,不必着急,一定会有人指着这个扬名立万,可以稍微等等。果不其然,吃完午饭上来,就有人放PoC出来了。

昨天晚上,“Father of China PT”又问我想不想写ms08-067的代码。我说这么赶着写这个干嘛呀,咱们也不急着下大雨。“Father of China PT”说:这个漏洞大家都在盯着,写了就流芳百世了。我说:关键是想流芳百世的人那么多,咱们又不急用,等两天,各种代码肯定会乌泱乌泱铺天盖地而来,就 跟当年ms03-026一样,咱们可以捡个现成。

结果今天早晨发现Alexander Sotirov连逆的代码贴出来了。这段代码很有教学意义,我打算收到我的案例库里去。

顺便说一句,这个Alexander Sotirov下个月会来XCon演讲“Bypassing browser memory protections in Windows Vista”。

From http://www.phreedom.org/blog/2008/decompiling-ms08-067/
Decompiling the vulnerable function for MS08-067
Oct 24, 2008

I spent a couple of hours tonight reversing the vulnerable code responsible for the MS08-067 vulnerability. This bug is pretty interesting, because it is in the same area of code as the MS06-040 buffer overflow, but it was completely missed by all security researchers and Microsoft. It’s quite embarassing.

Here’s the code of the vulnerable function on Windows XP SP3:

#include <wchar.h>

// This is the decompiled function sub_5B86A51B in netapi32.dll on XP SP3

int ms08_067(wchar_t* path)
{
    wchar_t* p;
    wchar_t* q;
    wchar_t* previous_slash = NULL;
    wchar_t* current_slash  = NULL;
    wchar_t  ch;

    // If the path starts with a server name, skip it

    if ((path[0] == L'\\' || path[0] == L'/') &&
        (path[1] == L'\\' || path[1] == L'/'))
    {
        p = path+2;

        while (*p != L'\\' || *p != L'/') {
            if (*p == L'\0')
                return 0;
            p++;
        }

        p++;

        // make path point after the server name

        path = p;

        // make sure the server name is followed by a single slash

        if (path[0] == L'\\' || path[0] == L'/')
            return 0;
    }

    if (path[0] == L'\0')   // return if the path is empty
        return 1;

    // Iterate through the path and canonicalize ..\ and .\

    p = path;

    while (1) {
        if (*p == L'\\') {
            // we have a slash

            if (current_slash == p-1)   // don't allow consequtive slashes
                return 0;

            // store the locations of the current and previous slashes

            previous_slash = current_slash;
            current_slash = p;
        }
        else if (*p == L'.' && (current_slash == p-1 || p == path)) {
            // we have \. or ^.

            if (p[1] == L'.' && (p[2] == L'\\' || p[2] == L'\0')) {
                // we have a \..\, \..$, ^..\ or ^..$ sequence

                if (previous_slash == NULL)
                    return 0;

                // example: aaa\bbb\..\ccc
                //             ^   ^  ^
                //             |   |  &p[2]
                //             |   |
                //             |   current_slash
                //             |
                //             previous_slash

                ch = p[2];

                wcscpy(previous_slash, &p[2]);

                if (ch == L'\0')
                    return 1;

                current_slash = previous_slash;
                p = previous_slash;

                // find the slash before p

                // BUG: if previous_slash points to the beginning of the
                // string, we'll go beyond the start of the buffer
                //
                // example string: \a\..\

                q = p-1;

                while (*q != L'\\' && q != path)
                    q--;

                if (*p == L'\\')
                    previous_slash = q;
                else
                    previous_slash = NULL;
            }
            else if (p[1] == L'\\') {
                // we have \.\ or ^.\

                if (current_slash != NULL) {
                    wcscpy(current_slash, &p[1]);
                    goto end_of_loop;
                }
                else { // current_slash == NULL
                    wcscpy(p, p+2);
                    goto end_of_loop;
                }
            }
            else if (p[1] != L'\0') {
                // we have \. or ^. followed by some other char

                if (current_slash != NULL) {
                    p = current_slash;
                }
                *p = L'\0';
                return 1;
            }
        }

        p++;

end_of_loop:
        if (*p == L'\0')
            return 1;
    }
}

// Run this program to simulate the MS08-067 vulnerability

int main()
{
    return ms08_067(L"\\a\\..\\");
}

相关日志

楼被抢了 4 层了... 抢座Rss 2.0或者 Trackback

  • sharks520

    谁有直接得shell的利用工具..给我一份..谢谢[email protected]

  • MK2

    这个用VC++ 6 能编释出来吗

  • vxasm

    Alexander Sotirov逆出来的好像错了个地方,SP3上地址为loc_5FDE8B24,不过无关紧要啦。

    else if (p[1] != L”) //此处的判断应该是 ==
    {
    // we have \. or ^. followed by some other char

    if (current_slash != NULL) {
    p = current_slash;
    }
    *p = L”;
    return 1;
    }

  • vxasm

    另外,这段代码有点复杂的,不过Alexander Sotirov逆出来的非常棒,可读性很强,的确很赞!不愧为“Bypassing browser memory protections in Windows Vista”的作者。

发表评论