Fix for DoS in LIST command with GNU ls
Chris Butler <[email protected]> Tue, 22 Feb 2005 21:44:03 +0000
| Newsgroups | gmane.network.ftp.wuftpd.devel |
|---|---|
| Message-ID | <[email protected]> |
--ieNMXl1Fr3cevapt Content-Type: multipart/mixed; boundary="CblX+4bnyfN0pR09" Content-Disposition: inline --CblX+4bnyfN0pR09 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Hi, I've had a bug reported via the Debian Bug Tracking System about a DoS attack against wu-ftpd, that exploits the --width argument to GNU 'ls'. By repeatedly giving it a very large argument, an attacker can cause ls to exhaust the system memory. The attached patch adds a function to ftpcmd.y, called sanitise_ls_args, which removes the -w argument and its argument from the arguments to the ls command. --=20 Chris Butler <[email protected]> Debian WU-FTPD package maintainer GnuPG Key ID: 1024D/D097A261 --CblX+4bnyfN0pR09 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="dosfix.patch" Content-Transfer-Encoding: quoted-printable Index: ftpcmd.y =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- ftpcmd.y (revision 33) +++ ftpcmd.y (working copy) @@ -395,15 +395,22 @@ } } | LIST check_login SP pathname CRLF { + char *ls_args; + =09 if (log_commands) syslog(LOG_INFO, "LIST %s", CHECKNULL($4)); if ($2 && $4 !=3D NULL && !restrict_list_check($4)) { retrieve_is_data =3D 0; #ifndef INTERNAL_LS + ls_args =3D sanitise_ls_args($4); + if (anonymous && dolreplies) - retrieve(ls_long, $4); + retrieve(ls_long, ls_args); else - retrieve(ls_short, $4); + retrieve(ls_short, ls_args); + + if (ls_args !=3D NULL) + free(ls_args); #else ls($4, 0); #endif @@ -1937,3 +1944,38 @@ (void) fflush(stdout); reply(214, ""); } + +char *sanitise_ls_args(char *inp) +{ + /* sanitise arguments to ls, to avoid -w DoS with GNU ls */ + char *ls_args, *inp_p, *ls_args_p; + + if (inp =3D=3D NULL) + return NULL; + =09 + ls_args =3D malloc(strlen(inp) + 1); + inp_p =3D inp; + ls_args_p =3D ls_args; + =09 + while(*inp_p !=3D '\0') { + if (strncasecmp(inp_p,"-w",2) =3D=3D 0) { + /* skip -w and its argument */ + inp_p +=3D 2; + for (;*inp_p !=3D '\0' && isspace(*inp_p);inp_p++); + for (;*inp_p !=3D '\0' && !isspace(*inp_p);inp_p++); + } else if (strncasecmp(inp_p,"--width",7) =3D=3D 0) { + /* same with the long option */ + inp_p +=3D 7; + for (;*inp_p !=3D '\0' && isspace(*inp_p);inp_p++); + for (;*inp_p !=3D '\0' && !isspace(*inp_p);inp_p++); + } else { + *ls_args_p =3D *inp_p; + ++ls_args_p; + ++inp_p; + } + } + + *ls_args_p =3D '\0'; + return ls_args; +} + Index: proto.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- proto.h (revision 33) +++ proto.h (working copy) @@ -135,6 +135,7 @@ void alias(char *s); void cdpath(void); void print_groups(void); +char *sanitise_ls_args(char *); =20 /* ** ftpd.c --CblX+4bnyfN0pR09-- --ieNMXl1Fr3cevapt Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Digital signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.4 (GNU/Linux) iD8DBQFCG6eiDzQFd9CXomERAqiLAJ9j1u8fw4tVkYe1X4MrZMbeHgFAVQCeJuRY 4ioPCAtW4D7+p/qOQhButRY= =nhIP -----END PGP SIGNATURE----- --ieNMXl1Fr3cevapt--