Spammers not welcome!

Inspecting my logs recently, I found that there were some strange requests to my Postfix mail server from user www-data. Now any sysadmin could tell you what www-data means but this does not really explain where exactly the requests came from. So I just copied the log files for my mail server and all the websites I run and grep’ed the relevant log entries to match the requests to Postfix with requests to Apache. Although I had first argued it might be one of the scripts included in the blog, forum and CMS software on my server, it turned out to be the script which is (i.e. was!) used as the backend of my contact form.

Of course I thought I had ruled out any risk by checking the referrer (which, by the way, worked for quite some time). Not so. The Apache logs showed that the referrer was forged and indeed tools such as WGET let you manipulate this HTTP header field manually. So I was out of luck and first took down the script to not allow spammers to misuse it further!

My mail queue was filled up with garbage (i.e. malformed and deferred mail) and the actual reason I found this problem was that I looked at my /var/log/syslog to find out about another, completely unrelated, problem. Why did the Postfix daemon send messages to completely odd mail addresses and why did it retry all the time? Something was definitely wrong. At that point I still thought that I had verified the user input so that an exploitation would be virtually impossible. But let’s look at my former sendmail.cgi (I stripped some strings, but no code):

use CGI::Carp qw(fatalsToBrowser);
use CGI qw(:standard);

my $host = $ENV{'HTTP_HOST'};
if1
{
  my $content  = '...';
  print header;
  if ($ENV{'HTTP_REFERER'} =~ /^http:\/\/$host/i)
  {
    MySendMail(
      param('Sender'),
      param('Sender'),
      param('Recipient').'@assarbad.net',
      param('Subject'),
      param('Mailtext'));
  }
  print $content;
}
else
{
  my $content  = '...';
  print header;
  print $content;
}
exit;

sub MySendMail
{
  my $from = shift;
  my $reply = shift;
  my $to = shift;
  my $subject = shift;
  my $content = shift;

  open (SENDMAIL, '| /usr/sbin/sendmail -t') or die "...";
  print SENDMAIL 'From: '.$from."\r\n";
  print SENDMAIL 'Reply-to: '.$reply."\r\n";
  print SENDMAIL 'Subject: '.$subject."\r\n";
  print SENDMAIL 'To: '.$to."\r\n";
  print SENDMAIL "Content-type: text/plain\n\n";
  print SENDMAIL $content;
  close(SENDMAIL);
}

Skipping directly to the subroutine MySendMail you will note, that I am using the sendmail compatibility layer of Postfix (“sendmail -t“) to get the mail sent. Anyone seeing any problem with the above code? No? Well, I did not see the problem either at the time. Until I noticed, that the envelope (Subject:, To: and so on) could be modified by the user, since it is not sanity-checked. Let’s see what is possible. Assume we pass the following to param('Subject') during the POST request:

Buy product xyz cheap!\r\nTo:a@b.com, ..., w@x.com, y@z.com

… you get the idea?! It is certainly possible to smuggle some additional header field(s) into the envelope header which is used by the sendmail binary to extract the sender, recipient and reply-to addresses. But given my naïve approach in the script above there turn out to be even more attack vectors. The regular expression checking the param('Sender') variable is not “tight” enough. Yes, it will match an email address, but it might match something else too. Furthermore it does not check whether there is exactly one sender address (which can be found by including ^ and $ markers in the regex). Basically any of the POST variables was vulnerable in this script.

Since this sendmail.cgi script was one of my first attempts to develop in Perl (was 3 or 4 years old), I can only blame myself for the naïveté, nothing else. Of course the problem is fixed now and there are checks for all user input variables. Questionable requests are immediately turned down, starting with checks for the recipient which must not even contain an @ anymore, since the @ and hostname are appended anyway. Funnily, because I added a logging facility to the script itself, I can now see the attempts from spammers everywhere (e.g. from Hongkong) to exploit the no more existing security hole.

I can only apologize to those who got spam through my server via this security hole. The script has been exploited for approximately ten days unseen and is fixed now.

Conclusion?

  • Look at your log files and mind any strange log entries! 😉
  • Never trust the user input, even if you think there is no other way to provide input to the script than through your webform, for example!

// Oliver

  1. param('Sender') =~ /.+?\@.+/gi) && (param('Mailtext') ne '' []
This entry was posted in EN, IT Security, Programming. Bookmark the permalink.

1 Response to Spammers not welcome!

  1. Pingback: AOL’s mail servers, a pain in the b… at Assarbad’s blog

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.