[MASOCH-L] Solução para E-mail injection (SPAM através de formulários vulneráveis)

Marcelo Coelho marcelo at tpn.com.br
Wed Dec 6 14:27:30 -03 2006


Olá,

Criei uma solução caseira pra resolver o problema de ataques de SPAMMERs 
que exploram formulários vulneráveis. Talvez interesse a quem trabalha 
com hospedagem compartilhada e não aguenta mais ficar caçando qual o 
cliente que está com o script vulnerável.

Ainda a considero "beta", mas tem funciona muito bem tanto com PHP para 
quem utiliza mail() como para CGIs (em perl, por exemplo), que chamam o 
/usr/sbin/sendmail diretamente.

Devo alertar que como é uma solução que tenta identificar o 
comportamento dos SPAMMERs, esta pode bloquear indevidamente alguma 
mensagem legítima (por exemplo, mensagens com headers 
incorretos/duplicados).

Eu utilizo esta solução em conjunto com o suhosin patch, 
http://www.hardened-php.net/suhosin.127.html.

-- 
Marcelo Coelho
marcelo at tpn.com.br
-------------- next part --------------
#!/usr/bin/perl

###########################
# 
# sendmail_wrapper v0.1
# Author: Marcelo Coelho ( marcelo _at_ tpn.com.br )
# 
# INSTALL INSTRUCTIONS:
# 
# 1) Edit sendmail_wrapper.txt, set "Configuration variables"
# 2) Copy and CHMOD this file
#    cp sendmail_wrapper.txt /usr/sbin/sendmail_wrapper
#    chmod 755 /usr/sbin/sendmail_wrapper
# 3) Edit your php.ini, put sendmail_path=/usr/sbin/sendmail_wrapper
# 
###########################

###########################
# Configuration variables #
###########################

$mail_from = 'www at yourdomain.com';
$sendmail = '/usr/sbin/sendmail -t';
$abuse_email = 'abuse at yourdomain.com';
$max_recipients = 5;
$debug = 0;

###########################


@buffer = <STDIN>;
@headers = ();
@body = ();
$from = "";
$seen_from = 0;
$seen_to = 0;
$seen_cc = 0;
$seen_bcc = 0;
$seen_header = 0;
$seen_subject = 0;
$seen_dot = 0;
$nto = 0;
$ncc = 0;
$nbcc = 0;
$n = 0;
$suspect = 0;
$deny = "";
$deny2 = "";
$last_header = "";

foreach $line (@buffer) {
  chop($line);
  if ($seen_header == 0) {
    if ($line =~ /^From: /i) {  
      if ($seen_from == 0) {
        if ($line =~ /<\s*([a-z0-9\=\+\.\_\-]+@[a-z0-9\=\+\_\-]+\.[a-z0-9\=\+\.\_\-]+)\s*>/i) {
          $from = $1;
        } elsif ($line =~ /([a-z0-9\=\+\.\_\-]+@[a-z0-9\=\+\_\-]+\.[a-z0-9\=\+\.\_\-]+)/i) {
          $from = $1;
        } elsif ($line =~ /^From:.*\<\>$/i) {
          $from = "";
        } elsif ($line =~ /^From:\s*$/i) {
          $from = "";
        } elsif ($line =~ /^From:\s*(\(\))*$/i) {
          $from = "";
        } else {
          $deny = "INVALID_FROM";
          $deny2 = $line;
          last;
        }
      }
      ++$seen_from;
    }
    if ($line =~ /^To: /i) {
      ++$seen_to;
      @tmp = split(/,/,$line);
      $nto += $#tmp + 1;
    }
    if ($line =~ /^Cc: /i) {
      ++$seen_cc;
      @tmp = split(/,/,$line);
      $ncc += $#tmp + 1;
    }
    if ($line =~ /^Bcc: /i) {
      ++$seen_bcc;
      @tmp = split(/,/,$line);
      $nbcc += $#tmp + 1;
      ++$suspect;
    }

    if ($line =~ /^Subject: /i) {
      ++$seen_subject;
    }
    
    if ($last_header ne '') {
      if ($last_header eq 'to') {
        @tmp = split(/,/,$line);
        $nto += $#tmp + 1;
      } elsif ($last_header eq 'cc') {
        @tmp = split(/,/,$line);
        $ncc += $#tmp + 1;
      } elsif ($last_header eq 'bcc') {
        @tmp = split(/,/,$line);
        $nbcc += $#tmp + 1;
      }
    }

    if ($line =~ /(To|Cc|Bcc):.*\,\s*$/i) {
      $last_header = $1;
      $last_header =~ tr/A-Z/a-z/;  
    } elsif ($line !~ /^(|\s\t ).*\,\s*$/) { $last_header = ''; }
    
    if ($seen_from > 1) { $deny = "DOUBLE_FROM"; $deny2 = $line; last; }
    if ($seen_to > 1) { $deny = "DOUBLE_TO"; $deny2 = $line; last; }
    if ($seen_cc > 1) { $deny = "DOUBLE_CC"; $deny2 = $line; last; }
    if ($seen_bcc > 1) { $deny = "DOUBLE_BCC"; $deny2 = $line; last; }
    if ($seen_subject > 1) { $deny = "DOUBLE_SUBJECT"; $deny2 = $line; last; }
    $n = $nto + $ncc + $nbcc;
    if ($n > $max_recipients) {
      $deny = "MAX_RECIPIENTS";
      $deny2 = $n;
    }
    
    if ($line eq '') { $seen_header = 1; next; }
    
  } else {
    if ($line eq '.' && ++$seen_dot > 1) { $deny = "DOUBLE_DOT"; $deny2 = $line; last; }
    if ($line =~ /^(From|To|Cc|Bcc|Subject): /i) {
      ++$suspect;
    }
    if ($suspect > 3) { $deny = "SUSPECT"; $deny2 = $line; last; }

  }
  
  if ($seen_header) {
    push @body, $line . "\n";
  } else {
    if ($line ne '') { push @headers, $line . "\n"; }
    if ($line =~ /^From: /i) {
      push @headers, "X-AntiAbuse: report abuse to $abuse_email\n";
    }
  }
  
}

if ($from eq '') {
  $deny = "NO_MAILFROM";
  $deny2 = "";
}

$arg = "";
foreach(@ARGV) {
    $arg .= " $_";
}

if ($arg =~ m/\-f\s?([a-z0-9_.-]+@[a-z0-9_.-]+)/i) {
  $mail_from = $1;
} elsif ($from ne '') {
  $mail_from = $from;
}

if ($deny eq '') {
  open(SENDMAIL,"|$sendmail -f$mail_from") or die("Couldn't start sendmail");
    print SENDMAIL @headers;
    print SENDMAIL "\n";
    print SENDMAIL @body;
  close(SENDMAIL);
} else {
  open(LOG,">>/var/log/sendmail_wrapper.log") or die("Couldn't open log");
    $tmp = `date`;
    chop($tmp);
    $log = "$tmp $deny $deny2 $mail_from\n";
    print LOG $log;
    if ($debug == 1) { print $log; }
  close(LOG);
}

if ($debug == 1) {
print "from = $from\n";
print "seen_from = $seen_from\n";
print "seen_to = $seen_to\n";
print "seen_cc = $seen_cc\n";
print "seen_bcc = $seen_bcc\n";
print "seen_header = $seen_header\n";
print "seen_subject = $seen_subject\n";
print "seen_dot = $seen_dot\n";
print "nto = $nto\n";
print "ncc = $ncc\n";
print "nbcc = $nbcc\n";
print "n = $n\n";
print "suspect = $suspect\n";
print "deny = $deny\n";
print "deny2 = $deny2\n";
}

exit;


More information about the masoch-l mailing list