通过PHP表单进行网络钓鱼攻击

时间:2013-05-13 11:44:19

标签: php forms captcha phishing

我在网站上遇到两个表单时遇到问题。由于网络钓鱼攻击导致我的主机多次删除托管表单的页面。

使用' PHPFormGenerator'构建的页面上的表单这是由托管公司(iPage)提供的软件。

我已经确定我使用了最新版本的PHPFormGenerator'推荐,但再次删除的页面。我安装了一个Captcha'在表格上,但页面已被删除。

我目前已从网页中删除了表单,并将其替换为电子邮件链接。

预订表单页面上的代码:

   <div class="formRow">
      <div class="formLeft">Name<span class="red">*</span></div>
      <div class="formRight">
        <input type=text name='Name' size=40>
      </div>
    </div>
    <div class="formRow">
      <div class="formLeft">Telephone<span class="red">*</span></div>
      <div class="formRight">
        <input type=text name='Telephone' size=40>
      </div>
    </div>
    <div class="formRow">
      <div class="formLeft">Email<span class="red">*</span></div>
      <div class="formRight">
        <input type=text name='Email' size=40>
      </div>
    </div>
    <div class="formRow">
      <div class="formLeft">Address1<span class="red">*</span></div>
      <div class="formRight">
        <input type=text name='Address1' size=40>
      </div>
    </div>
    <div class="formRow">
      <div class="formLeft">Address2<span class="red">*</span></div>
      <div class="formRight">
        <input type=text name='Address2' size=40>
      </div>
    </div>
    <div class="formRow">
      <div class="formLeft">Address3</div>
      <div class="formRight">
        <input type=text name='Address3' size=40>
      </div>
    </div>
    <div class="formRow">
      <div class="formLeft">Address4</div>
      <div class="formRight">
        <input type=text name='Address4' size=40>
      </div>
    </div>
    <div class="formRow">
      <div class="formLeft">Zip / Post code<span class="red">*</span></div>
      <div class="formRight">
        <input type=text name='PostCode' size=40>
      </div>
    </div>
    <div class="formRow">
      <div class="formLeft">Arrival<span class="red">*</span></div>
      <div class="formRight">
        <input type=text name='Arrival' size=15 id="datepicker">
      </div>
    </div>
    <div class="formRow">
      <div class="formLeft">Departure<span class="red">*</span></div>
      <div class="formRight">
        <input type=text name='Departure' size=15 id="datepicker2">
      </div>
    </div>
    <div class="formRow">
      <div class="formLeft">GroupNumber<span class="red">*</span></div>
      <div class="formRight">
        <select name='GroupNumber'>
          <option value='01'>01</option>
          <option value='02'>02</option>
          <option value='03'>03</option>
          <option value='04'>04</option>
          <option value='05'>05</option>
          <option value='06'>06</option>
        </select>
      </div>
    </div>
    <div class="formRow">
      <div class="formLeft">Reason</div>
      <div class="formRight">
        <select name='Reason'>
          <option value='Vacation'>Vacation</option>
          <option value='Business'>Business</option>
          <option value='Education'>Education</option>
          <option value='Other'>Other</option>
        </select>
      </div>
    </div>
    <div class="formRow">
      <div class="formLeft">Transfer</div>
      <div class="formRight">
        <input type=checkbox name='Transfer'>
      </div>
    </div>
    <div class="formRow">
      <div class="formLeft">CarRental</div>
      <div class="formRight">
        <input type=checkbox name='CarRental'>
      </div>
    </div>
    <div class="formRow">
      <div class="formLeft">Taxi</div>
      <div class="formRight">
        <input type=checkbox name='Taxi'>
      </div>
    </div>
    <div class="formRow">
      <div class="formLeft">Additional</div>
      <div class="formRightBox">
        <textarea name='Additional' rows=7 cols=31></textarea>
      </div>
    </div>
    <div class="formRow">
                 <div class="formLeft"> </div>
                    <div class="formRightCaptcha">
                         <?php
                              require_once('recaptchalib.php');
                              $publickey = "6LfgGOASAAAAAOQ-oVZNlo8HmxR4GadyY4h5c0hY"; // you got this from the signup page
                              echo recaptcha_get_html($publickey);
                            ?>
                    </div>
    </div>
    <div class="formRow">
      <div class="formLeft"> </div>
      <div class="formRight">
        <input type=submit value='Submit Form'>
        &nbsp;
        <input type=reset value='Reset Form'>
      </div>
    </div>
  </div>

Verify.php

    <?php
  require_once('recaptchalib.php');
  $privatekey = "***PRIVATEKEYREMOVED***";
  $resp = recaptcha_check_answer ($privatekey,
                                $_SERVER["REMOTE_ADDR"],
                                $_POST["recaptcha_challenge_field"],
                                $_POST["recaptcha_response_field"]);

  if (!$resp->is_valid) {
    // What happens when the CAPTCHA was entered incorrectly
    die ("The reCAPTCHA wasn't entered correctly. Go back and try it again." .
         "(reCAPTCHA said: " . $resp->error . ")");
  } else {
    // Your code here to handle a successful verification
    include("global.inc.php");
$errors=0;
$error="The following errors occured while processing your form input.<ul>";
pt_register('POST','Name');
pt_register('POST','Telephone');
pt_register('POST','Email');
pt_register('POST','Address1');
pt_register('POST','Address2');
pt_register('POST','Address3');
pt_register('POST','Address4');
pt_register('POST','PostCode');
pt_register('POST','Arrival');
pt_register('POST','Departure');
pt_register('POST','GroupNumber');
pt_register('POST','Reason');
pt_register('POST','Transfer');
pt_register('POST','CarRental');
pt_register('POST','Taxi');
pt_register('POST','Additional');
$Additional=preg_replace("/(\015\012)|(\015)|(\012)/","&nbsp;<br />", $Additional);if($Name=="" || $Telephone=="" || $Email=="" || $Address1=="" || $Address2=="" || $PostCode=="" || $Arrival=="" || $Departure=="" || $GroupNumber=="" ){
$errors=1;
$error.="<li>You did not enter one or more of the required fields. Please go back and try again.";
}
if(!eregi("^[a-z0-9]+([_\\.-][a-z0-9]+)*" ."@"."([a-z0-9]+([\.-][a-z0-9]+)*)+"."\\.[a-z]{2,}"."$",$Email)){
$error.="<li>Invalid email address entered";
$errors=1;
}
if($errors==1) echo $error;
else{
$where_form_is="http".($HTTP_SERVER_VARS["HTTPS"]=="on"?"s":"")."://".$SERVER_NAME.strrev(strstr(strrev($PHP_SELF),"/"));
$message="A booking enquiry has been made by ".$Name."

Telephone: ".$Telephone."

Email: ".$Email."

Address1: ".$Address1."

Address2: ".$Address2."

Address3: ".$Address3."

Address4: ".$Address4."

PostCode: ".$PostCode."

Arrival: ".$Arrival."

Departure: ".$Departure."

GroupNumber: ".$GroupNumber."

Reason: ".$Reason."

Transfer: ".$Transfer."

CarRental: ".$CarRental."

Taxi: ".$Taxi."

Additional: ".$Additional."
";
$message = stripslashes($message);

$subject = 'Louis Villa booking enquiry';
$headers = 'From:' .$Name. ' made a booking enquiry' . "\r\n" . // <- change your email here
        'Reply-To:' . $Email . "\r\n";

mail("info@louisvilla.com",$subject,$message,$headers);

header("Location:http://louisvilla.com/thankyou.html");
exit();
}
  }
?>

Global.inc.php

<?php

function pt_register()
{
  $num_args = func_num_args();
   $vars = array();

   if ($num_args >= 2) {
       $method = strtoupper(func_get_arg(0));

       if (($method != 'SESSION') && ($method != 'GET') && ($method != 'POST') && ($method != 'SERVER') && ($method != 'COOKIE') && ($method != 'ENV')) {
           die('The first argument of pt_register must be one of the following: GET, POST, SESSION, SERVER, COOKIE, or ENV');
     }

       $varname = "HTTP_{$method}_VARS";
      global ${$varname};

       for ($i = 1; $i < $num_args; $i++) {
           $parameter = func_get_arg($i);

           if (isset(${$varname}[$parameter])) {
               global $$parameter;
               $$parameter = ${$varname}[$parameter];
          }

       }

   } else {
       die('You must specify at least two arguments');
   }

}

?>

recaptchalib.php

<?php

define("RECAPTCHA_API_SERVER", "http://www.google.com/recaptcha/api");
define("RECAPTCHA_API_SECURE_SERVER", "https://www.google.com/recaptcha/api");
define("RECAPTCHA_VERIFY_SERVER", "www.google.com");

/**
 * Encodes the given data into a query string format
 * @param $data - array of string elements to be encoded
 * @return string - encoded request
 */
function _recaptcha_qsencode ($data) {
        $req = "";
        foreach ( $data as $key => $value )
                $req .= $key . '=' . urlencode( stripslashes($value) ) . '&';

        // Cut the last '&'
        $req=substr($req,0,strlen($req)-1);
        return $req;
}



/**
 * Submits an HTTP POST to a reCAPTCHA server
 * @param string $host
 * @param string $path
 * @param array $data
 * @param int port
 * @return array response
 */
function _recaptcha_http_post($host, $path, $data, $port = 80) {

        $req = _recaptcha_qsencode ($data);

        $http_request  = "POST $path HTTP/1.0\r\n";
        $http_request .= "Host: $host\r\n";
        $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
        $http_request .= "Content-Length: " . strlen($req) . "\r\n";
        $http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
        $http_request .= "\r\n";
        $http_request .= $req;

        $response = '';
        if( false == ( $fs = @fsockopen($host, $port, $errno, $errstr, 10) ) ) {
                die ('Could not open socket');
        }

        fwrite($fs, $http_request);

        while ( !feof($fs) )
                $response .= fgets($fs, 1160); // One TCP-IP packet
        fclose($fs);
        $response = explode("\r\n\r\n", $response, 2);

        return $response;
}



/**
 * Gets the challenge HTML (javascript and non-javascript version).
 * This is called from the browser, and the resulting reCAPTCHA HTML widget
 * is embedded within the HTML form it was called from.
 * @param string $pubkey A public key for reCAPTCHA
 * @param string $error The error given by reCAPTCHA (optional, default is null)
 * @param boolean $use_ssl Should the request be made over ssl? (optional, default is false)

 * @return string - The HTML to be embedded in the user's form.
 */
function recaptcha_get_html ($pubkey, $error = null, $use_ssl = false)
{
    if ($pubkey == null || $pubkey == '') {
        die ("To use reCAPTCHA you must get an API key from <a href='https://www.google.com/recaptcha/admin/create'>https://www.google.com/recaptcha/admin/create</a>");
    }

    if ($use_ssl) {
                $server = RECAPTCHA_API_SECURE_SERVER;
        } else {
                $server = RECAPTCHA_API_SERVER;
        }

        $errorpart = "";
        if ($error) {
           $errorpart = "&amp;error=" . $error;
        }
        return '<script type="text/javascript" src="'. $server . '/challenge?k=' . $pubkey . $errorpart . '"></script>

    <noscript>
        <iframe src="'. $server . '/noscript?k=' . $pubkey . $errorpart . '" height="300" width="500" frameborder="0"></iframe><br/>
        <textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
        <input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>
    </noscript>';
}




/**
 * A ReCaptchaResponse is returned from recaptcha_check_answer()
 */
class ReCaptchaResponse {
        var $is_valid;
        var $error;
}


/**
  * Calls an HTTP POST function to verify if the user's guess was correct
  * @param string $privkey
  * @param string $remoteip
  * @param string $challenge
  * @param string $response
  * @param array $extra_params an array of extra variables to post to the server
  * @return ReCaptchaResponse
  */
function recaptcha_check_answer ($privkey, $remoteip, $challenge, $response, $extra_params = array())
{
    if ($privkey == null || $privkey == '') {
        die ("To use reCAPTCHA you must get an API key from <a href='https://www.google.com/recaptcha/admin/create'>https://www.google.com/recaptcha/admin/create</a>");
    }

    if ($remoteip == null || $remoteip == '') {
        die ("For security reasons, you must pass the remote ip to reCAPTCHA");
    }



        //discard spam submissions
        if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0) {
                $recaptcha_response = new ReCaptchaResponse();
                $recaptcha_response->is_valid = false;
                $recaptcha_response->error = 'incorrect-captcha-sol';
                return $recaptcha_response;
        }

        $response = _recaptcha_http_post (RECAPTCHA_VERIFY_SERVER, "/recaptcha/api/verify",
                                          array (
                                                 'privatekey' => $privkey,
                                                 'remoteip' => $remoteip,
                                                 'challenge' => $challenge,
                                                 'response' => $response
                                                 ) + $extra_params
                                          );

        $answers = explode ("\n", $response [1]);
        $recaptcha_response = new ReCaptchaResponse();

        if (trim ($answers [0]) == 'true') {
                $recaptcha_response->is_valid = true;
        }
        else {
                $recaptcha_response->is_valid = false;
                $recaptcha_response->error = $answers [1];
        }
        return $recaptcha_response;

}

/**
 * gets a URL where the user can sign up for reCAPTCHA. If your application
 * has a configuration page where you enter a key, you should provide a link
 * using this function.
 * @param string $domain The domain where the page is hosted
 * @param string $appname The name of your application
 */
function recaptcha_get_signup_url ($domain = null, $appname = null) {
    return "https://www.google.com/recaptcha/admin/create?" .  _recaptcha_qsencode (array ('domains' => $domain, 'app' => $appname));
}

function _recaptcha_aes_pad($val) {
    $block_size = 16;
    $numpad = $block_size - (strlen ($val) % $block_size);
    return str_pad($val, strlen ($val) + $numpad, chr($numpad));
}

/* Mailhide related code */

function _recaptcha_aes_encrypt($val,$ky) {
    if (! function_exists ("mcrypt_encrypt")) {
        die ("To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed.");
    }
    $mode=MCRYPT_MODE_CBC;   
    $enc=MCRYPT_RIJNDAEL_128;
    $val=_recaptcha_aes_pad($val);
    return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
}


function _recaptcha_mailhide_urlbase64 ($x) {
    return strtr(base64_encode ($x), '+/', '-_');
}

/* gets the reCAPTCHA Mailhide url for a given email, public key and private key */
function recaptcha_mailhide_url($pubkey, $privkey, $email) {
    if ($pubkey == '' || $pubkey == null || $privkey == "" || $privkey == null) {
        die ("To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " .
             "you can do so at <a href='http://www.google.com/recaptcha/mailhide/apikey'>http://www.google.com/recaptcha/mailhide/apikey</a>");
    }


    $ky = pack('H*', $privkey);
    $cryptmail = _recaptcha_aes_encrypt ($email, $ky);

    return "http://www.google.com/recaptcha/mailhide/d?k=" . $pubkey . "&c=" . _recaptcha_mailhide_urlbase64 ($cryptmail);
}

/**
 * gets the parts of the email to expose to the user.
 * eg, given johndoe@example,com return ["john", "example.com"].
 * the email is then displayed as john...@example.com
 */
function _recaptcha_mailhide_email_parts ($email) {
    $arr = preg_split("/@/", $email );

    if (strlen ($arr[0]) <= 4) {
        $arr[0] = substr ($arr[0], 0, 1);
    } else if (strlen ($arr[0]) <= 6) {
        $arr[0] = substr ($arr[0], 0, 3);
    } else {
        $arr[0] = substr ($arr[0], 0, 4);
    }
    return $arr;
}

/**
 * Gets html to display an email address given a public an private key.
 * to get a key, go to:
 *
 * http://www.google.com/recaptcha/mailhide/apikey
 */
function recaptcha_mailhide_html($pubkey, $privkey, $email) {
    $emailparts = _recaptcha_mailhide_email_parts ($email);
    $url = recaptcha_mailhide_url ($pubkey, $privkey, $email);

    return htmlentities($emailparts[0]) . "<a href='" . htmlentities ($url) .
        "' onclick=\"window.open('" . htmlentities ($url) . "', '', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=300'); return false;\" title=\"Reveal this e-mail address\">...</a>@" . htmlentities ($emailparts [1]);

}


?>

任何帮助将不胜感激。我一直与我的托管公司保持联系,寻求支持,因为表格是用他们推荐的软件构建的,他们提供的唯一帮助就是去网上论坛寻求帮助。

我创建了许多联系表单&#39;以前从来没有遇到过这个问题。

提前感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

问题在于您发布的代码很容易被邮件标头攻击。

此代码的目的是始终向您发送电子邮件,并且仅向您发送电子邮件,但您的电子邮件标题可能会受到操纵,以致电子邮件会被非预期的内容重写并发送给任意收件人。

换句话说,对于知道如何攻击它的人来说,你有一个开放的电子邮件系统,可以完全匿名地向任何人发送任何内容。

问题的核心在于:

$headers = 'From:' .$Name. ' made a booking enquiry' . "\r\n" .
        'Reply-To:' . $Email . "\r\n";

$Name$Email都可以通过注入其他\r\n序列和其他标头来攻击系统。

您需要清理这些字段以及您可能用来阻止此类攻击的任何其他标头。

这种事情暴露了PHP内置mail()函数的弱点。使用此功能编写易受攻击的邮件程序非常容易。

我的建议是使用更好的邮件程序类,例如phpMailer而不是PHP的内置mail()函数。

phpMailer为您清理输入并使攻击者难以破解您的系统做了所有艰苦的工作。是的,您可以修改您的代码来自己处理所有这些,但这是很多工作,您永远不会完全确定您已经涵盖了所有内容。所以使用像phpMailer这样的类,因为他们已经为你完成了所有工作。

基本上,一旦你安装了phpMailer,你就会替换这段代码:

$subject = 'Louis Villa booking enquiry';
$headers = 'From:' .$Name. ' made a booking enquiry' . "\r\n" .
        'Reply-To:' . $Email . "\r\n";
mail("info@louisvilla.com",$subject,$message,$headers);

......用这个:

require 'class.phpmailer.php';
$mail = new PHPMailer;
$mail->From = $Email;
$mail->FromName = $Name;
$mail->AddAddress('info@louisvilla.com');
$mail->Subject = $subject;
$mail->Body    = $message;
if(!$mail->Send()) {
   echo 'Message could not be sent.';
   echo 'Mailer Error: ' . $mail->ErrorInfo;
   exit;
}

更整洁的代码,更安全。全面胜利。

希望有所帮助。

答案 1 :(得分:1)

如果托管公司因“网络钓鱼攻击”(声称您容易受到攻击)而删除内容,您可以放弃或起诉他们是不负责任的主机。网络钓鱼实际上是任何网站都容易受到攻击的东西;它是对人类的攻击,而不是对网站的攻击。<​​/ p>

social engineering类似,您可以做的唯一事情就是教育用户。 (注意:您也可以使用带有正确DKIM / SPF记录的签名电子邮件,Gmail也不会轻易将您标记为垃圾邮件,但这是您可以访问的限制)

此外(虽然这部分理想情况下应该进行代码审查)

  • 您正在混合$_SERVER(这是正确的)和$HTTP_SERVER_VARS(已deprecated for many years并在错误日志中抛出E_DEPRECATED
  • 您似乎已对HTTP_*_VARS进行了全局调整;这不是必需的,因为$_POST/GET/SESSION/...都是超级全球。
  • 您的电子邮件正则表达式无效; regex can't validate email(电子邮件语法不规则,因此正则表达式不会100%有效)。
  • 您无法抵御CSRF。请参阅Jeff's blog post

我能想到的唯一一件事就是让你的主机合法地删除内容,如果他们认为你是一个网络钓鱼,但是考虑到他们在此之后在论坛上寻求帮助的回应,我会说他们只是非常不专业。

编辑:在我看到自己看不到@Spudley看到的内容之后,似乎有人一直在使用您的脚本向人们发送网络钓鱼攻击。您的托管公司知道您的脚本正在发送它们,但只是删除它们并且没有告诉您它正在被利用(并且可能没有假设诚信)