親の持っているHPの一つは誰かに頼んで作ってもらったらしいんですが、そのHPにはメール送信フォームがあって、どうもそれには重大なセキュリティホールがあるらしいということが分かった。

その送信フォームが年明け早々からスパムメールの踏み台になってしまい、大量メールを送信してしまっているっぽいのがメールのログとサーバの毎日送られてくるログから分かったのである。

フォームメール(PHPでコーディング)がメール送信を受け付けてしまい、PHPから実行されるので、実行ユーザはたちの悪いことにapacheとなり、apacheがメールを送信してしまうので、いくらメールサーバの不正中継対策をやっていてもどうしようもない。

まず、送信フォーム自体がPHPで作られていて、フォームの各属性がこんな感じで指定されている。

<table width="100%" border="0" cellspacing="1" cellpadding="3">
<tr>
 <td><strong>Name: <br /> </strong>
   <input type="text" name="name" size="20" maxlength="22" /></td>
 <td rowspan="3"><strong>Message: <br /> </strong> <textarea name="message" rows="10" cols="42"></textarea></td> </tr> <tr> <td><strong>Email address: <br /> </strong>
   <input name="email" type="text" id="email" size="20" /></td> </tr>
<tr>
 <td>Telephone number <em>(optional)</em>: <br />
  <input type="text" name="tel" size="20" maxlength="18" /> <br /></td>
</tr>
<tr>
 <td>&nbsp;</td> <td><input type="submit" value="Send message to xxxx" /></td>
  <input type="hidden" name="_clandestinetoken" value="1" /></tr>
</table>

そのとき、このPHPは以下の別PHPファイルをincludeしていて、以下コードから分かるように、hiddenタグで指定されたキーが存在すれば、残りのコードを実行するという仕組み。
呼び出されるPHPコード。

<?
if (array_key_exists('_clandestinetoken', $_POST)) {
  $name = htmlspecialchars($_POST["name"]);
  $email = htmlspecialchars($_POST["email"]);
  $tel = htmlspecialchars($_POST["tel"]);
  $message = htmlspecialchars($_POST["message"]);
  if (empty($name) or empty($email) or empty($message)) {
    $message = '<div class="errormessage">Please enter name, email, and message.</div>';
  }
  else {

    // 準備
    $mlto = '<送信先アドレス1>';
    $mlsb = '[Query(Web form)]';
    $mlms = $message;
    $mlms.="\n-------------------------------------------------\n\n";
    $mlms.="HOST NAME:".getHostByAddr(getenv('REMOTE_ADDR'))."\n\n";
    $jcph = '.';
    $sender_name=$name;
    $sender_email=$email;
    $other_email="<送信先アドレス2>";
    $another_email="<送信先アドレス3>";
    $header = "From: \"".addslashes($sender_name)."\" <".$sender_email.">\r\n";
    $header .= "Cc: ".$other_email."\r\n";
    $header .= "Bcc: ".$another_email."\r\n";

    // メール送信
    $rcd =mail($mlto, $mlsb, $mlms, $header);

    if ($rcd) {
      $message = '<div class="donemessage">Message has been sent successfully !</div>';
    }
    else {
      $message = '<div class="donemessage">Message was not sent for some reason. Please Try again. </div>';
    }

  }
}
?>

重大な欠陥が容易にバレてしまうのが分かる。(←と言いながら理解するのに3日かかったが。。( ̄Д ̄;;)

はい、重大な欠陥!
1.フォームで指定されているhiddenタグでキーがモロばれ!
  →_clandestinetokenに何かしらキーを与えてPOSTしてやるだけで上のメール送信のほうのコードが実行されてしまう!
2.POSTで渡された値から余計なキャラクタなどを除去(サニタイジング→スクリプトの無効化)をしていない!
  →POSTで大量のメールアドレスをBCCとして渡してしまうことができる!
  →例えば、email属性として単純にBCC: アドレス1,アドレス2,アドレス3,・・・アドレス500みたいな感じ?これをPOSTで渡るよう環境変数にセットすればいいだけですから。

という理解。

鉄則として、PHPでコーディングする場合、hiddenタグは使わず、セッション変数を使うこと!
参考:hiddenフィールドの危険性
スクリプトの無効化をしないのは自殺行為!
参考:クロスサイトスクリプティング

もっともまずいのは呼び出されるほうのPHPコードのここの部分。

$header = "From: \"".addslashes($sender_name)."\" <".$sender_email.">\r\n";

$sender_emailはPOSTで渡されてきた内容を格納しているので、ここに悪意のあるものが埋め込んだBCCのアドレスを大量に埋め込むことができてしまうものと思われる。
参考:PHPでメール送信

ということで、このコードを書いた人(親曰く、商売でやっている人らしいが)は他のサイトでも同様なメール送信フォームを作っていたらあらゆるところでとんでもないことになっているでしょう。クロスサイトスクリプティングしてください、カモーン!と言っているようなもんですから。

そして、いまだにapacheに対して存在しなかったメールアドレスからのエラーメールが大量に戻ってきているのである。
そんなこんなで年明けからてんやわんや!( ̄Д ̄;;
もちろん、問題のメール送信フォームはすぐにリネームしたので被害は最小限に食い止めたが、かなりまずい状況であることには違いない。

他にもやらなきゃいけないこと山積みなのに、年明けから幸先悪いことだらけです。。



こちらもご一緒にどうぞ!