PHP Mail Form Email Injection Hijack

{ September 13th, 2005 }

Spam is one thing, but hijacking form mail scripts and spoofing other people’s domains and email is downright wrong. We need tough(er) penalties against these guys.

Lately my customers and I had been receiving hundreds of email sent from the forms on our sites. All form fields were filled out with email addresses from the domain in which it was sent. After checking the headers it was found that most had a BCC address of jrubin3546@aol.com.

After a little research, and a heads up by a fellow website designer in my area, it looks like this automated hijack is going to become a very big and widespread problem.

Hijack Overview
The “attacker” sends an automated bot to exploit unchecked fields in contact forms. It works by assuming a field used in an email header (e.g.: “From:” or “Subject:”) is passed unchecked to the mail subsystem. Appending a newline characters and more header lines with a BCC list and a spam message body might trick the underlying mail system into relaying spam messages. Currently it seems to be just phishing for vulnerable scripts sending emails via Bcc.

Current List of Bcc Recipients (in alphabetical order):
angelrrsmr@aol.com
bergkoch8@aol.com
cameronmtc@aol.com
damnitmayn@aol.com
Homeiragtime@aol.com
Homeragtime@aol.com
jrubin3546@aol.com
jshmng@aol.com
killerhamster@punkass.com
kolyathekid1@aol.com
kshmng@aol.com
kshmng@aol.com
lshmng@aol.com
mhkoch321@aol.com
wnacyiplay@aol.com
wolfione@aol.com
wwjdkid14@aol.com

The Fix?
It seems that stripping fields for carriage return (”\r”) and newline characters (”\n”) used directly in email headers resolves the problem. Note all your Post-Data variables (var) must be protected:

if (eregi (”\r”, $_POST[’var1′].$_POST[’var2′].$_POST[’var3′].$_POST[’etc’])) {die(”SPAM Injection Error :(”);}
if (eregi (”\n”, $_POST[’var1′].$_POST[’var2′].$_POST[’var3′].$_POST[’etc’])) {die(”SPAM Injection Error :(”);}
if (eregi (”Content-Transfer-Encoding”, $_POST[’var1′].$_POST[’var2′].$_POST[’var3′].$_POST[’etc’])) {die(”SPAM Injection Error :(”);}

For even more protection add:

if (eregi (”MIME-Version”, $_POST[’var1′].$_POST[’var2′].$_POST[’var3′].$_POST[’etc’])) {die(”SPAM Injection Error :(”);}
if (eregi (”Content-Type”, $_POST[’var1′].$_POST[’var2′].$_POST[’var3′].$_POST[’etc’])) {die(”SPAM Injection Error :(”);}

More Information
Email Injection
Crack.Attempt to Relay Spam

It is good to share: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • Furl
  • Ma.gnolia
  • NewsVine
  • Reddit
  • Spurl
  • StumbleUpon
  • Technorati

Categories: PHP ~ No Tags ~ Trackback

18 Responses to “PHP Mail Form Email Injection Hijack”

  1. 1
    Gavin Cotton

    Thanks for this article, it’s proved to be a godsend for my site which has recently come under attack from these mindless email form injections.

    Great work!

  2. 2
    Raymond Davey

    Great article.

    I had to come up with a different way to stop hijacks as we have TEXTAREA fields and would like to keep the formatting of the cr/lf.

    $from=replace($_POST[“sender???] , ???:??? , ““);
    $message=replace($_POST[“message???] , ???:??? , ““);
    etc…

    and then we use the variables in the mail function

    I know that the recipient of the form would still receive the email – but the hacker would not be able to include any other headers. The added benefit is that you can keep the formatting of the TEXTAREA fields (with the removal of the colons)

    And you would also know if someone is trying to hack your form

  3. 3
    mginop

    Raymond, accually you can leave out the TEXTAREA variables in the first two lines of my fix above. The other lines make sure no other headers are included.

  4. 4
    mginop

    One more thing. If you wish to stop all those anoying “Test” emails from being sent try:

    //Prevents Test Emails From Being Sent
    if (eregi (”@”, $_POST[’Fax’])) {die(”SPAM Injection ErrorPlease Go Back and fill out the form properly.”);}

    Note that the “Fax” field was used as it souldn’t contain a “@”.

    You could also use a hidden form field.

  5. 5
    Jo

    Today I’ve seen over 100,000 hits with only BergKoch8@aol.com. This means nearly that number of web forms got the probes and published it on their pages. And probably many of them are exploited now as spamrelays too.

    The idea with the hidden form field will work with the current version of that spambot, but future version may easily copy the constant content of a hidden field to the POST data the spambot submits to the script. Same is with the incomplete HTTP_REFERER string and the missing HTTP_USER_AGENT the bot sends.

  6. 6
    bsl

    How can we do the same using the CDONTS object in asp

  7. 7
    dan jones

    hi,
    thanks for the suggestions. one of my client websites has been having the same problem — endless ‘test’ emails Bcc:’d to random email addresses, with the same fake email in each form field. I implemented the following check within the ASP code that runs the form mailer:

    if ((inStr(Request("fax"),"@")=0) and (inStr(Request("phone"),"@")=0) and (inStr(Request("zip"),"@")=0)) then
    (business as usual)
    else
    (invoke spambot protection error)
    end if

    hopefully this will cut down on the number of ‘tests’ that clog up my client’s email inbox (and mine, since I get copied on them all)…

  8. 8
    Malcolm Corti

    This is all new to me - can you clarify whether it is necessary to check ALL form data, or only those fields which are then used in the mail headers? (Typically I only put the sender email address into the email header, and then only after checking the format).
    Thanks for your help.
    M.

  9. 9
    mginop

    Malcolm, all your Post-Data variables must be protected. So what ever form fields you have (even hidden) must be stripped.

  10. 10
    Hector

    Orlando, Florida, September 19th, 2005.

    Email Injection TRAP

    I am recording who these guys are, from where they
    are coming from, they can’t hurt me no more, and if they show up, I
    put them to sleep for an hour.
    Sounds good, doesn’t it.

    I am visited every 5 or 6 days, with the exception of August 31st and
    September 1rst.
    If someone is touched every day and can implement this script will
    be awesome. Post the results. Thank you.

    I am assuming..,
    As Barbara from UK posted:
    Barbara from UK
    #275 | Wed, Sep 14, 2005 08:37 AM
    http://www.anders.com/cms/75/Crack.Attempt/Spam.Relay

    That the spam-bot has the url address of my cgi script form handlers
    and is injecting whatever he/she want exploiting the poor cgi programming
    made. (For other will be PHP, or ASP, who knows)

    THESE IS NOT A DEFINITIVE SOLUTIONS, IT IS JUST A WAY TO FIGHT BACK
    WHEN THEY SHOWS UP. BETTER FORM HANDLERS IS WHAT WE NEED.

    Here is what I made.

    Hello, like many others on the internet I was hit
    by these guys that deserve being in jail big time.

    here are the records I have of total visits.

    bergkoch8@aol.com Wed, 31 Aug 2005 21:06:24 -0400
    Form processed at Wed Aug 31 21:06:24 EDT 2005
    From IP: 146.83.216.207
    TOTAL 45 EMAIL SPAM RECEIVED

    jrubin3546@aol.com Thu, 1 Sep 2005 19:16:03 -0400
    Form processed at Thu Sep 1 19:16:03 EDT 2005
    From IP: 194.117.20.30
    TOTAL 47 EMAIL SPAM RECEIVED

    jrubin3546@aol.com Tue, 6 Sep 2005 06:54:54 -0400
    Form processed at Tue Sep 6 06:54:54 EDT 2005
    From IP: 82.67.11.110
    TOTAL 48 EMAIL SPAM RECEIVED

    jrubin3456@aol.com Mon, 12 Sep 2005 04:28:11 -0400
    Form processed at Mon Sep 12 04:28:11 EDT 2005
    From IP: 216.194.16.226
    TOTAL 94 EMAIL SPAM RECEIVED

    Homeiragtime@aol.com Sat, 17 Sep 2005 19:27:05
    -0400
    Form processed at Sat Sep 17 19:27:04 EDT 2005
    From IP: 170.148.96.108
    TOTAL 45 EMAIL SPAM RECEIVED

    I discovered that about 8 cgi script in my site are
    potentially evolved in the risk of been hijacked and
    used as source of spam. Really they are very poor in
    programming security. (Usually called on the “action” field
    in a form)
    Beside these I have more script that must be fixed
    ASAP.
    example:

    http://www.mywebsite.com/cgi-bin/script-1.cgi
    http://www.mywebsite.com/cgi-bin/script-2.cgi
    http://www.mywebsite.com/cgi-bin/script-3.cgi
    http://www.mywebsite.com/cgi-bin/script-4.cgi
    http://www.mywebsite.com/cgi-bin/script-5.cgi
    http://www.mywebsite.com/cgi-bin/script-6.cgi
    http://www.mywebsite.com/cgi-bin/script-7.cgi
    http://www.mywebsite.com/cgi-bin/script-8.cgi

    First thing I made was change script’s names and, of
    Course, I changed also the call’s name from my html forms.

    Then I Used the Mod_Rewrite Apache Directive to
    redirect whoever is looking for my scripts names
    (the old names) to a script that will log visitors
    http environment) information and put them to sleep for
    an hour or so.

    Please if you don’t understand what it’s going on
    here, call somebody who does.

    [File created]
    .htaccess (Write this file in Pure ascii, notepad is ok)

    RewriteEngine on
    Options +FollowSymlinks
    RewriteBase /
    RewriteRule ^\old-script-1.cgi$ /cgi-bin/death-meat.cgi?%{REQUEST_URI}
    RewriteRule ^\old-script-2.cgi$ /cgi-bin/death-meat.cgi?%{REQUEST_URI}
    RewriteRule ^\old-script-3.cgi$ /cgi-bin/death-meat.cgi?%{REQUEST_URI}
    RewriteRule ^\old-script-4.cgi$ /cgi-bin/death-meat.cgi?%{REQUEST_URI}
    RewriteRule ^\old-script-5.cgi$ /cgi-bin/death-meat.cgi?%{REQUEST_URI}
    RewriteRule ^\old-script-6.cgi$ /cgi-bin/death-meat.cgi?%{REQUEST_URI}
    RewriteRule ^\old-script-7.cgi$ /cgi-bin/death-meat.cgi?%{REQUEST_URI}
    RewriteRule ^\old-script-8.cgi$ /cgi-bin/death-meat.cgi?%{REQUEST_URI}

    As you can see all the requests are re-directed
    (Internally, trough Apache system)
    to a script called death-meat.cgi (sample name, you can use anything you want)
    ##############################################################################
    # NOTE, DO THIS AT YOUR RISK:
    # Upload the file to your cgi-bin directory, Please be careful, don’t
    # make any mistake, check with your web master or ISP before uploading
    # this file, if you are already using .htaccess file, just add the above lines.
    # do it wrong and your site will disappear from the web until your ISP delete
    # or replace the .htaccess file. (I know it for my own past experience).
    ##############################################################################
    The following script is not my creation, I just
    modified one I am using for other purposes.

    Those who have access to the features below will be
    able to help in the capture of these bastards or at least make
    their brilliant ideas more difficult to implement.

    My site is stored under Linux OS, Apache webserver.
    I have access to cgi scripts, I can write the
    .htaccess file and upload it.
    and obviously I can run CGI scripts.

    Upload the file below to your cgi-bin directory in
    ascii (text) only Use a simple text editor, notepad is fine, after
    uploaded change chdmod 755

    Create a folder inside cgi-bin, stats >chdmod 777,
    and inside stats the file igotyou.log (I don’t know if
    it will be created
    automatically)

    [death-meat.cgi file name]

    #!/usr/bin/perl
    # If required, adjust line above to point to Perl 5.
    ######################################################
    # THIS IS WHAT IS GOING TO HAPPEND,
    # AFTER THIS SCRIPT COLLECT SOME VISITOR’S INFORMATION
    # WHICH IT MAY BE USEFULL OR NOT, DEPENDING IF THEY DO NOT
    # MAKE ANY MISTAKE AND ALLWAYS SEND THE BOT TROUGH A ANONIMUS PROXY
    # OTHERWISE WE GOT THE REAL PHISICAL ADDRESS.
    # THE SCRIPT WILL PUT THE VISITOR TO SLEEP FOR ABOUT AN HOUR
    #
    $stats_dir = “stats”;
    $log_file = “igotyou.log”;

    $sleeptime = 3600;

    $remote_host = “$ENV{’REMOTE_HOST’}”;
    $remote_addr = “$ENV{’REMOTE_ADDR’}”;
    $user_agent = “$ENV{’HTTP_USER_AGENT’}”;
    $referer = “$ENV{’HTTP_REFERER’}”;
    $document_name = “$ENV{’QUERY_STRING’}”;

    &get_date;

    &log_hits
    (”$date $remote_host $remote_addr $user_agent $referer
    $document_name\n”);

    print “Content-type: text/plain\n\n”;
    print @TEXT;

    ######## THE SPIDER-BOT OR THE BROWSER GET TRAPPED HERE FOR AN HOUR
    sleep ($sleeptime);
    ######## WAITING…, WAITING…,WAITING….
    exit;

    sub get_date {
    ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime();
    $mon++;
    $sec = sprintf (”%02d”, $sec);
    $min = sprintf (”%02d”, $min);
    $hour = sprintf (”%02d”, $hour);
    $mday = sprintf (”%02d”, $mday);
    $mon = sprintf (”%02d”, $mon);
    $year = scalar localtime;
    $year =~ s/.*?(\d{4})/$1/;
    $date=”$year-$mon-$mday, $hour:$min:$sec”;
    }

    sub log_hits {
    open (HITS, “>>$stats_dir/$log_file”);
    print HITS @_;
    close (HITS);
    }

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

    I am testing the urls trying to reach the cgi script
    and it work perfectly.

    I hope somebody else can try it and post the results.

    Good Luck,

    Hector Gonzalo
    hector2561@yahoo.com

  11. 11
    Steve

    Help! I really don’t understand a lot about PHP, but our site’s “request for information” form has been getting hit by the mhkock321 address, and it is really frustrating. The code for the PHP mail sender is below. What do I need to add or change? Any help would be soooooo appreciated!

    “,
    “Contact Email from _____.com”,
    “Name: $_REQUEST[name]\n”.
    “Email: $_REQUEST[email]\n”.
    “Industry Type: $_REQUEST[industry]\n”.
    “Topic of Interest: $_REQUEST[interest]\n”,

    “From: Our Web Site”
    );

    header(”Location: http://www._____.com/newsletter_thanks.php“);

    ?>

  12. 12
    Dave C.

    Thanks for all the great posts and the links to the other discussions regarding injection hacks.

  13. 13
    JJS

    Hello,

    PHP users may refer to this article where it is all documented.
    See http://securephp.damonkohler.com/index.php/Email_Injection

    Actually, the article was inspired from an older one (in French) referenced at bottom of page.

    hih,

    JJS.

  14. 14
    Dave C.

    These are a couple of functions that I am trying to break the injection hacks.

    sanitize_textarea() lets me use textarea input objects but will kill the process if there are cc, bcc, Content-Type or Mime headers/text in the input. I selected these headers because they seem to be the most useful to the injection hacks.

    These are not 100% but are much more selective than just stripping the \r and \n characters.

    function sanitize($varg) // This function attempts to break injection hacks.
    {
    $varg=stripslashes($varg);
    $carturn=’\r’;
    $newline=’\n’;
    // echo(”$varg”); // This line for testing purposes only.
    if (eregi($carturn,$varg) || eregi($newline,$varg))
    {
    // exit(”Failed on $varg.”);
    exit(”Form data syntax failure.”);
    }
    }

    function sanitize_textarea($varg) // This function attempts to break injection hacks in textarea input objects.
    {
    $varg=stripslashes($varg);
    $cont=”content-type”;
    $cc=”cc”;
    $bcc=”bcc”;
    $mime=”mime”;
    $newline=’\n’;
    // echo(”Message $varg”); // This line for testing purposes only.
    if (eregi($cont,$varg) || eregi($cc,$varg) || eregi($bcc,$varg) || eregi($mime,$varg))
    {
    // exit(”Failed on $varg.”);
    exit(”Form submission syntax failure.”);
    }
    }

  15. 15
    Giuseppe M.

    Great article, I have the same problem and now I have also the solution. In the BBC Recipient list I found:

    bergkoch8@aol.com
    Homeragtime@aol.com

    Thank you!

  16. 16
    Jason

    Hi, I am desperately trying to solve my problem with this. I am getting a bunch of these. I currently have a very standard form that submits to the following .ASP page which formats and send the email. Can anyone suggeest the solution according to what I am trying to accomplish here? Thanks in advance!
    ——-

  17. 17
    Jason

    i posted a text file version of the code at the following URL:
    http://www.jwhowarddesign.com/samplecode.txt

  18. 18
    Dave C.

    I have been tweaking my filters a bit. Its still just an attempt at sanitizing input but seems to have have helped tremendously.

    function sanitize($varg) // This function attempts to break injection hacks.

    {
    $varg=stripslashes($varg);
    if (!(strpos($varg,’\r’)===false) || !(strpos($varg,’\n’)===false) || !(strpos($varg,’0×0D’)===false) || !(strpos($varg,’%0D’)===false))
    {
    exit(”Form data syntax failure. Error 2.”);
    }
    }

    Of course you can add whatever search strings you need. Simple and effective from what I have seen.

.htaccess accessibility Apple articles browser bugs chrome CSS domain names ecommerce email ems eps fonts google HTML http https IE Internet Explorer interview Mac menu PayPal plugins redirects Safari SEO spam SSL survey tools web standards website design Windows WordPress