1. Please take a little time for this simple survey! Thank you for participating!
    Dismiss Notice

PHP Email Injection

Discussion in 'Plesk for Linux - 8.x and Older' started by TDuncklee, Dec 1, 2005.

  1. TDuncklee

    TDuncklee Guest

    PHP Email Injection. If your users have php email forms you are an open relay!

    Ive managed to stop the hackers/spammers from using php email injection on my customers forms. http://securephp.damonkohler.com/index.php/Email_Injection
    The correct way to stop this hack is for all form data to be properly validated. However, even just explaining what the issues are to some customers is impossible so I had to come up with a server wide solution. I also log all form submissions for now. Ill look through them occasionally to see if a spammer got through somehow. At the end of the code are the things I check for to flag it as spam. This is a tough one but for now it seems every message Ive looked at has multiple Subject: s so if I find that I drop the message. I also am checking for the known test email addresses the spammers are using. PLEASE, if anyone has ideas on what to look for to definitively determine if it is an email injection spam message, post them. Also, they do not change their test addressees very often in the thousands of messages Ive looked at anyway. If anyone sees a new address, post it.

    Here is what I did:

    Create a php script called fake_sendmail.php
    // script to filter email generated from php mail() function.
    // Used to block spammers from abusing the function as described here:
    // [url]http://securephp.damonkohler.com/index.php/Email_Injection[/url]
    // modify php.ini
    //         sendmail_path = /path/to/fake_sendmail.php -t -i
    // If message does not pass the message_chk function we just
    // drop the message on the floor.
    $size_of_mbox = 10; // Approx max size (in Meg) of logged messages
    $sendmail="/usr/local/psa/qmail/bin/sendmail";  // the real sendmail program
    $args = "";
    for( $i=1; $i <= $argc; $i++ ){
         $args .= $argv[$i]." ";
    $fd = fopen("php://stdin", "r");
    $email = "";
    while (!feof($fd)) {
        $email .= fread($fd, 1024);
    $lines = explode("\n", $email);
    $from = "";
    $subject = "";
    $headers = "";
    $message = "";
    $splittingheaders = true;
    for ($i=0; $i<count($lines); $i++) {
        if ($splittingheaders) {    // this is a header until we find empty line
            if (trim($lines[$i])!="") {
                $headers .= $lines[$i]."\n";
            }  // look out for special headers
            if (preg_match("/^Subject: (.*)/", $lines[$i], $matches)) {    
                $subject = $matches[1];
            if (preg_match("/^From: (.*)/", $lines[$i], $matches)) {
                $from = $matches[1];
        } else { // not a header, but message
            $message .= $lines[$i]."\n";
        if (trim($lines[$i])=="") { // empty line, header section has ended
            $splittingheaders = false;
    $chk_result = message_chk( $headers, $message );
    if( file_exists( "/usr/mailarchive_php/php_mail_log" ) ){
        if( (filesize( "/usr/mailarchive_php/php_mail_log" )/1024/1000) > $size_of_mbox ){
            rename( "/usr/mailarchive_php/php_mail_log", 
                         "/usr/mailarchive_php/php_mail_log.".date( "y_m_d_H_i_s" ) );
    $archive_fp = fopen ("/usr/mailarchive_php/php_mail_log", "a");
    fwrite( $archive_fp, "*******\n" );
    if( $chk_result ){
        fwrite( $archive_fp, "******* Block Rule: ".$chk_result . "\n");
    fwrite( $archive_fp, "Custom-Info2: Sent with php\n\n" . $headers.$message );
    fclose( $archive_fp );
    if( !$chk_result ){
        $fps = popen( $sendmail . " " . $args, "w" );
        // Doing this so I can identify all PHP created messages.
        fwrite( $fps,  $headers . "Custom-Info2: Sent with php\n\n" . $message ); 
        pclose( $fps );
    function message_chk( $headers, $message ){
        if( substr_count ( $headers, "Subject: " ) > 1 ){    return "Multiple Subject:'s";    }
        else if (eregi( "beacon5919@aol.com", $message.$headers ) ) 
                { return "beacon5919@aol.com"; }
        else if (eregi( "batts1005@aol.com", $to.$subject.$message.$headers ) ) 
                { return "batts1005@aol.com"; }
        else if (eregi( "charleslegbe@aol.com", $to.$subject.$message.$headers ) ) 
                { return "charleslegbe@aol.com"; }
        else if (eregi( "charleselegb@aol.com", $to.$subject.$message.$headers ) ) 
                { return "charleslegbe@aol.com"; }
        else if (eregi( "charleselegbed@aol.com", $to.$subject.$message.$headers ) ) 
                { return "charleselegbed@aol.com"; }
        else if (eregi( "caitl57421@aol.com", $to.$subject.$message.$headers ) ) 
                { return "caitl57421@aol.com"; }
        else if (eregi( "michaelhorowitzzzz@SoftHome.net", $to.$subject.$message.$headers ) ) 
                { return "michaelhorowitzzzz@SoftHome.net"; }
    Create /usr/mailarchive_php/ and make it rwx by apache only. This is where I chose to log messages for now.

    In /usr/local/psa/apache/conf/php.ini add
    sendmail_path = /path/to/fake_sendmail.php -t -i

    Restart apache
  2. matt.simpson

    matt.simpson Basic Pleskian

    Sep 12, 2001
    Likes Received:
    Hey TDuncklee,
    Just wondering how this is working for you? Any thoughts / experiences you'd like to share. I'm looking for something of this nature as well.

    Best Regards,
    Matt Simpson
  3. TDuncklee

    TDuncklee Guest

    Only change so far is the "Custom-Info2: " header entry is not valid according the the RFC. Needs to be "X-Custom-Info2: "

    I also started a From: address validation routine but have not finished it. So far the multiple subject check has stopped all the junk from getting out but the hackers will get wise to it someday...
  4. HMIBarryLSalter

    HMIBarryLSalter Basic Pleskian

    Sep 7, 2005
    Likes Received:
    Does anyone know how to add extra headers to all out going email on a plesk server?

    For the same reason as you two have for detecting spam, I want to add a x-report-spam header to all out going emails so that people can report spam to us to help us find invaded forms on our server.

    Also, in my filtering, I do the same as you do with the "if spam, then die" but I also add tracking to capture their IP and I have any attempts report to a security address so that I get the attempts forwarded to me. i have one guy trying two full days now to get back in but my scripts does nothing but die when I detect attack and so he hasn't caught wind that I'm wasting his time.

    I search for the setting of mime instructions like boundry and bit type because those things are not usually done in the script but occur after the mail function run.

    please help someone on the server wide x-header idea.

    Barry L. Salter
  5. TDuncklee

    TDuncklee Guest

  6. MikeParsons

    MikeParsons Guest

    New test addresses

    New addresses appearing in my log using the filter