Content Form Hacked - Mangaged to Create Files With It

Discussions of secure PHP coding. Security in software is important, so don't be afraid to ask. And when answering: be anal. Nitpick. No security vulnerability is too small.

Moderator: General Moderators

Post Reply
User avatar
Skara
Forum Regular
Posts: 703
Joined: Sat Mar 12, 2005 7:13 pm
Location: US

Content Form Hacked - Mangaged to Create Files With It

Post by Skara »

Ok, so I had a meager little contact form that got hacked. This is the slightly updated version. Somehow they managed to create a folder within the contact/ folder and upload files into it. I realize it's not in great shape.. I can see a few issues with it now--namely, I need to check for newlines within everything but the message variable. But I'm pretty sure there's something else related to newlines other than just checking for \n and \r? It seems like I've seen something like that.
What else sticks out? How exactly would something like this be used to create files of all things? Send spam, I get..

Code: Select all

<?php
require_once('../config.php');  //just defines a couple of things.. not really used in this file.

$_title = 'Contact';
$_content = '<table><tr><td>';

$_msg = '<img src="../images/c_line.png" alt="Something to say? Questions? Drop me a line." />';
$_msg2 = '<img src="../images/c_sent.png" alt="Email sent. Expect reply within 2-4 business days." />';
$_name = 'my name';
$_email = 'myemail@mydomain.com';
$_subject = 'Subject Prefix';

function printform($e='') {
	global $_msg,$_content;
	$_content .= "<div style='padding: 40px 20px 20px 60px;'><p>{$_msg}</p><form method='post'><table id='contact'>";
	if ($e) $_content .= "<tr><td colspan='2' style='padding-bottom: 14px;'><b style='color: #500;'>Error:</b> {$e}</td></tr>";
	$_content .= "<tr><td><img src='../images/c_name.png' alt='Name:' /></td><td><input type='text' name='name' size='20' ".(isset($_POST['name'])?"value='".htmlentities($_POST['name'])."' ":'')." /></td></tr>
<tr><td><img src='../images/c_email.png' alt='Email:' /></td><td><input type='text' name='email' size='30' ".(isset($_POST['email'])?"value='".htmlentities($_POST['email'])."' ":'')." /></td></tr>
<tr><td><img src='../images/c_subject.png' alt='Subject:' /></td><td><input type='text' name='subject' size='40' ".(isset($_POST['subject'])?"value='".htmlentities($_POST['subject'])."' ":'')." /></td></tr>
<tr><td style='padding-right: 10px;'><img src='../images/c_message.png' alt='Message:' /></td><td><textarea cols='50' rows='8' name='message'>".(isset($_POST['message'])?htmlentities($_POST['message']):'')."</textarea></td></tr>
<tr><td></td><td><input type='submit' name='contactme' value='Send' /></td></tr>
</table></form></div>";
}

if (isset($_POST['contactme'])) {
    if (empty($_POST['name']) || empty($_POST['email']) || empty($_POST['subject']) || empty($_POST['message'])) {
        printform("All fields must be filled.");
    }
    elseif (!preg_match('/^[a-zA-Z][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$/',$_POST['email'])) {
        printform('Email does not appear to be valid.');
    }
    else {
        $injection = '/(subject:)|(to:)|(bcc:)|(cc:)|(content\s*-\s*disposition)|(content\s*-\s*transfer\s*-\s*encoding)|(mime\s*-\s*version)|(multipart\s*\/\s*mixed)|(multipart\s*\/\s*alternative)|(multipart\s*\/\s*related)|(reply\s*-\s*to)|(x\s*-\s*mailer)|(x\s*-\s*sender)|(x\s*-\s*uidl)|(content\s*-\s*type)/is';
        if (preg_match($injection,$_POST['name']) || preg_match($injection,$_POST['email']) || preg_match($injection,$_POST['subject']) || preg_match($injection,$_POST['message'])) {
            printform('Header injection detected.');
        }
        else {
            $to = '"'.$_name.'" <'.$_email.'>';
            $from = "\"{$_POST['name']}\" <{$_POST['email']}>";
            $headers = "From: {$from}\r\nReply-To: {$from}";
            if (mail($to, $_subject.' :: '.$_POST['subject'], $_POST['message'], $headers)) {
                echo "<div style='padding: 40px 20px 20px 80px;'>'.$_msg2.'</div>";
            }
            else {
                printform("Server error. Please try again.");
            }
        }
    }
}
else printform();

require_once('../main.php'); //does little more than echo $_content
?>
User avatar
califdon
Jack of Zircons
Posts: 4484
Joined: Thu Nov 09, 2006 8:30 pm
Location: California, USA

Re: Content Form Hacked - Mangaged to Create Files With It

Post by califdon »

I think if you just use mysql_real_escape_string() on all your Post variables, you'll be better off than what you have there.
User avatar
Mordred
DevNet Resident
Posts: 1579
Joined: Sun Sep 03, 2006 5:19 am
Location: Sofia, Bulgaria

Re: Content Form Hacked - Mangaged to Create Files With It

Post by Mordred »

califdon wrote:I think if you just use mysql_real_escape_string() on all your Post variables, you'll be better off than what you have there.
I strongly disagree. This function is for MySQL queries, of which here there are none. For email header injection it might incidentally help, because it would add slashes to the newlines, but this doesn't mean it's correct to use it.
Skara wrote:I can see a few issues with it now--namely, I need to check for newlines within everything but the message variable.
Yes, that's right, and when you do this right you can dispense with the $injection regexp horror.

You also have some XSS in printform() because you're not calling htmlentities correctly, you always need to specify ENT_QUOTES and the correct page encoding, best done with a proxy function.

What you don't have in this function is code that would cause files to be uploaded. Must be in another file, most probably one that deals with file uploads.
User avatar
califdon
Jack of Zircons
Posts: 4484
Joined: Thu Nov 09, 2006 8:30 pm
Location: California, USA

Re: Content Form Hacked - Mangaged to Create Files With It

Post by califdon »

I stand corrected. I jumped to a conclusion. Thanks, Mordred.
User avatar
Skara
Forum Regular
Posts: 703
Joined: Sat Mar 12, 2005 7:13 pm
Location: US

Re: Content Form Hacked - Mangaged to Create Files With It

Post by Skara »

Hm. If I'm not checking for newlines in the message itself, would I not still need the regex horror for it at least?

I've actually never heard of running htmlentities differently, but I see the quotes point sure enough. I'll get that fixed up too.

I was thinking there wasn't any upload anything here, but I don't have any upload form on my website. What I do have is a single upload script on another website with the same hosting. Bizarre. I've disabled that upload script for now until I can look it over.

Thanks!
User avatar
Mordred
DevNet Resident
Posts: 1579
Joined: Sun Sep 03, 2006 5:19 am
Location: Sofia, Bulgaria

Re: Content Form Hacked - Mangaged to Create Files With It

Post by Mordred »

What you also appear to have is write permissions in the contact/ folder, which you don't actually need. Or a weak/stolen FTP password (do change it just in case).
Skara wrote:If I'm not checking for newlines in the message itself, would I not still need the regex horror for it at least?
Newlines are special when they are used in the header portion, since they start a new header line. This is why they are dangerous in the to, subject and header lists, the attacker can use them to inject additional headers or prepend/replace his own data in the email body. Strip them and check for them in these parameters of mail() and you'll be fine. Email bodies on the other hand are perfectly okay with newlines.
Post Reply