SitePoint Sponsor

User Tag List

Results 1 to 24 of 24
  1. #1
    SitePoint Guru
    Join Date
    Oct 2001
    Location
    USA
    Posts
    764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Simple contact form being exploited?

    I have a simple contact form on my websites that allow people to contact me. Over the last few days I have seen weird things submitted, seems to be a bot. Maybe someone is trying to use the simple code to relay mail, I have no idea. How can I make the form more secure?

  2. #2
    SitePoint Zealot
    Join Date
    Aug 2004
    Location
    Canada
    Posts
    131
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Perhaps post the code you are using?

  3. #3
    SitePoint Enthusiast
    Join Date
    Jul 2004
    Location
    Brisbane, Australia
    Posts
    35
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yeah, we've been getting a lot of this on some of our sites too. (Started maybe a month ago?)

    I think its called an 'email header inject' attack - essentially, they're trying to put:
    \r\n BCC: new@email.com \r\n
    into the email address, which many of us put directly into the header in an attempt to set the reply-to address or something.

    Anyway, its very annoying. A quick google search of 'email header inject' brings up a fair bit of data on it.

    Haven't come across a foolproof way using PHP to prevent it - I have noticed a trend that they'll often throw in abc12345@domain.com (where domain.com is your website) at some point - so I added a filter into my scripts to not send emails if it involves our own domain.

    Not the best solution, but it seems okay for a quick fix.


    EDIT: Just noticed this post which covers it, and solutions, in case you've got the same prob as me.

  4. #4
    Freelance Web Guy freekrai's Avatar
    Join Date
    May 2003
    Location
    Penticton,BC
    Posts
    400
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Here's a function that I've been using on scripts for the last while. Instead of the mail() command, use the send_mail() function here:

    PHP Code:
    <? 
     
    function  send_email($to,  $fromaddr,  $fromname,  $subject,  $message_text,  $message_html  =  "") { 
      
    $subject  =  preg_replace("/\nfrom\:.*?\n/i",  "",  $subject); 
      
    $subject  =  preg_replace("/\nbcc\:.*?\n/i",  "",  $subject); 
      
    $subject  =  preg_replace("/\ncc\:.*?\n/i",  "",  $subject); 
      
    $message_text  =  preg_replace("/\nfrom\:.*?\n/i",  "",  $message_text); 
      
    $message_text  =  preg_replace("/\nbcc\:.*?\n/i",  "",  $message_text); 
      
    $message_text  =  preg_replace("/\ncc\:.*?\n/i",  "",  $message_text); 
      
    $message_html  =  preg_replace("/\nfrom\:.*?\n/i",  "",  $message_html); 
      
    $message_html  =  preg_replace("/\nbcc\:.*?\n/i",  "",  $message_html); 
      
    $message_html  =  preg_replace("/\ncc\:.*?\n/i",  "",  $message_html); 
      
    $additional_parameters  =  "-f  $fromaddr"
      
    $headers  =  "From:  $fromname  <$fromaddr>\r\n"
      
    $headers  .=  "MIME-Version:  1.0\r\n"
      if(
    $message_html  !=  "") { 
       
    $boundary  =  uniqid("sometext"); 
       
    $headers  .=  "Content-Type:  multipart/alternative;  boundary  =  $boundary\r\n\r\n"
       
    $body    =  "--$boundary\r\n"
       
    $body  .=  "Content-Type:  text/plain;  charset=ISO-8859-1\r\n"
       
    $body  .=  "Content-Transfer-Encoding:  7  bit\r\n\r\n"
       
    $body  .=  $message_text."\r\n\r\n"
       
    $body  .=  "--$boundary\r\n"
       
    $body  .=  "Content-Type:  text/html;  charset=ISO-8859-1\r\n"
       
    $body  .=  "Content-Transfer-Encoding:  t  bit\r\n\r\n"
       
    $body  .=  $message_html."\r\n\r\n"
      } 
      if(
    $message_html  ==  "") { 
       
    $headers  .=  "Content-type:  text/plain;  charset=iso-8859-1\n"
       
    $body  =  $message_text
      } 
      return  
    mail($to,  $subject,  $body,  $headers,  $additional_parameters); 
     } 
    ?>
    Roger Stringer
    DBStract - Build a database - Gather data - View it from every angle
    Other Sites: [ 1 ][ 2 ][ 3 ][ 4 ][ 5 ]


  5. #5
    SitePoint Guru
    Join Date
    Oct 2001
    Location
    USA
    Posts
    764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    ajferg that is exactly the same thing that is heppening to me.

  6. #6
    SitePoint Evangelist -Oz-'s Avatar
    Join Date
    Nov 2001
    Location
    Phoenix, AZ, USA
    Posts
    406
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Oz
    GamersMark - On Target Gaming
    OzTheory - Programming and Web Solutions
    AmIBlocked - Check if you've been blocked on IM

  7. #7
    PHP/Rails Developer Czaries's Avatar
    Join Date
    May 2004
    Location
    Central USA
    Posts
    806
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yeah, this has been happening to me, too. I guess it is a fairly common thing.

  8. #8
    Keep it simple, stupid! bokehman's Avatar
    Join Date
    Jul 2005
    Posts
    1,935
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    This can only happen on scripts where the writer has been to lazy to validate the form inputs. Don't worry about how it is happening, just validate each and every input. For example telephone numbers: only allow figures and spaces, names: only allow letters and spaces, email address: check against a pattern, etc.

  9. #9
    SitePoint Guru
    Join Date
    Oct 2001
    Location
    USA
    Posts
    764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Lazy would mean that people know and yet do nothing about it. That is not the case here.

  10. #10
    Keep it simple, stupid! bokehman's Avatar
    Join Date
    Jul 2005
    Posts
    1,935
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by 321web
    Lazy would mean that people know and yet do nothing about it. That is not the case here.
    Validating an input should be the first thing you learn in PHP. If you don't know how to validate an input you should not be running your scripts in a live environment.

  11. #11
    SitePoint Guru
    Join Date
    Oct 2001
    Location
    USA
    Posts
    764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Again that doesnt mean people are lazy, it just means that they didnt know that.

    My code looks like this
    PHP Code:
        $msg "Name:\t$name\n";
          
    $msg .= "E-mail:\t$email\n";
          
    $msg .= "ICQ:\t$icq\n";
          
    $msg .= "URL:\t$url\n";
          
    $msg .= "Description:\t$description\n";
          
    $msg .= "IP:\t$REMOTE_ADDR\n";
          
      
    $mailheaders "From: $email\n";
      
    $mailheaders .= "Reply-To: $email\n\n";
      
      
    mail("webmaster@321graphics.com""Feedback From 321Graphics.com"$msg$mailheaders); 
    None of the suggestions seem to be working.
    Last edited by 321web; Nov 19, 2005 at 15:26.

  12. #12
    SitePoint Addict
    Join Date
    Apr 2005
    Location
    San Diego, CA
    Posts
    205
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I host several hundred sites using common code including a guestbook and contact form. Last year a bot started posting to a bunch of guestbooks and contact forms. I got around it by limiting submissions by IP address and forcing confirmation emails for the original message to go through. It's been working for a year and the mass posting has stopped. As for sending bogus headers, validating input is the best method. Good luck.
    I study speed waiting. I can wait an entire hour in 10 minutes.

  13. #13
    SitePoint Guru
    Join Date
    Oct 2001
    Location
    USA
    Posts
    764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Anyone want to try and secure the code I specified above? I'll give you a cookie :-)

    Once I see it done I can better understand it and apply it to other forms. I have tried the other code specified as fixes but they dont seem to work on my site as the injections just keep coming.

  14. #14
    PHP/Rails Developer Czaries's Avatar
    Join Date
    May 2004
    Location
    Central USA
    Posts
    806
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Just because our forms are being hit does not mean we do not validate the input... It just means a bot or a person visited the form and tried it. I DO validate my input - I was just wondering about the source of the attacks and if anyone else was getting them.

  15. #15
    SitePoint Guru
    Join Date
    Oct 2001
    Location
    USA
    Posts
    764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Apprently I do not validate as well as I should be. Still awaiting some insight. Thanks again guys.

  16. #16
    Keep it simple, stupid! bokehman's Avatar
    Join Date
    Jul 2005
    Posts
    1,935
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by 321web
    Apprently I do not validate as well as I should be. Still awaiting some insight. Thanks again guys.
    If you validate your input for what is should contain rather than shouldn't contain you should not be vunerable to any type of attack.

  17. #17
    SitePoint Guru
    Join Date
    Oct 2001
    Location
    USA
    Posts
    764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Other than an email address any message could contain any type of character, so I am not sure what you mean. How can you validate a comment or suggestion some one might be sending.

    Seems to me like you need to check for what shouldnt be there, and I am not even sure of that, as I dont know what the heck people are trying to do nor do I know how they are doing it. But stopping them would be nice.

  18. #18
    Spacebug Beansprout's Avatar
    Join Date
    Oct 2005
    Location
    UK
    Posts
    464
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Strip out all \r and \n squences from the input and you'll be fine. Easy. But also the bare minimum in terms of validation really.
    Thermal Degree - web design with standards! (View our portfolio)
    Vidahost - shared and reseller linux hosting with real support
    Use my free file uploader!
    5.99 .com/net/org/biz/us/name domains; 2.99 .info!

  19. #19
    SitePoint Guru
    Join Date
    Oct 2001
    Location
    USA
    Posts
    764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Apparently this is a bot that searches the net for unsecure scripts.
    http://www.nyphp.org/phundamentals/e..._injection.php

  20. #20
    SitePoint Guru
    Join Date
    Oct 2001
    Location
    USA
    Posts
    764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I have heard that this bot targets commonly used form names such as contact.php or feedback.php, can anyone confirm being hit by it with an uncommon named page?

  21. #21
    SitePoint Enthusiast
    Join Date
    Jul 2004
    Location
    Brisbane, Australia
    Posts
    35
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    We've had hits on a file named 'email-to-a-friend.php'. Chances are, the bot also looks for keywords like 'contact' or 'email' in the filename. So files like 'contact-companyname.php' would also be targetted.

    Or hell, it could be just looking for <form> tags on all pages it finds!

  22. #22
    SitePoint Guru
    Join Date
    Oct 2001
    Location
    USA
    Posts
    764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I am conducting a test now...changed form to f33dback.php, we will see what happens.

  23. #23
    SitePoint Addict
    Join Date
    Aug 2004
    Location
    Chicago
    Posts
    296
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by 321web
    Again that doesnt mean people are lazy, it just means that they didnt know that.

    My code looks like this
    PHP Code:
        $msg "Name:\t$name\n";
          
    $msg .= "E-mail:\t$email\n";
          
    $msg .= "ICQ:\t$icq\n";
          
    $msg .= "URL:\t$url\n";
          
    $msg .= "Description:\t$description\n";
          
    $msg .= "IP:\t$REMOTE_ADDR\n";
          
      
    $mailheaders "From: $email\n";
      
    $mailheaders .= "Reply-To: $email\n\n";
      
      
    mail("webmaster@321graphics.com""Feedback From 321Graphics.com"$msg$mailheaders); 
    None of the suggestions seem to be working.
    I'm going to be using these two functions throughout, so paste it in the page or include it in a file. Doesn't really matter.
    PHP Code:
    function valid($email$debug false)
    {
        
    // valid structure??
        
    if (!preg_match('~^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$~'$email)) {
            if (
    $debug) {
                
    trigger_error('Email address not valid structure in valid()');
            }

            return 
    false;
        }

        
    // get the username and the domain into seperate parts
        
    list($username$domain) = explode('@'$email);

        
    // use getmxrr() to try to get the ip of the mail host
        // you can remove the function_exists(...) if you know you won't be running on windows
        
    if (function_exists('getmxrr') && getmxrr($domain$mxhost)) {
            
    $connectaddress $mxhost[0];
        } else {
            if (
    $debug) {
                
    trigger_error('Couldn\'t use getmxrr() in valid()');
            }

            
    // fall back on the domain
            
    $connectaddress $domain;
        }

        
    // connect to SMTP server of the connectaddress
        
    $connect fsockopen($connectaddress25$no$str15);

        
    // validate connect
        
    if ($connect) {
            
    // match the 220 response code
            
    if (preg_match('|^220|'$out fgets($connect1024))) {
                
    // hi! (tell the smtp server that)
                
    fputs ($connect'HELO ' $connectaddress "\r\n");
                
    $out fgets($connect1024);

                
    // see if its a valid user
                
    fputs($connect'MAIL FROM: <' $email '>' "\r\n");
                
    $from fgets($connect1024);

                
    // ... twice ...
                
    fputs ($connect'RCPT TO: <' $email '>' "\r\n");
                
    $to fgets ($connect1024);

                
    // quit and close
                
    fputs ($connect'QUIT' "\r\n");
                
    fclose($connect);

                
    // see if 250 was resonded
                
    if (!preg_match('!^250!'$from) || !preg_match('!^250!'$to)) {
                    if (
    $debug) {
                        
    trigger_error('No 250 response code (e.g. not a valid user) in valid()');
                    }

                    return 
    false;
                }
            } else {
                if (
    $debug) {
                    
    trigger_error('No 220 response code in valid()');
                }

                
    // no 220 response code
                
    return false;
            }
        } else {
            if (
    $debug) {
                
    trigger_error('Couldn\'t connect to ' $connectaddress ':25 in valid()');
            }

            
    // no connect
            
    return false;
        }

        
    // what??? OMGOMGOMGOMGOMGOMG!!!1!!one!1!
        
    return true;
    }

    // returns everything before any new lines (e.g. the user can't put in their own bcc or cc headers by putting in new lines)
    function b4nl($var)
    {
        return 
    preg_replace("!^(.+)(\r|\n).+$!isU"'$1'$var);

    Here's the secured (to me) code:
    PHP Code:
    <?php
    // holds all the errors
    $errors = array();

    if (isset(
    $email)) {
        
    // remove new lines
        
    $email b4nl($email);

        
    // check if its valid
        
    if (valid($email)) {
            
    $clean['email'] = $email;
        } else {
            
    $errors[] = 'Invalid email: ' $email;
        }
    } else {
        
    $errors[] = 'Your email was not present or empty';
    }

    // this reduces the amount of code by a few lines ;)
    // this strips all new lines away from the variables,
    // so I didn't put description in here
    foreach (array('name''icq''url') as $var) {
        
    // $$var would translate into something like $name or $icq
        
    $$var b4nl($var);

        
    // check that it exists and is not empty
        
    if (!isset($$var) || empty(trim($$var))) {
            
    $errors[] = 'Your' $var ' was not present or empty';
        } else {
            
    // it's clean
            
    $clean[$var] = $$var;
        }
    }

    if (!isset(
    $description) || empty(trim($description))) {
        
    $errors[] = 'Your' $var ' was not present or empty';
    } else {
        
    $clean['description'] = $description;
    }

    // more thorough, i guess?
    if (isset($_SERVER['X_FORWARDED_FOR']) && !empty(trim($_SERVER['X_FORWARDED_FOR'])) {
        
    $ip $_SERVER['X_FORWARDED_FOR'];
    } else {
        
    $ip $_SERVER['REMOTE_ADDR'];
    }

    // this detects if there are any errors.
    // you should probably change the styling around a bit, but...
    if (count($errors) > 0) {
        echo 
    'A few errors occured:<ul>';

        foreach (
    $errors) {
            echo 
    '<li>' $errors "</li>\r\n";
        }

        echo 
    '</ul>';
    }

    // construct the message
    $msg  "Name:\t" $clean['name'] . "\nE-mail:\t" $clean['email'] . "\nICQ:\t" $clean['icq'];
    $msg .= "\nURL:\t" $clean['url'] . "\nDescription:\t" $clean['description'] . "\nIP:\t" $ip "\n";

    // construct the headers.
    $headers 'From: ' $clean['email'] . "\r\nReply-To:" $clean['email'] . "\r\n\r\n";

    // you should probably change the error message here
    mail('webmaster@321graphics.com''Feedback From 321Graphics.com'$msg$headers) or echo 'Couldn\'t send mail...';
    Why's (Poignant) Guide to Ruby
    learn ruby with foxes, wizards, and chunky bacon

  24. #24
    SitePoint Addict
    Join Date
    Feb 2004
    Posts
    291
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Here is a good article about building a secure contact form: http://www.phpnerds.com/article/buil...e-contact-form


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •