プロが教える店舗&オフィスのセキュリティ対策術

perlでメールフォームを作成しています。

メールの送信にはsendmail をopen関数で使用していたのですが
openはセキュリティ上の問題があることを知り、対策を調べているうちに
sysopenを使用することが有効だという情報にたどり着きました。

しかし、単純にopenをsysopenに書き換え、オープンモードも設定したのですが
sysopenに失敗してしまいます。
sendmail以外のテキストファイルのオープンには成功しているので
sysopenの使用方法が間違っている

sysopenを使用したsendmailの実行方法を教えていただけませんでしょうか?


[ソース]
use Fcntl;

$sendmail = '/usr/xxx/sendmail -t -io';


sysopen(MAIL,"$sendmail ", O_WRONLY ) or die "error!!"
my $mailstr = &MAILHEADER($to,$subject);
my $mailbody = &MAILBODY($fileId);
$mailstr .= $mailbody;
print MAIL $mailstr;
close MAIL;

&MAILHEADER()
  →To,From,Subjectの設定
&MAILBODY()
  →メール本文の設定

・sysopen部分は今まで以下の記述で、メールの送信をしていました。
  open(MAIL,"| $sendmail") or die "error!!"

 ・念のため、-fで「/usr/xxx/sendmail」の存在チェックをおこない、
  存在していることを確認しました。

 ・sysopenの使用方法が間違っているのかと思い、以下のサンプルを作成してみましたが
  問題なく動きました。
my $file = 'test1.txt';
sysopen(MSG,$file, O_WRONLY|O_CREAT|O_APPEND ) or die "sysopen error!!"
print MSG "sysopen OK";
close MSG;

サンプルが動いたことで、ますますsendmailをオープンできないことに
行き詰ってしまいました。
どうぞよろしくお願いいたします。

質問内容でわかららない部分があればご指摘ください。
可能な限りソースも載せます。

A 回答 (6件)

>少なくとも、$subject は定数なので、ユーザからの入力は反映されません。



$subject は例としてあげただけで $to や、その他に参照される変数なども同じですが大丈夫でしょうか。

実際にできるかどうかは別として他の思い当たるのは、例えばそのメール送信処理のcgiに

$ telnet そのサーバのホスト名 80
GET パス?SUBJECT=...

ように直接urlでアクセスできてしまうとか、
それを処理しているサーバのsendmailが外部から直接アクセス可能で自由に利用できる状態になってるとか。

今のところ思いつくのはこれくらいです。
    • good
    • 0
この回答へのお礼

休日にも関わらず、何度もありがとうございます。

>$ telnet そのサーバのホスト名 80
>GET パス?SUBJECT=...

>ように直接urlでアクセスできてしまうとか、
>それを処理しているサーバのsendmailが外部から
>直接アクセス可能で自由に利用できる状態になってるとか。

sshでの直接アクセスはIPアドレス指定で制限しているので基本的にはできないはずです。
サーバのsendmail等へのアクセスは、上記設定が有効である以上、できないと思います。

PCがハッキングされたりすれば別ですが、
そこまで考えているとキリがないので、
プログラム上のことしか今は考えないことにします。

サーバまわりは、そちらの管理者の管轄ですから
質問や「大丈夫ですよね?」って念を押すことはできても
実対応は口出しはできません。


結論として、kmeeさまよりご提案いただいた
Mail::Sendmail案を採用することになりました。

wormholeさまにはたくさんのご意見をいただき
ありがとうございました。
いろいろと私が考えていなかったことなどもありましたので
ベストアンサーとさせていただきます。
perlまわりで質問することもあると思いますので
今後ともよろしくお願いいたします。

ありがとうございました。

お礼日時:2014/06/11 00:11

>$sendmail にユーザの入力値が反映されるつくりではありませんが


>お恥ずかしながら、ログを解析すると当方のメールフォームを踏み台とし、
>spamメールの送信を行われた可能性が大きいことがわかりました。

それはopenの問題ではなくて

>my $mailstr = &MAILHEADER($to,$subject);
>my $mailbody = &MAILBODY($fileId);
>$mailstr .= $mailbody;
>print MAIL $mailstr;

の方じゃないかなと。
例えば $subject が "サブジェクト\nBCC: どっかのメールアドレス" だったりメール本文の先頭に "CC: どっかのメールアドレス" あったりしたら、$mailstr でのメールヘッダとして解釈される部分に含まれたりしませんか?
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。


少なくとも、$subject は定数なので、ユーザからの入力は反映されません。

>メール本文の先頭に "CC: どっかのメールアドレス" あったりしたら、
>$mailstr でのメールヘッダとして解釈される部分に含まれたりしませんか?

この可能性は考えていませんでした。
テストしてみたら、メールは送信されませんでした。
ありがとうございます。

参考までに、&MAILBODY のソースを載せます。
改修後のソースなので、引数はなくなっています。

## メールフォーム入力内容から本文作成
sub MAILBODY {

my $name = $FORM{'name'};
my $mail = $FORM{'mail1'};
my $comment = $FORM{'comment'};

$strbody = "[お名前]: $name\n";
$strbody .= "[メールアドレス]: $mail\n";
$strbody .= "[コメント]:\n $comment\n\n";

$strbody = encode_base64($strbody);

}
※$mail(メールアドレス)にカンマ、セミコロンでの区切りで複数のアドレスが入力されていないことはチェック済みです。


メール本文のログを見る限り、本文に入力文字はありませんでした。
そのため、
 open(MAIL,"| $sendmail") に対し、
パイプで何かのコマンドなりなんなりをつなげられたのかなと推測し、
open関数の使用に慎重になっている次第です。
(どうやってやったのかは、不明です。
悪用手口がわかれば、適切な対処もできるのですが、
残念ながら、そこまで至っておりません)

汚染チェック等の強化でopen関数&sendmailコマンドで実施してもよいか、Mail::sendmailに移行するか検討していますが、
その結果次第ではopen関数&sendmailコマンドということもあり得ます。

もともとも質問である”sysopenでのsendmailの方法”は
見当違い、勘違いでしたが、
perlの知識がある人・社外の人からのご意見は非常にありがたいです。
本当に、何度も回答させてしまい申し訳ありません。
ありがとうございます。

お礼日時:2014/06/08 00:31

>「脆弱性」とは、OSコマンドイジェクションのことを指しています。



注意されることはとてもよいことだとは思いますが単純に「openを使うのは危険」という認識のされかたしていませんか?

https://www.ipa.go.jp/security/awareness/vendor/ …
http://www.atmarkit.co.jp/icd/root/87/24084287.h …

に書かれているのは不適切な使い方をした場合の話ですけど。
質問に書かれているソースも $sendmail がユーザーからの入力を反映したりするなら問題はありますけど定数的に'/usr/xxx/sendmail -t -io'から変わることないということなら特に書き直す必要ないと私は思いますが。
    • good
    • 0
この回答へのお礼

何度もありがとうございます。

perl開発の経験の浅さ(知識の少なさ)故かもしれませんが
単純に「openを使うのは危険」という認識をしています。
というのも、
$sendmail にユーザの入力値が反映されるつくりではありませんが
お恥ずかしながら、ログを解析すると当方のメールフォームを踏み台とし、
spamメールの送信を行われた可能性が大きいことがわかりました。
(悪用した人が、何をどうやったかまではわかりません。
実際にspamメールの送信だったかもわかりませんが、
ログ等の情報から可能性として一番濃厚という程度です。)

実際に「事故が起きた」後であるため過剰反応気味かもしれませんが、対応に慎重になっております。

お礼日時:2014/06/07 03:40

http://perldoc.jp/func/sysopen
http://perldoc.jp/func/open

openにはちゃんと「ファイル名は出力がパイプされるコマンドとして 解釈され」等とコマンドとして実行する場合があることが書いてあります。
sysopenにはありません。sysopenはファイル(状のもの)が対象です。


その「脆弱性」って、具体的に何のことですか?
事前チェックや、MODEを別引数にしたopenを使う等で避けられませんか?

あるいは、 Sendmail.pm等を使うことはできませんか?
http://search.cpan.org/~mivkovic/Mail-Sendmail-0 …

この回答への補足

ご回答ありがとうございます。

「脆弱性」とは、OSコマンドイジェクションのことを指しています。

恥ずかしながら、この言葉も知らず、
"perl OSコマンドイジェクション 対策"等で検索し、
https://www.ipa.go.jp/security/awareness/vendor/ …

http://www.atmarkit.co.jp/icd/root/87/24084287.h …
等で、openではなく、sysopenを使用するほうが安全だと知りました。

sendmailがファイルというより、コマンドである認識ではいますが、openではなくsysopenを使用するほうが安全だというサイトを多くみて、質問に書いたようなソースを作成しました。

汚染チェックでopen関数でも安全であれば
open関数でもいいと思います。
Sendmail.pmの使用もテストしてみます。

補足日時:2014/06/06 01:24
    • good
    • 0
この回答へのお礼

本日、ご提案いただいた
Mail::Sendmail案を採用することが決定し、
メール送信に至りました。

open関数を否定する気はありませんが、
こちらの記事を見つけ、Mail::Sendmail案の採用のほうが
好ましいとの上の判断でした。
(私も、自分の知識不足故に悪用されたであろう
open関数ですので、気持ちはMail::Sendmail案寄りでした)
http://firegoby.jp/archives/968

ありがとうございました。

お礼日時:2014/06/11 00:21

もう一点、


sysopenは">ファイル名","|プログラム名"のようなモード指定はサポートしていなかったような。

この回答への補足

確かに、open関数のように、"<"や"|"は見当りませんね。

http://itpro.nikkeibp.co.jp/article/Reference/20 …
を参照しました。

サンプルは、sysopen関数そのものの実行が間違えているのかと思い、シンプルなものを作成しました。

おっしゃる通り、sendmailのオプションである、"-t"等も含んだ
「/usr/xxxにある"sendmail -t -ioというファイル」をオープンしようとしているという実行文ですよね。

open関数または、kmee様が提示してくださったSendmail.pmでのメール送信を検討します。
(当然、汚染チェックを前提です)

補足日時:2014/06/06 01:38
    • good
    • 0

サンプルと同じに考えるなら「"/usr/xxx/sendmail -t -io"というファイル(/usr/xxxにある"sendmail -t -io"というファイル名のファイル)をオープンする」になっちゃっていますが。

この回答への補足

ご回答ありがとうございます。

コメントは追加でいただいたほうに
まとめさせていただきました。

補足日時:2014/06/06 01:44
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!