代码安全,网络安全,系统内核
« »
2008-10-29网络安全

3 views

Decompiling the vulnerable function for MS08-067

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 and Vista SP1:

#include <wchar.h>

// This is the decompiled function sub_5B86A51B in netapi32.dll on XP SP3
// and sub_6EA11D4D on Vista SP1

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;

#ifdef VISTA
    int len = wcslen(path);
    wchar_t* end_of_path = path + len;
#endif

    // 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];

#ifdef VISTA
                if (previous_slash >= end_of_path)
                    return 0;

                wcscpy_s(previous_slash, (end_of_path-previous_slash)/2, p+2);
#else // XP
                wcscpy(previous_slash, &p[2]);
#endif

                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 ^.\

#ifdef VISTA
                if (current_slash != NULL) {
                    if (current_slash >= end_of_path)
                        return 0;
                    wcscpy_s(current_slash, (end_of_path-current_slash)/2, p+2)
                    goto end_of_loop;
                }
                else {  // current_slash == NULL
                    if (p >= end_of_path)
                        return 0;
                    wcscpy_s(p, (end_of_path-p)/2, p+2);
                    goto end_of_loop;
                }
#else // XP
                if (current_slash != NULL) {
                    wcscpy(current_slash, p+2);
                    goto end_of_loop;
                }
                else { // current_slash == NULL
                    wcscpy(p, p+2);
                    goto end_of_loop;
                }
#endif
            }
            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"\\c\\..\\..\\AAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
}


日志信息 »

该日志于2008-10-29 11:18由 老周 发表在网络安全分类下, 你可以发表评论。除了可以将这个日志以保留源地址及作者的情况下引用到你的网站或博客,还可以通过RSS 2.0订阅这个日志的所有评论。

没有评论

发表评论 »

发表评论您必须先登录

返回顶部