Page 1 of 3

Script Keeps getting Hijacked

Posted: Mon Oct 16, 2006 8:10 am
by macdoc
JayBird | Please use

Code: Select all

,

Code: Select all

and [syntax="..."] tags where appropriate when posting code. Your post has been edited to reflect how we'd like it posted. Please read:  [url=http://forums.devnetwork.net/viewtopic.php?t=21171]Posting Code in the Forums[/url] to learn how to do it too.[/color]


Hello.

I have a contact form that gets sent to a php mailing script. I keep getting emails that are obvious hijackings of the script. I do not host the site myself, but rather have a hosting service, Doteasy.com. So, not so much can be done on the server side. In the email example i included below, there is only one bcc, but in some, there are dozens. I was wondering if some suggestions as to what the best practice is to protect something like this might be, and where to find it.

TIA

Mark

Script:

Code: Select all

<?php
// Website Contact Form Generator 
// http://www.tele-pro.co.uk/scripts/contact_form/ 
// This script is free to use as long as you  
// retain the credit link  

// get posted data into local variables
$EmailFrom = Trim($_POST[EmailFrom]); 
$EmailTo = Trim($_POST[EmailTo]); 
$Subject = Trim($_POST[Subject]); 
$FirstName = Trim($_POST[FirstName]); 
$LastName = Trim($_POST[LastName]); 
$Address01 = Trim($_POST[Address01]); 
$Address02 = Trim($_POST[Address02]); 
$City = Trim($_POST[City]); 
$State = Trim($_POST[State]); 
$PostCode = Trim($_POST[PostCode]); 
$Province = Trim($_POST[Province]); 
$Country = Trim($_POST[Country]); 
$Tel = Trim($_POST[Tel]); 
$Email = Trim($_POST[Email]); 
$Phone = Trim($_POST[Phone]); 
$Fax = Trim($_POST[Fax]); 
$PostalMail = Trim($_POST[PostalMail]); 
$Facsimele = Trim($_POST[Facsimele]); 
$message = Trim($_POST[message]); 

// validation
$validationOK=true;
if (Trim($EmailFrom)=="") $validationOK=false;
if (Trim($EmailTo)=="") $validationOK=false;
if (Trim($Subject)=="") $validationOK=false;
if (Trim($message)=="") $validationOK=false;
if (Trim($Email)=="" and Trim($Phone)=="" and Trim($Fax)=="" and Trim($PostalMail)=="") $validationOK=false;
if (!$validationOK) {
  print "<meta http-equiv=\"refresh\" content=\"0;URL=error.php\">";
  exit;
}
if (Trim($Email)=="") $Email="No"; 
if (Trim($Phone)=="") $Phone="No";
if (Trim($Fax)=="") $Fax="No"; 
if (Trim($PostalMail)=="") $PostalMail="No"; 

$EmailToo = "markmiller@mitechsol.com";
$EmailFrom2 = explode("@", $EmailFrom); 

// prepare email body text
$Body = "";
$Body .= "First Name:  ";
$Body .= "$FirstName";
$Body .= "\n";
$Body .= " Last Name:  ";
$Body .= "$LastName";
$Body .= "\n";
$Body .= "\n";
$Body .= "Message: ";
$Body .= "\n";
$Body .= "$message";
$Body .= "\n";
$Body .= "\n";
$Body .= "Telephone:  ";
$Body .= "$Tel";
$Body .= "\n";
$Body .= "      Fax:  ";
$Body .= "$Facsimele";
$Body .= "\n";
$Body .= "\n";
$Body .= "     Address:  ";
$Body .= "$Address01";
$Body .= "\n";
$Body .= "            :  ";
$Body .= "$Address02";
$Body .= "\n";
$Body .= "        City:  ";
$Body .= "$City";
$Body .= "\n";
$Body .= "       State:  ";
$Body .= "$State";
$Body .= "\n";
$Body .= "Zip/PostCode:  ";
$Body .= "$PostCode";
$Body .= "\n";
$Body .= "    Province:  ";
$Body .= "$Province";
$Body .= "\n";
$Body .= "     Country:  ";
$Body .= "$Country";
$Body .= "\n";
$Body .= "$EmailFrom\n";
$Body .= "\n";
$Body .= "             Please Contact me by:";
$Body .= "\n";
$Body .= "Email:        ";
$Body .= "Phone:        ";
$Body .= "Postal Mail:   ";
$Body .= "Fax: ";
$Body .= "\n";
$Body .= " $Email           ";
$Body .= "$Phone              ";
$Body .= "$PostalMail        ";
$Body .= "$Fax";

//Check for HiJackers

if ($EmailFrom2[1]=='endo-nurses.org') {

	print "<meta http-equiv=\"refresh\" content=\"0;URL=hijacker.php\">";
	exit;
	
	}
	
if ($EmailFrom2[2]=='endo-nurses.org') {

	print "<meta http-equiv=\"refresh\" content=\"0;URL=hijacker.php\">";
	exit;
	
	}
	
// send email 
$success = mail($EmailTo, $Subject, $Body, "From: <$EmailFrom>");

// redirect to success page 
if ($success){
  print "<meta http-equiv=\"refresh\" content=\"0;URL=ok.php\">";
	mail($EmailToo, $Subject, $Body, "From: <$EmailFrom>");
}
else{
  print "<meta http-equiv=\"refresh\" content=\"0;URL=error.php\">";
}
?>
Email I Receive:

Code: Select all

from one of eight clearly defined











1770b1b884ad680c0c729d974ad847a7
.>

First Name:  legislation2121@endo-nurses.org
 Last Name:  legislation2121@endo-nurses.org

Message: 
legislation2121@endo-nurses.org

Telephone:  legislation2121@endo-nurses.org
      Fax:  legislation2121@endo-nurses.org

     Address:  legislation2121@endo-nurses.org
            :  legislation2121@endo-nurses.org
        City:  legislation2121@endo-nurses.org
       State:  legislation2121@endo-nurses.org
Zip/PostCode:  legislation2121@endo-nurses.org
    Province:  legislation2121@endo-nurses.org
     Country:  legislation2121@endo-nurses.org
salt
Content-Transfer-Encoding: 7bit
Content-Type: text/plain
X-Mailer: Mozilla 4.76 [en]C-CCK-MCD   (Win95; U)
Subject: baste the bird without human assistance
bcc: tinayankee@questfindissm.com

from one of eight clearly defined












1770b1b884ad680c0c729d974ad847a7
.

             Please Contact me by:
Email:        Phone:        Postal Mail:   Fax: 
 legislation2121@endo-nurses.org           legislation2121@endo-nurses.org              legislation2121@endo-nurses.org        legislation2121@endo-nurses.org

JayBird | Please use

Code: Select all

,

Code: Select all

and [syntax="..."] tags where appropriate when posting code. Your post has been edited to reflect how we'd like it posted. Please read:  [url=http://forums.devnetwork.net/viewtopic.php?t=21171]Posting Code in the Forums[/url] to learn how to do it too.[/color]

Posted: Mon Oct 16, 2006 8:53 am
by feyd
Your use of $EmailFrom is the source of the major portion of the hole in security. While I can appreciate the wish to build this yourself or wanting to continue using the existing code, I would suggest that you use a mailing library such as SwiftMailer.

If you insist on continuing to use this code, I would suggest storing the submission data into a database until you have enough code to avoid the header injection. To learn more about email header injection, this may be of interest.

Posted: Mon Oct 16, 2006 10:19 am
by macdoc
Thanks jaybird. I didn't read a lot before posting. I'll try to do better in the future, when I am not as frazzled as this morning.

Thanks feyd. I guess it's not a matter of insisting on using the code. It's the code that I found, and implemented. I'll look at swiftmailer, but it being a library probably precludes me from using it, as I have no control over the server side of things. i tried the captcha php this morning, and that wasn't a viable solution because of the same reason. I'll take a look at the header injection stuff.

Mark

Posted: Mon Oct 16, 2006 10:22 am
by macdoc
Also, feyd, I did put a check in there for $EmailFrom, which actually worked for some time. i don't think this is the reason for the hijacking this time around, but I could be wrong.

Code: Select all

$EmailFrom2 = explode("@", $EmailFrom);


//Check for HiJackers

if ($EmailFrom2[1]=='endo-nurses.org') {

        print "<meta http-equiv=\"refresh\" content=\"0;URL=hijacker.php\">";
        exit;
       
        }
       
if ($EmailFrom2[2]=='endo-nurses.org') {

        print "<meta http-equiv=\"refresh\" content=\"0;URL=hijacker.php\">";
        exit;
       
        }

Posted: Mon Oct 16, 2006 10:25 am
by feyd
Swift doesn't require much beyond it's scripts being on the server, so it should work fine.

As for your check, I did see it, but it isn't a thorough and is easily avoided.

Posted: Mon Oct 16, 2006 10:40 am
by macdoc
Ok. How is it being avoided? If I tell the script to exit if $EmailFrom is from my own domain, then $EmailFrom can't be what's causing it. Right?

Posted: Mon Oct 16, 2006 10:47 am
by feyd
Store the full submissions in a database (or flat file) and you'll find out. Sending the following to $_POST[EmailFrom] would avoid it.

Code: Select all

"toby@endo-nurses.org\r\nX-Mailer: I'm a spammer!"
Also something you should be aware of, PHP is likely internally throwing errors based on your use of $_POST[EmailFrom]. It should be

Code: Select all

$_POST['EmailFrom']
unless you have EmailFrom et al defined as constants.

Posted: Mon Oct 16, 2006 10:48 am
by macdoc
Thanks again feyd

Swift is nice, but over kill for what I am looking for. I don't need a mailing list, just a simple email form that is secure. Thanks for the link. I do have a need for an email list with one of my other clients, and am using a somewhat less feature rich solution.

Posted: Mon Oct 16, 2006 10:58 am
by feyd
Even for a "simple email form" Swift is really solid for it.

Posted: Mon Oct 16, 2006 11:32 am
by macdoc
feyd wrote:
Also something you should be aware of, PHP is likely internally throwing errors based on your use of $_POST[EmailFrom]. It should be

Code: Select all

$_POST['EmailFrom']
unless you have EmailFrom et al defined as constants.
This is interesting. The host provider never mentioned this to me, so I wasn't aware of it. I just thought the constant was the post from the email form of the same name.

From the email form:

Code: Select all

Your Email Address:<font color='#FF0033' size='4'>*</font>
<br>
<input type="text" name="EmailFrom">
need to concentrate on one problem at a time though. :wink:

Posted: Mon Oct 16, 2006 11:39 am
by feyd
macdoc wrote:This is interesting. The host provider never mentioned this to me, so I wasn't aware of it. I just thought the constant was the post from the email form of the same name.
If they don't have error_reporting set to E_ALL (or E_NOTICE) they wouldn't see them, but that doesn't mean they don't fire. ;)
macdoc wrote:From the email form:

Code: Select all

Your Email Address:<font color='#FF0033' size='4'>*</font>
<br>
<input type="text" name="EmailFrom">
need to concentrate on one problem at a time though. :wink:
I'm not sure what you're trying to point out here. If it's my circumvention example, a malicious poster doesn't need your form to submit.

Posted: Mon Oct 16, 2006 11:56 am
by macdoc
feyd wrote:Store the full submissions in a database (or flat file) and you'll find out. Sending the following to $_POST[EmailFrom] would avoid it.

Code: Select all

"toby@endo-nurses.org\r\nX-Mailer: I'm a spammer!"
The more I read about injection, the more frightened I become. 8O

I am looking into regexps now. Might be the way to go for me. Then, once that's in place, tackle a more robust solution. Seems that ilovejackdaniels and Roja have some good examples.

Before today, I didn't have a clue that injection existed. I am still not entirely clear on how it is done. the Wiki is good, but a bit confusing right now. I am getting a handle on avoiding injection, so, for now, this will do. I need to really get a handle on the whole process however.

Thanks again.

Mark

Posted: Mon Oct 16, 2006 11:58 am
by feyd
This is why I recommend SwiftMailer; it has a bunch of exploitive avoidance code to help people not get these problems.

Posted: Mon Oct 16, 2006 12:06 pm
by macdoc
feyd wrote:I'm not sure what you're trying to point out here. If it's my circumvention example, a malicious poster doesn't need your form to submit.
I guess I am not understanding the relationship between EmailFrom in the form, and $_POST[EmailFrom] in the script. I am fairly new to PHP, maybe a year now, and always thought that $_POST[EmailFrom] was a literal (i.e. one in the same) from the web form. yes, I understand that they are representations of the data contained in them, but just thought that the actual identifier was being past in the $_POST and not just the data itself, which is why I never really thought about it as a string, or a new instance. And also, should'nt I be getting errors reported back when the web form is submitted?

Posted: Mon Oct 16, 2006 12:09 pm
by feyd
If your host has the various error display and level settings correct, yes. If you're curious as to what settings they have:

Code: Select all

<?php

$neg = array('off', 0, false, '', null);
$flags = array(
	'Register Globals' => 'register_globals',
	'Short Tags' => 'short_open_tag',
	'Display Errors' => 'display_errors',
	'Magic Quotes GPC' => 'magic_quotes_gpc',
	'Magic Quotes Runtime' => 'magic_quotes_runtime',
	'Magic Quotes Sybase' => 'magic_quotes_sybase',
);
$ve = phpversion();
$os = PHP_OS;
$er = intval(error_reporting());
foreach ($flags as $n => $v)
{
	$flags[$n] = (in_array(strtolower(ini_get($v)), $neg) ? 'Off' : 'On');
}
$cli = (php_sapi_name() == 'cli');
$eol = "\n";

$gle = get_loaded_extensions();
$rows = array();
$le = '';
$wide = 4;
$j = count($gle);
$pad = $wide - $j % $wide;
$len = max(array_map('strlen', $gle));
$func = create_function('$a', 'return str_pad($a, ' . intval($len) . ');');
$gle = array_map($func, $gle);
for($i = 0; $i < $j; $i += $wide)
{
	$le .= '   ' . implode('   ', array_slice($gle, $i, $wide)) . $eol;
}

$ec = array(
	'E_STRICT' => 2048, 'E_ALL' => 2047, 'E_USER_NOTICE' => 1024,
	'E_USER_WARNING' => 512, 'E_USER_ERROR' => 256, 'E_COMPILE_WARNING' => 128,
	'E_COMPILE_ERROR' => 64, 'E_CORE_WARNING' => 32, 'E_CORE_ERROR' => 16,
	'E_NOTICE' => 8, 'E_PARSE' => 4, 'E_WARNING' => 2, 'E_ERROR' => 1,
);

$e = array();
$t = $er;
foreach ($ec as $n => $v)
{
	if (($t & $v) == $v)
	{
		$e[] = $n;
		$t ^= $v;
	}
}
if (ceil(count($ec) / 2) + 1 < count($e))
{
	$e2 = array();
	foreach ($ec as $n => $v)
	{
		if (!in_array($n, $e) and $n != 'E_ALL')
		{
			$e2[] = $n;
		}
	}
	$er = $er . ' ((E_ALL | E_STRICT) ^ ' . implode(' ^ ', $e2) . '))';
}
else
{
	$er = $er . ' (' . implode(' | ', $e) . ')';
}

if (!$cli)
{
	echo '<html><head><title>quick info</title></head><body><pre>', $eol;
}

echo 'PHP Version: ', $ve, $eol;
echo 'PHP OS: ', $os, $eol;
echo 'Error Reporting: ', $er, $eol;
foreach ($flags as $n => $v)
{
	echo $n, ': ', $v, $eol;
}
echo 'Loaded Extensions:', $eol, $le, $eol;

if (!$cli)
{
	echo '</pre></body></html>', $eol;
}

?>