Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

FormMail spam

by htmanning (Friar)
on Jul 09, 2021 at 23:12 UTC ( [id://11134880]=perlquestion: print w/replies, xml ) Need Help??

htmanning has asked for the wisdom of the Perl Monks concerning the following question:

Monks, I'm using an upgraded version of FormMail.pl with various checks added for spam. We check a database of bad words, and present a question on the form like "What month does Santa come?" just for basic security. Somehow, hackers are getting past all of it. Even if I hard code the address the form can send to they get around it. Even if a word is on the bad words list they get around it. I'm baffled. Perhaps someone can point me in the right direction.
#!/usr/local/bin/perl # $Id: formmail.pl,v 1.15 2007/12/14 12:04:37 pjmclaug Exp $ ### Updated by pair Networks for added security and spam protection ### See: http://www.pair.com/pair/support/library/systemcgi/formmail.h +tml ### Last Modified 06/03/02 ###################################################################### +######## # FormMail Version 1.5 + # # Copyright 1996 Matt Wright mattw@misha.net + # # Created 6/9/95 Last Modified 04/04/2001 + # # Additional security and bug fixes added for use on pair Networks' se +rvers # # See: http://www.pair.com/pair/support/library/systemcgi/formmail.htm +l # # Scripts Archive at: http://www.worldwidemart.com/scripts/ + # ###################################################################### +######## # COPYRIGHT NOTICE + # # Copyright 1996 Matthew M. Wright All Rights Reserved. + # # + # # FormMail may be used and modified free of charge by anyone so long a +s this # # copyright notice and the comments above remain intact. By using thi +s # # code you agree to indemnify Matthew M. Wright from any liability tha +t # # might arise from it's use. + # # + # # Selling the code for this program without prior written consent is + # # expressly forbidden. In other words, please ask first before you tr +y and # # make money off of my program. + # ###################################################################### +######## #use strict; use CGI qw(param); ##### #SDO custom fields that you want to specify must be listed here... ##### my @CONFIG_FIELDS = qw(question subject email realname redirect backgr +ound bgcolor link_color vlink_color print_blank_fields text_color alink_color title print_config return_l +ink_title required sort return_link_url env_report username missing_fields_redirect print_config_to_html messa +ge organization Url); my @DAYS = qw(Sunday Monday Tuesday Wednesday Thursday Friday Saturd +ay); my @MONTHS = qw(January February March April May June July August September October November December); my $userfile = '.formmail'; my $query = new CGI; # Retrieve Date my $date = &get_date; #build config hash my %CONFIG = &hash_config_data; ########### REQUIRED SETTINGS ########## $CONFIG{'recipient'} = 'me@me.com'; $CONFIG{'site'} = 'me.com'; $CONFIG{'required'} = 'email,realname,message,question'; $CONFIG{'redirect'} = 'https://www.me.com/sent/'; $CONFIG{'env_report'} = 'REMOTE_HOST,HTTP_USER_AGENT'; $CONFIG{'subject'} = 'Me.com Feedback'; my $site_domain = "me.com"; my @referers = ('www.me.com','me.com'); ########### END REQUIRED SETTINGS ########## $CONFIG{'realname'} =~ s/\r/ /g; $CONFIG{'realname'} =~ s/\n/ /g; $CONFIG{'email'} =~ s/\r/ /g; $CONFIG{'email'} =~ s/\n/ /g; #make sure method=post &error('request_method') if $ENV{'REQUEST_METHOD'} !~ /^POST$/i; # Check Required Fields &check_required; # Check the Question Field &check_question; # Check Recipient of mail &check_recipient; &check_url; &log_entry; # Send E-Mail &send_mail; # Return HTML Page or Redirect User &return_html; ################### sub check_url { if ($ENV{'HTTP_REFERER'}) { foreach $referer (@referers) { if ($ENV{'HTTP_REFERER'} =~ /$referer/i) { $check_referer = '1'; last; } } } else { $check_referer = '1'; } if ($check_referer != 1) { #&error('bad_referer'); print "Content-type: text/html\n\n"; #&Print_Page_Top; print qq~ <br><br> <center><p><font face=arial><h1><b><font color=red>Error</font>: Y +our message seems like spam!</b></h1></font></p></center><br><br><br> +<br> ~; die } } ####################################### # Sub to check for spam and log entry sub log_entry { $regtype = $CONFIG{'regtype'}; $username = $CONFIG{'reguser'}; $ID = $CONFIG{'ID'}; $message = $CONFIG{'message'}; $URL = $CONFIG{'Url'}; $IP = $ENV{'REMOTE_HOST'}; require "/usr/home/account/public_html/mysite/cgi-bin/db-common.sub" | +| die "Error loading db-common.sub"; &Conn_to_DB; ##### CHECK FOR SPAM ##### $SQL3 = "SELECT badwords FROM badwords"; &Do_SQL3; $pointer3 = $sth3->fetchrow_hashref; $badword = $pointer3->{'badwords'}; @badwords = split /\n/,$badword; foreach $badword (@badwords) { # Strip any extra CR/LF's $badword =~ s/\n//g; $badword =~ s/\r//g; if ($message =~ /$badword/i){ $badword_found = 1; $bad_entered =($badword); } } # end foreach $badword (@badwords) if (($badword_found == 1)) { print "Content-type: text/html\n\n"; &Print_Page_Top; print qq~ <br><br> <center><p font size=+1><b><font color=red>Error</font>: Your mess +age seems like spam!</b></p></center><br><br><br><br> ~; $log = "$username tried to submit spam email"; $notes = "$message<br><br>URL Reporting: $URL"; &log_it; exit; } } ####### END CHECK FOR SPAM ####### sub get_date { my ($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime(); return sprintf ("%s, %s, %d, %d at %02d:%02d:%02d", $DAYS[$wday], $MONTHS[$mon], $mday, $year + 1900, $hour, $min, $sec); } sub hash_config_data { my %hash; foreach (@CONFIG_FIELDS) { $hash{$_} = $query->param($_) if $query->param($_); } return %hash; } #end sub hash_config_data sub check_required { my @required = split(/,/,$CONFIG{'required'}); my @error_fields; foreach (@required) { (my $field = $_) =~ s/(^\s+|\s+$)//g; if (!$query->param($field)) { push(@error_fields, $field); } } &error('missing_fields',@error_fields) if @error_fields; } sub check_recipient { my $user; ($user) = ($ENV{'DOCUMENT_ROOT'} =~ m#/usr/wwws?/users/([a-z0-9_\- +]+)#i); if (!$user) { $user = $CONFIG{'username'}; } $CONFIG{'recipient'} =~ s/\s+//g; my @recipient = split(/,/,$CONFIG{'recipient'}); foreach my $address (@recipient) { my ($domain) = ($address =~ /^[^@%!]+\@([A-Za-z0-9\.\-]+)$/) or &error('invalid_recipient'); &error('bad_recipient') unless ($domain =~ /^$site_domain$/i) +|| &in_rcpt($domain) || &in_userfile($address,$user); } } #end sub check_recipient sub in_rcpt { my $domain = shift; open(FILE,'/var/qmail/control/morercpthosts') || &error('file_unope +ned'); while (<FILE>) { chomp; return 1 if /(^\Q$domain\E$)|(\@\Q$domain\E +$)/i; } close(FILE); return 0; } #end sub in_rcpt sub in_userfile { my $address = shift; my $user = lc(shift); return 0 if $user !~ /^[a-z0-9]{2,8}$/; open(FILE,"/usr/home/$user/$userfile") || return 0; while (<FILE>) { chomp; if (/^\s*\Q$address\E\s*$/i) { close(FILE) +; return 1; } } close(FILE); return 0; } sub return_html { if ($CONFIG{'redirect'} =~ m#https?://.+\..+#) { # print the redirectional location header. print "Location: $CONFIG{'redirect'}\n\n"; } else { $CONFIG{'title'} ||= 'Thank You'; my $body = &body_attributes; print "Content-type: text/html\n\n"; print <<" %%%"; <html> <head> <title>$CONFIG{'title'}</title> </head> <body $body> <center> <h1>$CONFIG{'title'}</h1> </center> Below is what you submitted to $CONFIG{'site'} on $date <p><hr><p> %%% my @list = &get_fields; foreach (@list) { print "$_<p>"; } print "<p><hr><p>"; if ($CONFIG{print_config_to_html}) { print "Config Fields:<br><br>"; $CONFIG{print_config_to_html} =~ s/\s//g; my @print_config = split(/,/,$CONFIG{print_config_to_html}); foreach (@print_config) { print "&nbsp;&nbsp;&nbsp;$_: $CONFIG{$_}<br>" if $CONFIG{ +$_}; } print "<p><hr><p>"; } # Check for a Return Link if ($CONFIG{'return_link_url'} =~ m#https?://.+\..+# && $CONFIG{ +'return_link_title'}) { print <<" %%%"; <center> <a href=\"$CONFIG{'return_link_url'}\">$CONFIG{'return_lin +k_title'}</a> </center> %%% } print "</body></html>"; } #end else } #end sub sub send_mail { $CONFIG{'subject'} ||= 'WWW form submission'; $CONFIG{realname} and $CONFIG{realname} = "($CONFIG{realname})"; ##### #SDO you must add fields that you want to place in the email here... # They must also be included at the top of this script #### #filter NULL characters and new line #foreach (qw(subject email realname recipient message organization +Url)) { # $CONFIG{$_} =~ s/\0|\r|\n//g; #} if ($CONFIG{'email'}) { ($ENV{'QMAILUSER'},$ENV{'QMAILHOST'}) = split(/@/,$CONFIG{'email' +}); } open(MAIL,"|/var/qmail/bin/qmail-inject") || &error('mail_error'); print MAIL <<"%%%"; From: $CONFIG{'email'} $CONFIG{'realname'} To: $CONFIG{'recipient'} Subject: $CONFIG{'subject'} X-Posted-From: $ENV{'REMOTE_ADDR'} ============================ | F E E D B A C K ============================ | FROM: $CONFIG{'realname'} ($CONFIG{'email'}) | USERNAME:$CONFIG{'username'} ============================ $CONFIG{'message'} %%% #SDO commented this stuff out so I could customize this myself # if ($CONFIG{'print_config'}) { # $CONFIG{'print_config'} =~ s/\s//g; # my @print_config = split(/,/,$CONFIG{'print_config'}); # foreach (@print_config) { print MAIL "$_: $CONFIG{$_}\n\n" unl +ess !$CONFIG{$_}; } # print MAIL "------------------------- end config fields ------ +----------------------\n\n"; # } my @list = &get_fields; #SDO commented this stuff out so I could customize this myself #foreach (@list) { print MAIL "$_\n"; } #print MAIL "------------------------------------------------------ +---------------------\n"; print MAIL "======================================\n"; # Send Any Environment Variables To Recipient. $CONFIG{'env_report'} =~ s/\s//g; my @env_report = split(/,/,$CONFIG{'env_report'}); foreach (@env_report) { print MAIL "$_: $ENV{$_}\n"; } close(MAIL); } sub get_fields { my @list; my @sort_order; $_ = $CONFIG{'sort'}; if (/alphabetic/) { #sort fields and push them @sort_order = sort $query->param; } elsif (s/^order://) { my %done; my @order = split (/,/, $_); foreach (@order) { (my $field = $_) =~ s/(^\s+|\s+$)//g; push(@sort_order,$field); } @done{@sort_order} = @sort_order; push @sort_order, grep {!$done{$_}} $query->param; } else { @sort_order = $query->param; } foreach my $field (@sort_order) { my $val; foreach my $value ($query->param($field)) { $val .= " $value"; } next if (!$CONFIG{'print_blank_fields'} && (!$val || $val =~ / +^\s+$/)); push(@list, "$field: $val") unless ($CONFIG{$field} or ($field eq 'print_blank_fie +lds')); } #in case someone sets p_b_f + = 0 return @list; } #end sub sort_list sub error { my ($error,@error_fields) = @_; my %titles = ('bad_recipient' => 'Bad Recipient', 'file_unopened' => 'Unable to open file', 'request_method' => 'Request Method', 'missing_fields' => 'Missing Fields', 'mail_error' => 'Error sending mail', 'invalid_recipient' => 'Invalid Recipient' ); my $body = &body_attributes; if (($error eq 'missing_fields') && ($CONFIG{'missing_fields_redirect'} =~ m#https?://.+\..+#)) { # print the redirectional location header. print "Location: $CONFIG{'missing_fields_redirect'}\n\n"; } else { print "Content-type: text/html\n\n"; print <<" %%%"; <html> <head> <title>$titles{$error}</title> </head> <body $body> <center><table width=700><tr><td align=center> <h1>Error: $titles{$error}</h1> </td></tr><tr><td> %%% if ($error eq 'bad_recipient') { print <<" %%%"; One of the recipients of the information on this form is not a customer of pair Networks or is not currently config +ured as a valid recipient. Sorry. %%% } elsif ($error eq 'invalid_recipient') { print <<" %%%"; One of the recipients of the information on this form is not valid. %%% } elsif ($error eq 'file_unopened') { print "No way to determine if recipient is valid. \n"; } elsif ($error eq 'request_method') { print <<" %%%"; The Request Method of the Form you submitted did not match POST. Please check the form, and make sure that method=POS +T. <p><hr><p> <center> <a href=\"$ENV{'HTTP_REFERER'}\">Back to the Submission +Form</a> </center> %%% } elsif ($error eq 'missing_fields') { print <<" %%%"; The following fields were left blank in your submission fo +rm:<p> <ul> %%% foreach my $missing_field (@error_fields) { print "<li>$missing_field\n"; } print <<" %%%"; </ul> <p><hr><p> These fields must be filled out before you can successfull +y submit the form. Please return to the <a href=\"$ENV{'HTTP_REFERER'}\">Fill Out Form</a> and try + again. %%% } elsif ($error eq 'bad_question') { print <<" %%%"; <center>Sorry! You did not answer the question correctly. + Please go back and try again.<p></center> %%% } print "</td></tr></table></center></body></html>"; } exit; } sub body_attributes { my $body; # Check for Background Color $body .= qq/ bgcolor="$CONFIG{'bgcolor'}"/ if $CONFIG{'bgcolor'}; # Check for Background Image $body .= qq/ background="$CONFIG{'background'}"/ if $CONFIG{'background'} =~ /http\:\/\/.*\..*/; # Check for Link Color $body .= qq/ link="$CONFIG{'link_color'}"/ if $CONFIG{'link_color'}; # Check for Visited Link Color $body .= qq/ vlink="$CONFIG{'vlink_color'}"/ if $CONFIG{'vlink_color'}; # Check for Active Link Color $body .= qq/ alink="$CONFIG{'alink_color'}"/ if $CONFIG{'alink_color'}; # Check for Body Text Color $body .= qq/ text="$CONFIG{'text_color'}"/ if $CONFIG{'text_color'}; return $body; } sub check_question { require "/usr/home/account/public_html/mysite/cgi-bin/db-common.sub" | +| die "Error loading db-common.sub"; &Conn_to_DB; $SQL3 = "SELECT answer FROM badwords"; &Do_SQL3; $pointer3 = $sth3->fetchrow_hashref; $answer = $pointer3->{'answer'}; #unless ($CONFIG{'question'} =~ /(d|D)ecember/) { unless ($CONFIG{'question'} =~ /$answer/i) { &error('bad_question') } }

Replies are listed 'Best First'.
Re: FormMail spam
by Corion (Patriarch) on Jul 10, 2021 at 05:48 UTC

    Maybe print out some more diagnostics to see where/how the script is progressing. Maybe one of your SQL selects doesn't return what you think it should?

    Also consider using something other than FormMail, it has various problems.

    The code you posted is far too long to wade through. Trim it down to maybe only the spam detection without any CGI, database or mail part, to see whether the problem is there. If the problem is not there, look at the other parts.

Re: FormMail spam
by marto (Cardinal) on Jul 10, 2021 at 06:30 UTC

    Your system logs should show how this is being called resulting in your issues, however this ancient script is known to have many problems, and yours isn't even based upon the last release. It's not the 1990s anymore, and this hasn't been supported or a good idea for decades. Previous replies have recommend alternatives.

Re: FormMail spam ( pebkac maximus)
by Anonymous Monk on Jul 10, 2021 at 03:44 UTC

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11134880]
Approved by Marshall
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (5)
As of 2024-04-25 12:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found