SMTP入門 〜メールアドレス偽装〜 0. はじめに 突然ですが、例えばあなたが自分の家の住所を偽装して(偽って)誰かに手紙を 送りたいと考えたとする。その場合あなたはどうするだろうか?これは簡単な ことだろう。相手の名前と宛先の住所だけを書いて手紙をポストにいれればい いだけの話だ。(試したことは無いが)そうすれば差出人不明の手紙が相手に届 くことになる。見事自分の住所を偽装したことになるだろう。(まぁ住所が未 記入なわけだから正確には偽装とは呼ばないかもしれないが...)さて、では話 を置き換えよう。同じように電子メールでもこれとおなじことをやれば差出人 (送信元)が偽装できるのではないか。「いや、でも待ってくれ。Outlookに送 信元を書く欄なんて無いぜ!」 確かに。ならば実際Outlookが(まぁOutlookに 限らずメールソフトなら何でもだが)メールを送信する際にどういった手順を 踏んでいるのかを調べてみようじゃないか。 1. SMTPとは SMTP とは Simple Mail Transfer Protocol の略です。電子メールの送信に用 いられるプロトコルで(電子メールの受信にはまた別のプロトコルが用いられ ます)一般的にはポート番号 25 番を使用します。今回は入門なので SMTP に ついてあまり深い説明はしませんが詳しく知りたい方は RFC821 などを参照し てください。 2. メール送信の過程 まずは最初にtelnetを使用してメール送信の動作を追っていこうと思います。 ここではサンプルとしてYahooメールのメールサーバを使いますがどのメール サーバでもOKです。メールアドレスなんて持ってねーよ。という方はYahooメー ルを取得してください。もちろん無料です。 まずメールサーバを調べます。 [kenji@localhost smtp]$ host -t mx yahoo.co.jp yahoo.co.jp mail is handled (pri=10) by mta11.mail.yahoo.co.jp yahoo.co.jp mail is handled (pri=10) by mta12.mail.yahoo.co.jp yahoo.co.jp mail is handled (pri=10) by mta13.mail.yahoo.co.jp yahoo.co.jp mail is handled (pri=10) by mta14.mail.yahoo.co.jp yahoo.co.jp mail is handled (pri=10) by mta15.mail.yahoo.co.jp yahoo.co.jp mail is handled (pri=10) by mta16.mail.yahoo.co.jp yahoo.co.jp mail is handled (pri=10) by mta17.mail.yahoo.co.jp yahoo.co.jp mail is handled (pri=10) by mta18.mail.yahoo.co.jp yahoo.co.jp mail is handled (pri=100) by mta10.mail.yahoo.co.jp [kenji@localhost smtp]$ わざわざhostコマンドで調べていますが、Outlook Expressを使っているなら ば ツール -> アカウント -> プロパティ -> サーバ -> の「送信メール (SMTP)」という項目に書かれてあるサーバ名のことです。ほかのメールソフト はちょっと分からないのでSMTPと書かれてある項目を適当に探してください。 もし見つからない場合は Yahooメール を使ってください。 沢山出て来ましたが特にどれでもいいので mta15.mail.yaoo.co.jp にしましょ う。では早速 telnet で接続して次のように入力してください。SMTPなのでポー ト番号は 25 です。Windowsの場合はコマンドプロンプトに次のように打って ください。 (コマンドプロンプト) C:\xxxx>telnet mta15.mail.yahoo.co.jp 25 Connected to mta15.mail.yahoo.co.jp. 220 YSmtp mta15.mail.yahoo.co.jp ESMTP service ready [kenji@localhost smtp]$ telnet mta15.mail.yahoo.co.jp 25 Trying 211.14.15.26... Connected to mta15.mail.yahoo.co.jp. Escape character is '^]'. 220 YSmtp mta15.mail.yahoo.co.jp ESMTP service ready まずここまで表示されます。ここではYahooメールを使用していますが、どの サーバでも同じようなレスポンスが返って来ると思います。最初にHELOコマン ドを送りましょう。引数は送信元のホスト名を入れなければならないようです が、特になんでも構わないと思います。 HELO yahoo.co.jp 250 mta15.mail.yahoo.co.jp すると 250 ....という文字列が返って来ました。では次に送信元のメールア ドレスを渡します。送信元は気にいらないなら適当に変更しても構いません。 宛先さえちゃんとしたアドレスにしておけば送信できるので。 MAIL FROM: 250 sender ok またまた 250 ....という文字列が返って来ました。さらに宛先(送信先)のメー ルアドレスを渡します。これはちゃんとしたメールアドレスを渡さなければい けません。 RCPT TO: 250 recipient ok レスポンスはさらに 250 ....が返って来ました。では送信元と宛先をサーバ に渡したので次はデータを渡します。 DATA 354 go ahead From: from@yahoo.co.jp To : to@yahoo.co.jp Subject: this is test (一行あける) THIS IS TEST. . ('.'だけ!ここでDATA部の終了を判断します) 250 ok dirdel 今度は 354 が返って来ました。それに続けてメールヘッダを入力します。そ して一行あけてメール本文を入力したあと'.'(ドット)だけの行を作って終了 です。そのあともやはり 250 ....という文字列は返って来ました。最後に QUITコマンドを送信して終了しましょう。 QUIT 221 mta15.mail.yahoo.co.jp Connection closed by foreign host. さて実際メールが送られているかどうかを見てみましょう。 ---------------------------------- From: from@yahoo.co.jp To : to@yahoo.co.jp Subject: this is test THIS IS TEST. ---------------------------------- こういうメールが送られていたら成功です。 ではもう一度一連の動作をみてみましょう。 C:\xxxx>telnet mta15.mail.yahoo.co.jp 25 Connected to mta15.mail.yahoo.co.jp. [kenji@localhost smtp]$ telnet mta15.mail.yahoo.co.jp 25 Trying 211.14.15.26... Connected to mta15.mail.yahoo.co.jp. Escape character is '^]'. 以下同じ 220 YSmtp mta15.mail.yahoo.co.jp ESMTP service ready HELO yahoo.co.jp 250 mta15.mail.yahoo.co.jp MAIL FROM: 250 sender ok RCPT TO: 250 recipient ok DATA 354 go ahead From: from@yahoo.co.jp To : to@yahoo.co.jp Subject: this is test THIS IS TEST. . 250 ok dirdel QUIT 221 mta15.mail.yahoo.co.jp Connection closed by foreign host. まず最初に気になるのは常に現れる 250.... というレスポンスです。これは 「リクエストされたコマンドが正常に終了しました」ということを意味してい ます。しかし QUIT に対する応答は 221 となっています。これは「コネクショ ンの終了」を意味し基本的に QUIT に対する応答にのみ使用されます。他に 220 と 354 というものがあります。354 は「メールデータを入力してくださ い」ということであり続く行全てがメッセージテキストである、と考えられま す(中間応答)。220 は「サービス用意」返答となっていますがつまりは「接続 が確立されました」くらいの意味で取っても構わないでしょう。 この例では当然(メールが送信できたのだから)「成功」の応答しか返って来ま せんが、もちろん「失敗」や「エラー」などの応答コードもあります。メール 送信の実験ではタイピングの失敗は許されませんので、もしかしたら貴方が上 記のテストを行うまでに数回タイプミスをしてエラーコードを目にしたかもし れません。主に 400, 500 番台の数がエラーもしくは失敗コードであるようで す。詳細は RFC にて。 さてここではコマンドは HELO, MAIL, RCPT, DATA, QUIT, しか使用しません でしたが、他にも NOOP, RSET, HELP, VRFY, EXPN, TURN, SOML, SAML, など 沢山あります。説明はしませんが1つずつ試してみるのも面白いでしょう。コ マンドによっては実装されて無いサーバもあるだろうしすべてのコマンドが実 装されてるサーバもあるかもしれません。ちなみに mta15.mail.yahoo.co.jp は HELP までは実装されてました。 ではこれまでやってきたことをまとめましょう。 接続して最初に行うのは HELO の発行です。引数は自身のホスト名(ホントは なんでもいいのですが一応、建て前として)。そして次に MAIL FROM:<...@.....> で送信元のアドレスを伝えて、 RCPT TO:<...@....> で宛先を伝えます。最後に DATA でメールヘッダの情報とメール本文を送信し QUITで終了となります。 3. メールアドレスの偽装を考える では実際にメールアドレスを偽装してみます。「えっ?どうやって?」という 方はもう一度メール送信の実験でやった一連の作業を思いだしてみて下さい。 ポイントは送信元アドレスと宛先アドレスを書いた場所がそれぞれ2つありま したよね?ってことです。とりあえず送信元アドレスは2つとも嘘のアドレス に変更しても問題無いでしょう。何故ならメールを送信するという動作におい ては必要無いからです。(もちろんメールを受け取った人にとっては重要な情 報ですが) そして2つある宛先アドレスのうちサーバはどちらを見て送信すべ き宛先のアドレスを判断しているでしょうか?簡単なことです。おそらく、 RCPT TO に書いたアドレスでしょう。つまり DATA のメールヘッダに書いた宛 先アドレスは変更しても問題ないのではないか?という結論にいきつきます。 では実際やってみましょう。もう一度 telnet mta15.mail.yahoo.co.jp 25 と 打ちこんでください。と言いたい所ですが正直もう一度 telnet ......co.jp 25 から始めるのは面倒です。何故ならもうメール送信の手順は理解している のですから。しかもいちいちタイプミスを気しながら試してみるのも大変です。 ということでメール送信プログラムを書きます。 < ここからは Perl がわかる方を対象としています > 4. メール送信プログラムの作成 ソースは以下にUPしました。 http://ruffnex.oc.to/kenji/src/SMTP.txt (SMTP.pl) まぁ詳しい話は置いといて、とりあえずDLして拡張子を.plにして宛先だけ変 更して実行してみましょう。 Perlで書いているのでLinuxでもWindowsでも同じプログラムで動くはず(とい うかこれがPerlで書いた理由)ですのでとりあえず $to だけ変更して実行して みてください。(もちろんyahooメールで実験してない方は$serverも変更して ください)見事success!!と表示されたらメールソフトもしくはブラウザでメー ルを確認してみてください。ちゃんとメールアドレスが偽装されてたら成功で す。ちなみにYahooメールはブラウザからでもちゃんとメールヘッダの詳細を みることができます(右上にリンクがあります) 一応プログラムの簡単な説明をします。 まず最初にメールアドレスに関する設定項目が続きます。それは省略。 そして $head = 'From: '. $h_from . '<'. $h_from .'>' . "\r\n"; $head .= 'To: '. $h_to . "\r\n"; $head .= 'Subject: ' . $subject . "\r\n"; $head .= 'X-Mailer: sample mailer' . "\r\n"; $head .= 'MIME-Version: 1.0' . "\r\n"; $head .= 'Content-Type: text/plain; charset=iso-2022-jp' . "\r\n"; $head .= 'Message-Id: <00000000000000.00000000000@local.com.>' . "\r\n"; $head .= "\r\n"; ここでヘッダ情報の偽装を行っています。アドレスだけ偽装してもヘッダを見 ればさまざまな情報がばれてしまいますので、ここである程度の偽装を試みて ます。 $port = getservbyname('smtp', 'tcp'); $struct = sockaddr_in($port, inet_aton($server)); socket(SOCK, PF_INET, SOCK_STREAM, 0) || die("socket $!"); connect(SOCK, $struct) || die("connect $!"); select(SOCK); $| = 1; select(STDOUT); 接続の処理です。 unless( =~ /^220/){ close(SOCK); die("Don't 220 $!"); } もしも220...という文字列を受け取らなかったらエラーということで終了して います。 talk("HELO $server\r\n", "250"); talk("MAIL FROM:<$from>\r\n", "250"); talk("RCPT TO:<$to>\r\n", "250"); talk("DATA\r\n", "354"); talk( $data, "250"); talk("QUIT\r\n", "221"); ここはtalkをよびだして、サーバとの会話をしています。 sub talk{ print SOCK $_[0]; my $respons = ; $respons =~ s/\x0D\x0A|\x0D|\x0A/\n/g; unless($respons =~ /^$_[1]/){ print SOCK "RSET\r\n"; close(SOCK); die("Error: $_[0], $_[1]"); } } まず第1引数を送信してレスポンスを受け取りそのレスポンスの改行を'\n'に 変更します。そしてその文字列に対して第2引数がマッチしなかったらエラー、 マッチしたらそのまま次のtalkへ進みます。 このプログラムをいろいろ書きかえてどれくらいヘッダが偽装できるのか実験 してみるのも面白いです。 5. 匿名メール送信フォームを作る (sendmailを利用する) CGI/Perlを使って匿名メール送信フォームを作りたい。しかしたいていの無料 HPスペースではSocketが使用できないようになっています。(まぁ使用できた ら大変ですが...)なので匿名メール送信フォームどころか他のサーバに接続す ること自体できないのですが、実はこれは sendmail を使うことによって可能 となります。 SMTPをある程度理解していれば sendmail も簡単に理解できます。結局最終的 には同じことをやっているので。sendmail は無料HPスペースなら XREA が使 用可能ですが XREA は実は sendmail では無く qmail だったりするので他の 無料HPスペースを探すか UNIX系OS で試したほうがいいかもしれません。XREA だとメールアドレスの偽装には問題ないのですがヘッダの関連の偽装がおかし くなるようです。使える.net で試したらうまくいきましたのでここもお勧め です。他にも sendmail が使用できる無料HPスペースはあるかと思うので適当 に探してください。なお、ここからはLinuxを使って進めていきます。 まずは sendmail を使ってメールを送信してみます。 [kenji@localhost sendmail]$ /usr/sbin/sendmail ******@yahoo.co.jp From: test@test.com To: ******@yahoo.co.jp Subject: Mailtest test ok?? . [kenji@localhost sendmail]$ sendmail の引数に渡したアドレスが送信すべきアドレスであり、From:行以下 の情報がメールヘッダの情報であることが予想できます。つまり送信元や宛先 なども偽装できることが分かる。しかし宛先を偽装してもあまり意味がないし、 引数に宛先を渡すのもめんどくさいので -t をつけてみる。 [kenji@localhost sendmail]$ /usr/sbin/sendmail -t From: test@test.com To: ******@yahoo.co.jp Subject: Mailtest test ok?? . [kenji@localhost sendmail]$ こんどは引数を渡さずともメールが送信できるようです。これは To: ....の アドレスを宛先として送信してくれるからです(もちろんメールヘッダにもこ のアドレスが使われる) -t をつけるとちょっと楽ができることが分かる。 ではこれを Perl から利用してみようと思います。 smail.pl ------------------------------------------------------------------------------ #!/usr/bin/perl $sendmail = '/usr/sbin/sendmail'; open(SENDMAIL,"| $sendmail -t"); print SENDMAIL << "EOF"; From: my\@host.com To: ******\@yahoo.co.jp Subject: MailTest Perl script test OK? . EOF close(SENDMAIL); ------------------------------------------------------------------------------ [kenji@localhost sendmail]$ chmod 755 smail.pl [kenji@localhost sendmail]$ ./smail.pl [kenji@localhost sendmail]$ こんな感じです。これを実行してみるとToのあて先にこのメールが届きます。 ではCGI用に書き換えます。 http://ruffnex.oc.to/kenji/src/smailA.txt (smailA.cgi) だらだらと長くなりましたが、基本的には HTML や フォームデータの加工処 理だけですから、特に難しいことはありません。(ソースが汚いとかは言わな いでください。ちょっと前に書いたものなのでと言い訳しつつごめんなさいで す)From と To のところが両方とも $add 変数を使っています。つまり受け取っ た側は自分から自分にメールが送信されてきたように見えるということです。 もちろんちょっと加工すれば送信元もフォームからもらえるように変更するこ とが可能ですね。では今度はメールヘッダを偽装するコードを追加します。さ てどこまで偽装が可能だろうか。 http://ruffnex.oc.to/kenji/src/smailB.txt (smailB.cgi) 無事偽装できたでしょうか?おそらくReceived:以外はちゃんと偽装できたか と思います。私が実験した限りでは 使える.net ではちゃんと偽装できたが XREA ではうまく偽装できませんでした。もちろん自分のサーバではOK!です。 ネット上に匿名メール送信フォームなんてものがあるがそれはこういう仕組み で実現されている場合多いようです。 ちなみにsmailB.cgiやsmailA.cgiには日本語変換処理などを施しておりません。 (まぁ見ればわかるが)つまり漢字コードによっては文字化けする可能性があり ます。もし日本語にも対応したいのならばいろいろと工夫してみてください。 6. 最後に いかがだったでしょうか?これを機会にちょっとネットワークやプログラムに ついて勉強してみようかな。という人が少しでもいてくれたら幸いです。SMTP も最近(もうかなり以前から問題になってはいるが)はスパムなどの影響でかな り不評なようですがここまで普及してしまったからにはすぐに変更というわけ にはいかないようです。最後になりましたが、ここまで付き合って読んでくだ さった方有り難うございました。次にいつかまた書く機会があればそのときは よろしくお願いします。 では、また会う日まで... End. written by kenji aiko 2003/11/15 Copyright (C) 2003 kenji aiko All Rights Reserved